Merge branch 'main' of https://git.stella-ops.org/stella-ops.org/git.stella-ops.org
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
api-governance / spectral-lint (push) Has been cancelled
oas-ci / oas-validate (push) Has been cancelled
Policy Simulation / policy-simulate (push) Has been cancelled
sdk-generator-smoke / sdk-smoke (push) Has been cancelled
SDK Publish & Sign / sdk-publish (push) Has been cancelled
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
api-governance / spectral-lint (push) Has been cancelled
oas-ci / oas-validate (push) Has been cancelled
Policy Simulation / policy-simulate (push) Has been cancelled
sdk-generator-smoke / sdk-smoke (push) Has been cancelled
SDK Publish & Sign / sdk-publish (push) Has been cancelled
This commit is contained in:
@@ -1,16 +1,16 @@
|
||||
using StellaOps.Notify.Models;
|
||||
|
||||
namespace StellaOps.Notifier.WebService.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Request for creating or updating a channel.
|
||||
/// </summary>
|
||||
public sealed record ChannelUpsertRequest
|
||||
{
|
||||
public string? Name { get; init; }
|
||||
public NotifyChannelType? Type { get; init; }
|
||||
public string? Endpoint { get; init; }
|
||||
public string? Target { get; init; }
|
||||
public string? SecretRef { get; init; }
|
||||
public string? Description { get; init; }
|
||||
}
|
||||
using StellaOps.Notify.Models;
|
||||
|
||||
namespace StellaOps.Notifier.WebService.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Request for creating or updating a channel.
|
||||
/// </summary>
|
||||
public sealed record ChannelUpsertRequest
|
||||
{
|
||||
public string? Name { get; init; }
|
||||
public NotifyChannelType? Type { get; init; }
|
||||
public string? Endpoint { get; init; }
|
||||
public string? Target { get; init; }
|
||||
public string? SecretRef { get; init; }
|
||||
public string? Description { get; init; }
|
||||
}
|
||||
|
||||
@@ -1,137 +1,137 @@
|
||||
namespace StellaOps.Notifier.WebService.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Request to enqueue a dead-letter entry.
|
||||
/// </summary>
|
||||
public sealed record EnqueueDeadLetterRequest
|
||||
{
|
||||
public required string DeliveryId { get; init; }
|
||||
public required string EventId { get; init; }
|
||||
public required string ChannelId { get; init; }
|
||||
public required string ChannelType { get; init; }
|
||||
public required string FailureReason { get; init; }
|
||||
public string? FailureDetails { get; init; }
|
||||
public int AttemptCount { get; init; }
|
||||
public DateTimeOffset? LastAttemptAt { get; init; }
|
||||
public IReadOnlyDictionary<string, string>? Metadata { get; init; }
|
||||
public string? OriginalPayload { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response for dead-letter entry operations.
|
||||
/// </summary>
|
||||
public sealed record DeadLetterEntryResponse
|
||||
{
|
||||
public required string EntryId { get; init; }
|
||||
public required string TenantId { get; init; }
|
||||
public required string DeliveryId { get; init; }
|
||||
public required string EventId { get; init; }
|
||||
public required string ChannelId { get; init; }
|
||||
public required string ChannelType { get; init; }
|
||||
public required string FailureReason { get; init; }
|
||||
public string? FailureDetails { get; init; }
|
||||
public required int AttemptCount { get; init; }
|
||||
public required DateTimeOffset CreatedAt { get; init; }
|
||||
public DateTimeOffset? LastAttemptAt { get; init; }
|
||||
public required string Status { get; init; }
|
||||
public int RetryCount { get; init; }
|
||||
public DateTimeOffset? LastRetryAt { get; init; }
|
||||
public string? Resolution { get; init; }
|
||||
public string? ResolvedBy { get; init; }
|
||||
public DateTimeOffset? ResolvedAt { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to list dead-letter entries.
|
||||
/// </summary>
|
||||
public sealed record ListDeadLetterRequest
|
||||
{
|
||||
public string? Status { get; init; }
|
||||
public string? ChannelId { get; init; }
|
||||
public string? ChannelType { get; init; }
|
||||
public DateTimeOffset? Since { get; init; }
|
||||
public DateTimeOffset? Until { get; init; }
|
||||
public int Limit { get; init; } = 50;
|
||||
public int Offset { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response for listing dead-letter entries.
|
||||
/// </summary>
|
||||
public sealed record ListDeadLetterResponse
|
||||
{
|
||||
public required IReadOnlyList<DeadLetterEntryResponse> Entries { get; init; }
|
||||
public required int TotalCount { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to retry dead-letter entries.
|
||||
/// </summary>
|
||||
public sealed record RetryDeadLetterRequest
|
||||
{
|
||||
public required IReadOnlyList<string> EntryIds { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response for retry operations.
|
||||
/// </summary>
|
||||
public sealed record RetryDeadLetterResponse
|
||||
{
|
||||
public required IReadOnlyList<DeadLetterRetryResultItem> Results { get; init; }
|
||||
public required int SuccessCount { get; init; }
|
||||
public required int FailureCount { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Individual retry result.
|
||||
/// </summary>
|
||||
public sealed record DeadLetterRetryResultItem
|
||||
{
|
||||
public required string EntryId { get; init; }
|
||||
public required bool Success { get; init; }
|
||||
public string? Error { get; init; }
|
||||
public DateTimeOffset? RetriedAt { get; init; }
|
||||
public string? NewDeliveryId { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to resolve a dead-letter entry.
|
||||
/// </summary>
|
||||
public sealed record ResolveDeadLetterRequest
|
||||
{
|
||||
public required string Resolution { get; init; }
|
||||
public string? ResolvedBy { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response for dead-letter statistics.
|
||||
/// </summary>
|
||||
public sealed record DeadLetterStatsResponse
|
||||
{
|
||||
public required int TotalCount { get; init; }
|
||||
public required int PendingCount { get; init; }
|
||||
public required int RetryingCount { get; init; }
|
||||
public required int RetriedCount { get; init; }
|
||||
public required int ResolvedCount { get; init; }
|
||||
public required int ExhaustedCount { get; init; }
|
||||
public required IReadOnlyDictionary<string, int> ByChannel { get; init; }
|
||||
public required IReadOnlyDictionary<string, int> ByReason { get; init; }
|
||||
public DateTimeOffset? OldestEntryAt { get; init; }
|
||||
public DateTimeOffset? NewestEntryAt { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to purge expired entries.
|
||||
/// </summary>
|
||||
public sealed record PurgeDeadLetterRequest
|
||||
{
|
||||
public int MaxAgeDays { get; init; } = 30;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response for purge operation.
|
||||
/// </summary>
|
||||
public sealed record PurgeDeadLetterResponse
|
||||
{
|
||||
public required int PurgedCount { get; init; }
|
||||
}
|
||||
namespace StellaOps.Notifier.WebService.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Request to enqueue a dead-letter entry.
|
||||
/// </summary>
|
||||
public sealed record EnqueueDeadLetterRequest
|
||||
{
|
||||
public required string DeliveryId { get; init; }
|
||||
public required string EventId { get; init; }
|
||||
public required string ChannelId { get; init; }
|
||||
public required string ChannelType { get; init; }
|
||||
public required string FailureReason { get; init; }
|
||||
public string? FailureDetails { get; init; }
|
||||
public int AttemptCount { get; init; }
|
||||
public DateTimeOffset? LastAttemptAt { get; init; }
|
||||
public IReadOnlyDictionary<string, string>? Metadata { get; init; }
|
||||
public string? OriginalPayload { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response for dead-letter entry operations.
|
||||
/// </summary>
|
||||
public sealed record DeadLetterEntryResponse
|
||||
{
|
||||
public required string EntryId { get; init; }
|
||||
public required string TenantId { get; init; }
|
||||
public required string DeliveryId { get; init; }
|
||||
public required string EventId { get; init; }
|
||||
public required string ChannelId { get; init; }
|
||||
public required string ChannelType { get; init; }
|
||||
public required string FailureReason { get; init; }
|
||||
public string? FailureDetails { get; init; }
|
||||
public required int AttemptCount { get; init; }
|
||||
public required DateTimeOffset CreatedAt { get; init; }
|
||||
public DateTimeOffset? LastAttemptAt { get; init; }
|
||||
public required string Status { get; init; }
|
||||
public int RetryCount { get; init; }
|
||||
public DateTimeOffset? LastRetryAt { get; init; }
|
||||
public string? Resolution { get; init; }
|
||||
public string? ResolvedBy { get; init; }
|
||||
public DateTimeOffset? ResolvedAt { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to list dead-letter entries.
|
||||
/// </summary>
|
||||
public sealed record ListDeadLetterRequest
|
||||
{
|
||||
public string? Status { get; init; }
|
||||
public string? ChannelId { get; init; }
|
||||
public string? ChannelType { get; init; }
|
||||
public DateTimeOffset? Since { get; init; }
|
||||
public DateTimeOffset? Until { get; init; }
|
||||
public int Limit { get; init; } = 50;
|
||||
public int Offset { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response for listing dead-letter entries.
|
||||
/// </summary>
|
||||
public sealed record ListDeadLetterResponse
|
||||
{
|
||||
public required IReadOnlyList<DeadLetterEntryResponse> Entries { get; init; }
|
||||
public required int TotalCount { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to retry dead-letter entries.
|
||||
/// </summary>
|
||||
public sealed record RetryDeadLetterRequest
|
||||
{
|
||||
public required IReadOnlyList<string> EntryIds { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response for retry operations.
|
||||
/// </summary>
|
||||
public sealed record RetryDeadLetterResponse
|
||||
{
|
||||
public required IReadOnlyList<DeadLetterRetryResultItem> Results { get; init; }
|
||||
public required int SuccessCount { get; init; }
|
||||
public required int FailureCount { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Individual retry result.
|
||||
/// </summary>
|
||||
public sealed record DeadLetterRetryResultItem
|
||||
{
|
||||
public required string EntryId { get; init; }
|
||||
public required bool Success { get; init; }
|
||||
public string? Error { get; init; }
|
||||
public DateTimeOffset? RetriedAt { get; init; }
|
||||
public string? NewDeliveryId { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to resolve a dead-letter entry.
|
||||
/// </summary>
|
||||
public sealed record ResolveDeadLetterRequest
|
||||
{
|
||||
public required string Resolution { get; init; }
|
||||
public string? ResolvedBy { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response for dead-letter statistics.
|
||||
/// </summary>
|
||||
public sealed record DeadLetterStatsResponse
|
||||
{
|
||||
public required int TotalCount { get; init; }
|
||||
public required int PendingCount { get; init; }
|
||||
public required int RetryingCount { get; init; }
|
||||
public required int RetriedCount { get; init; }
|
||||
public required int ResolvedCount { get; init; }
|
||||
public required int ExhaustedCount { get; init; }
|
||||
public required IReadOnlyDictionary<string, int> ByChannel { get; init; }
|
||||
public required IReadOnlyDictionary<string, int> ByReason { get; init; }
|
||||
public DateTimeOffset? OldestEntryAt { get; init; }
|
||||
public DateTimeOffset? NewestEntryAt { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to purge expired entries.
|
||||
/// </summary>
|
||||
public sealed record PurgeDeadLetterRequest
|
||||
{
|
||||
public int MaxAgeDays { get; init; } = 30;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response for purge operation.
|
||||
/// </summary>
|
||||
public sealed record PurgeDeadLetterResponse
|
||||
{
|
||||
public required int PurgedCount { get; init; }
|
||||
}
|
||||
|
||||
@@ -1,149 +1,149 @@
|
||||
using System.Collections.Immutable;
|
||||
using System.Text.Json.Serialization;
|
||||
using StellaOps.Notify.Models;
|
||||
|
||||
namespace StellaOps.Notifier.WebService.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Request to create/update an escalation policy.
|
||||
/// </summary>
|
||||
public sealed record EscalationPolicyUpsertRequest
|
||||
{
|
||||
public string? Name { get; init; }
|
||||
public string? Description { get; init; }
|
||||
public ImmutableArray<EscalationLevelRequest> Levels { get; init; }
|
||||
public int? RepeatCount { get; init; }
|
||||
public bool? Enabled { get; init; }
|
||||
public IReadOnlyDictionary<string, string>? Metadata { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Escalation level configuration.
|
||||
/// </summary>
|
||||
public sealed record EscalationLevelRequest
|
||||
{
|
||||
public int Order { get; init; }
|
||||
public TimeSpan EscalateAfter { get; init; }
|
||||
public ImmutableArray<EscalationTargetRequest> Targets { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Escalation target configuration.
|
||||
/// </summary>
|
||||
public sealed record EscalationTargetRequest
|
||||
{
|
||||
public string? Type { get; init; }
|
||||
public string? TargetId { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to start an escalation for an incident.
|
||||
/// </summary>
|
||||
public sealed record StartEscalationRequest
|
||||
{
|
||||
public string? IncidentId { get; init; }
|
||||
public string? PolicyId { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to acknowledge an escalation.
|
||||
/// </summary>
|
||||
public sealed record AcknowledgeEscalationRequest
|
||||
{
|
||||
public string? StateIdOrIncidentId { get; init; }
|
||||
public string? AcknowledgedBy { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to resolve an escalation.
|
||||
/// </summary>
|
||||
public sealed record ResolveEscalationRequest
|
||||
{
|
||||
public string? StateIdOrIncidentId { get; init; }
|
||||
public string? ResolvedBy { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to create/update an on-call schedule.
|
||||
/// </summary>
|
||||
public sealed record OnCallScheduleUpsertRequest
|
||||
{
|
||||
public string? Name { get; init; }
|
||||
public string? Description { get; init; }
|
||||
public string? TimeZone { get; init; }
|
||||
public ImmutableArray<OnCallLayerRequest> Layers { get; init; }
|
||||
public bool? Enabled { get; init; }
|
||||
public IReadOnlyDictionary<string, string>? Metadata { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// On-call layer configuration.
|
||||
/// </summary>
|
||||
public sealed record OnCallLayerRequest
|
||||
{
|
||||
public string? LayerId { get; init; }
|
||||
public string? Name { get; init; }
|
||||
public int Priority { get; init; }
|
||||
public DateTimeOffset RotationStartsAt { get; init; }
|
||||
public TimeSpan RotationInterval { get; init; }
|
||||
public ImmutableArray<OnCallParticipantRequest> Participants { get; init; }
|
||||
public OnCallRestrictionRequest? Restrictions { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// On-call participant configuration.
|
||||
/// </summary>
|
||||
public sealed record OnCallParticipantRequest
|
||||
{
|
||||
public string? UserId { get; init; }
|
||||
public string? Name { get; init; }
|
||||
public string? Email { get; init; }
|
||||
public ImmutableArray<ContactMethodRequest> ContactMethods { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Contact method configuration.
|
||||
/// </summary>
|
||||
public sealed record ContactMethodRequest
|
||||
{
|
||||
public string? Type { get; init; }
|
||||
public string? Address { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// On-call restriction configuration.
|
||||
/// </summary>
|
||||
public sealed record OnCallRestrictionRequest
|
||||
{
|
||||
public string? Type { get; init; }
|
||||
public ImmutableArray<TimeRangeRequest> TimeRanges { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Time range for on-call restrictions.
|
||||
/// </summary>
|
||||
public sealed record TimeRangeRequest
|
||||
{
|
||||
public TimeOnly StartTime { get; init; }
|
||||
public TimeOnly EndTime { get; init; }
|
||||
public DayOfWeek? DayOfWeek { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to add an on-call override.
|
||||
/// </summary>
|
||||
public sealed record OnCallOverrideRequest
|
||||
{
|
||||
public string? UserId { get; init; }
|
||||
public DateTimeOffset StartsAt { get; init; }
|
||||
public DateTimeOffset EndsAt { get; init; }
|
||||
public string? Reason { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to resolve who is on-call.
|
||||
/// </summary>
|
||||
public sealed record OnCallResolveRequest
|
||||
{
|
||||
public DateTimeOffset? EvaluationTime { get; init; }
|
||||
}
|
||||
using System.Collections.Immutable;
|
||||
using System.Text.Json.Serialization;
|
||||
using StellaOps.Notify.Models;
|
||||
|
||||
namespace StellaOps.Notifier.WebService.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Request to create/update an escalation policy.
|
||||
/// </summary>
|
||||
public sealed record EscalationPolicyUpsertRequest
|
||||
{
|
||||
public string? Name { get; init; }
|
||||
public string? Description { get; init; }
|
||||
public ImmutableArray<EscalationLevelRequest> Levels { get; init; }
|
||||
public int? RepeatCount { get; init; }
|
||||
public bool? Enabled { get; init; }
|
||||
public IReadOnlyDictionary<string, string>? Metadata { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Escalation level configuration.
|
||||
/// </summary>
|
||||
public sealed record EscalationLevelRequest
|
||||
{
|
||||
public int Order { get; init; }
|
||||
public TimeSpan EscalateAfter { get; init; }
|
||||
public ImmutableArray<EscalationTargetRequest> Targets { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Escalation target configuration.
|
||||
/// </summary>
|
||||
public sealed record EscalationTargetRequest
|
||||
{
|
||||
public string? Type { get; init; }
|
||||
public string? TargetId { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to start an escalation for an incident.
|
||||
/// </summary>
|
||||
public sealed record StartEscalationRequest
|
||||
{
|
||||
public string? IncidentId { get; init; }
|
||||
public string? PolicyId { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to acknowledge an escalation.
|
||||
/// </summary>
|
||||
public sealed record AcknowledgeEscalationRequest
|
||||
{
|
||||
public string? StateIdOrIncidentId { get; init; }
|
||||
public string? AcknowledgedBy { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to resolve an escalation.
|
||||
/// </summary>
|
||||
public sealed record ResolveEscalationRequest
|
||||
{
|
||||
public string? StateIdOrIncidentId { get; init; }
|
||||
public string? ResolvedBy { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to create/update an on-call schedule.
|
||||
/// </summary>
|
||||
public sealed record OnCallScheduleUpsertRequest
|
||||
{
|
||||
public string? Name { get; init; }
|
||||
public string? Description { get; init; }
|
||||
public string? TimeZone { get; init; }
|
||||
public ImmutableArray<OnCallLayerRequest> Layers { get; init; }
|
||||
public bool? Enabled { get; init; }
|
||||
public IReadOnlyDictionary<string, string>? Metadata { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// On-call layer configuration.
|
||||
/// </summary>
|
||||
public sealed record OnCallLayerRequest
|
||||
{
|
||||
public string? LayerId { get; init; }
|
||||
public string? Name { get; init; }
|
||||
public int Priority { get; init; }
|
||||
public DateTimeOffset RotationStartsAt { get; init; }
|
||||
public TimeSpan RotationInterval { get; init; }
|
||||
public ImmutableArray<OnCallParticipantRequest> Participants { get; init; }
|
||||
public OnCallRestrictionRequest? Restrictions { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// On-call participant configuration.
|
||||
/// </summary>
|
||||
public sealed record OnCallParticipantRequest
|
||||
{
|
||||
public string? UserId { get; init; }
|
||||
public string? Name { get; init; }
|
||||
public string? Email { get; init; }
|
||||
public ImmutableArray<ContactMethodRequest> ContactMethods { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Contact method configuration.
|
||||
/// </summary>
|
||||
public sealed record ContactMethodRequest
|
||||
{
|
||||
public string? Type { get; init; }
|
||||
public string? Address { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// On-call restriction configuration.
|
||||
/// </summary>
|
||||
public sealed record OnCallRestrictionRequest
|
||||
{
|
||||
public string? Type { get; init; }
|
||||
public ImmutableArray<TimeRangeRequest> TimeRanges { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Time range for on-call restrictions.
|
||||
/// </summary>
|
||||
public sealed record TimeRangeRequest
|
||||
{
|
||||
public TimeOnly StartTime { get; init; }
|
||||
public TimeOnly EndTime { get; init; }
|
||||
public DayOfWeek? DayOfWeek { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to add an on-call override.
|
||||
/// </summary>
|
||||
public sealed record OnCallOverrideRequest
|
||||
{
|
||||
public string? UserId { get; init; }
|
||||
public DateTimeOffset StartsAt { get; init; }
|
||||
public DateTimeOffset EndsAt { get; init; }
|
||||
public string? Reason { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to resolve who is on-call.
|
||||
/// </summary>
|
||||
public sealed record OnCallResolveRequest
|
||||
{
|
||||
public DateTimeOffset? EvaluationTime { get; init; }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
namespace StellaOps.Notifier.WebService.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Incident list query parameters.
|
||||
/// </summary>
|
||||
public sealed record IncidentListQuery
|
||||
{
|
||||
/// <summary>
|
||||
/// Filter by status (open, acknowledged, resolved).
|
||||
/// </summary>
|
||||
public string? Status { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Filter by event kind prefix.
|
||||
/// </summary>
|
||||
public string? EventKindPrefix { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Filter incidents after this timestamp.
|
||||
/// </summary>
|
||||
public DateTimeOffset? Since { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Filter incidents before this timestamp.
|
||||
/// </summary>
|
||||
public DateTimeOffset? Until { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Maximum number of results.
|
||||
/// </summary>
|
||||
public int? Limit { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Cursor for pagination.
|
||||
/// </summary>
|
||||
public string? Cursor { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Incident response DTO.
|
||||
/// </summary>
|
||||
public sealed record IncidentResponse
|
||||
{
|
||||
public required string IncidentId { get; init; }
|
||||
public required string TenantId { get; init; }
|
||||
public required string EventKind { get; init; }
|
||||
public required string Status { get; init; }
|
||||
public required string Severity { get; init; }
|
||||
public required string Title { get; init; }
|
||||
public string? Description { get; init; }
|
||||
public required int EventCount { get; init; }
|
||||
public required DateTimeOffset FirstOccurrence { get; init; }
|
||||
public required DateTimeOffset LastOccurrence { get; init; }
|
||||
public string? AcknowledgedBy { get; init; }
|
||||
public DateTimeOffset? AcknowledgedAt { get; init; }
|
||||
public string? ResolvedBy { get; init; }
|
||||
public DateTimeOffset? ResolvedAt { get; init; }
|
||||
public List<string>? Labels { get; init; }
|
||||
public Dictionary<string, string>? Metadata { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Incident list response with pagination.
|
||||
/// </summary>
|
||||
public sealed record IncidentListResponse
|
||||
{
|
||||
public required List<IncidentResponse> Incidents { get; init; }
|
||||
public required int TotalCount { get; init; }
|
||||
public string? NextCursor { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to acknowledge an incident.
|
||||
/// </summary>
|
||||
public sealed record IncidentAckRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Actor performing the acknowledgement.
|
||||
/// </summary>
|
||||
public string? Actor { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Optional comment.
|
||||
/// </summary>
|
||||
public string? Comment { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to resolve an incident.
|
||||
/// </summary>
|
||||
public sealed record IncidentResolveRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Actor resolving the incident.
|
||||
/// </summary>
|
||||
public string? Actor { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Resolution reason.
|
||||
/// </summary>
|
||||
public string? Reason { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Optional comment.
|
||||
/// </summary>
|
||||
public string? Comment { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delivery history item for an incident.
|
||||
/// </summary>
|
||||
public sealed record DeliveryHistoryItem
|
||||
{
|
||||
public required string DeliveryId { get; init; }
|
||||
public required string ChannelType { get; init; }
|
||||
public required string ChannelName { get; init; }
|
||||
public required string Status { get; init; }
|
||||
public required DateTimeOffset Timestamp { get; init; }
|
||||
public string? ErrorMessage { get; init; }
|
||||
public int Attempts { get; init; }
|
||||
}
|
||||
@@ -1,45 +1,45 @@
|
||||
namespace StellaOps.Notifier.WebService.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Request to create/update a localization bundle.
|
||||
/// </summary>
|
||||
public sealed record LocalizationBundleUpsertRequest
|
||||
{
|
||||
public string? Locale { get; init; }
|
||||
public string? BundleKey { get; init; }
|
||||
public IReadOnlyDictionary<string, string>? Strings { get; init; }
|
||||
public bool? IsDefault { get; init; }
|
||||
public string? ParentLocale { get; init; }
|
||||
public string? Description { get; init; }
|
||||
public IReadOnlyDictionary<string, string>? Metadata { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to resolve localized strings.
|
||||
/// </summary>
|
||||
public sealed record LocalizationResolveRequest
|
||||
{
|
||||
public string? BundleKey { get; init; }
|
||||
public IReadOnlyList<string>? StringKeys { get; init; }
|
||||
public string? Locale { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response containing resolved localized strings.
|
||||
/// </summary>
|
||||
public sealed record LocalizationResolveResponse
|
||||
{
|
||||
public required IReadOnlyDictionary<string, LocalizedStringResult> Strings { get; init; }
|
||||
public required string RequestedLocale { get; init; }
|
||||
public required IReadOnlyList<string> FallbackChain { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Result for a single localized string.
|
||||
/// </summary>
|
||||
public sealed record LocalizedStringResult
|
||||
{
|
||||
public required string Value { get; init; }
|
||||
public required string ResolvedLocale { get; init; }
|
||||
public required bool UsedFallback { get; init; }
|
||||
}
|
||||
namespace StellaOps.Notifier.WebService.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Request to create/update a localization bundle.
|
||||
/// </summary>
|
||||
public sealed record LocalizationBundleUpsertRequest
|
||||
{
|
||||
public string? Locale { get; init; }
|
||||
public string? BundleKey { get; init; }
|
||||
public IReadOnlyDictionary<string, string>? Strings { get; init; }
|
||||
public bool? IsDefault { get; init; }
|
||||
public string? ParentLocale { get; init; }
|
||||
public string? Description { get; init; }
|
||||
public IReadOnlyDictionary<string, string>? Metadata { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to resolve localized strings.
|
||||
/// </summary>
|
||||
public sealed record LocalizationResolveRequest
|
||||
{
|
||||
public string? BundleKey { get; init; }
|
||||
public IReadOnlyList<string>? StringKeys { get; init; }
|
||||
public string? Locale { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response containing resolved localized strings.
|
||||
/// </summary>
|
||||
public sealed record LocalizationResolveResponse
|
||||
{
|
||||
public required IReadOnlyDictionary<string, LocalizedStringResult> Strings { get; init; }
|
||||
public required string RequestedLocale { get; init; }
|
||||
public required IReadOnlyList<string> FallbackChain { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Result for a single localized string.
|
||||
/// </summary>
|
||||
public sealed record LocalizedStringResult
|
||||
{
|
||||
public required string Value { get; init; }
|
||||
public required string ResolvedLocale { get; init; }
|
||||
public required bool UsedFallback { get; init; }
|
||||
}
|
||||
|
||||
@@ -1,9 +1,35 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace StellaOps.Notifier.WebService.Contracts;
|
||||
|
||||
public sealed class PackApprovalAckRequest
|
||||
{
|
||||
[Required]
|
||||
public string AckToken { get; init; } = string.Empty;
|
||||
}
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace StellaOps.Notifier.WebService.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Request payload for acknowledging a pack approval decision.
|
||||
/// </summary>
|
||||
public sealed class PackApprovalAckRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Acknowledgement token from the notification.
|
||||
/// </summary>
|
||||
[Required]
|
||||
[JsonPropertyName("ackToken")]
|
||||
public string AckToken { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Approval decision: "approved" or "rejected".
|
||||
/// </summary>
|
||||
[JsonPropertyName("decision")]
|
||||
public string? Decision { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Optional comment for audit trail.
|
||||
/// </summary>
|
||||
[JsonPropertyName("comment")]
|
||||
public string? Comment { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Identity acknowledging the approval.
|
||||
/// </summary>
|
||||
[JsonPropertyName("actor")]
|
||||
public string? Actor { get; init; }
|
||||
}
|
||||
|
||||
@@ -1,45 +1,88 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace StellaOps.Notifier.WebService.Contracts;
|
||||
|
||||
public sealed class PackApprovalRequest
|
||||
{
|
||||
[JsonPropertyName("eventId")]
|
||||
public Guid EventId { get; init; }
|
||||
|
||||
[JsonPropertyName("issuedAt")]
|
||||
public DateTimeOffset IssuedAt { get; init; }
|
||||
|
||||
[JsonPropertyName("kind")]
|
||||
public string Kind { get; init; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("packId")]
|
||||
public string PackId { get; init; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("policy")]
|
||||
public PackApprovalPolicy? Policy { get; init; }
|
||||
|
||||
[JsonPropertyName("decision")]
|
||||
public string Decision { get; init; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("actor")]
|
||||
public string Actor { get; init; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("resumeToken")]
|
||||
public string? ResumeToken { get; init; }
|
||||
|
||||
[JsonPropertyName("summary")]
|
||||
public string? Summary { get; init; }
|
||||
|
||||
[JsonPropertyName("labels")]
|
||||
public Dictionary<string, string>? Labels { get; init; }
|
||||
}
|
||||
|
||||
public sealed class PackApprovalPolicy
|
||||
{
|
||||
[JsonPropertyName("id")]
|
||||
public string? Id { get; init; }
|
||||
|
||||
[JsonPropertyName("version")]
|
||||
public string? Version { get; init; }
|
||||
}
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace StellaOps.Notifier.WebService.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Request payload for pack approval events from Task Runner.
|
||||
/// See: docs/notifications/pack-approvals-contract.md
|
||||
/// </summary>
|
||||
public sealed class PackApprovalRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Unique event identifier for deduplication.
|
||||
/// </summary>
|
||||
[JsonPropertyName("eventId")]
|
||||
public Guid EventId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Event timestamp in UTC (ISO 8601).
|
||||
/// </summary>
|
||||
[JsonPropertyName("issuedAt")]
|
||||
public DateTimeOffset IssuedAt { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Event type: pack.approval.requested, pack.approval.updated, pack.policy.hold, pack.policy.released.
|
||||
/// </summary>
|
||||
[JsonPropertyName("kind")]
|
||||
public string Kind { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Package identifier in PURL format.
|
||||
/// </summary>
|
||||
[JsonPropertyName("packId")]
|
||||
public string PackId { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Policy metadata (id and version).
|
||||
/// </summary>
|
||||
[JsonPropertyName("policy")]
|
||||
public PackApprovalPolicy? Policy { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Current approval state: pending, approved, rejected, hold, expired.
|
||||
/// </summary>
|
||||
[JsonPropertyName("decision")]
|
||||
public string Decision { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Identity that triggered the event.
|
||||
/// </summary>
|
||||
[JsonPropertyName("actor")]
|
||||
public string Actor { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Opaque token for Task Runner resume flow. Echoed in X-Resume-After header.
|
||||
/// </summary>
|
||||
[JsonPropertyName("resumeToken")]
|
||||
public string? ResumeToken { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Human-readable summary for notifications.
|
||||
/// </summary>
|
||||
[JsonPropertyName("summary")]
|
||||
public string? Summary { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Custom key-value metadata labels.
|
||||
/// </summary>
|
||||
[JsonPropertyName("labels")]
|
||||
public Dictionary<string, string>? Labels { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Policy metadata associated with a pack approval.
|
||||
/// </summary>
|
||||
public sealed class PackApprovalPolicy
|
||||
{
|
||||
/// <summary>
|
||||
/// Policy identifier.
|
||||
/// </summary>
|
||||
[JsonPropertyName("id")]
|
||||
public string? Id { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Policy version.
|
||||
/// </summary>
|
||||
[JsonPropertyName("version")]
|
||||
public string? Version { get; init; }
|
||||
}
|
||||
|
||||
@@ -1,60 +1,60 @@
|
||||
using System.Collections.Immutable;
|
||||
|
||||
namespace StellaOps.Notifier.WebService.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Request to create or update a quiet hours schedule.
|
||||
/// </summary>
|
||||
public sealed class QuietHoursUpsertRequest
|
||||
{
|
||||
public required string Name { get; init; }
|
||||
public required string CronExpression { get; init; }
|
||||
public required TimeSpan Duration { get; init; }
|
||||
public required string TimeZone { get; init; }
|
||||
public string? ChannelId { get; init; }
|
||||
public bool? Enabled { get; init; }
|
||||
public string? Description { get; init; }
|
||||
public ImmutableDictionary<string, string>? Metadata { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to create or update a maintenance window.
|
||||
/// </summary>
|
||||
public sealed class MaintenanceWindowUpsertRequest
|
||||
{
|
||||
public required string Name { get; init; }
|
||||
public required DateTimeOffset StartsAt { get; init; }
|
||||
public required DateTimeOffset EndsAt { get; init; }
|
||||
public bool? SuppressNotifications { get; init; }
|
||||
public string? Reason { get; init; }
|
||||
public ImmutableArray<string> ChannelIds { get; init; } = [];
|
||||
public ImmutableArray<string> RuleIds { get; init; } = [];
|
||||
public ImmutableDictionary<string, string>? Metadata { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to create or update a throttle configuration.
|
||||
/// </summary>
|
||||
public sealed class ThrottleConfigUpsertRequest
|
||||
{
|
||||
public required string Name { get; init; }
|
||||
public required TimeSpan DefaultWindow { get; init; }
|
||||
public int? MaxNotificationsPerWindow { get; init; }
|
||||
public string? ChannelId { get; init; }
|
||||
public bool? IsDefault { get; init; }
|
||||
public bool? Enabled { get; init; }
|
||||
public string? Description { get; init; }
|
||||
public ImmutableDictionary<string, string>? Metadata { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to create an operator override.
|
||||
/// </summary>
|
||||
public sealed class OperatorOverrideCreateRequest
|
||||
{
|
||||
public required string OverrideType { get; init; }
|
||||
public required DateTimeOffset ExpiresAt { get; init; }
|
||||
public string? ChannelId { get; init; }
|
||||
public string? RuleId { get; init; }
|
||||
public string? Reason { get; init; }
|
||||
}
|
||||
using System.Collections.Immutable;
|
||||
|
||||
namespace StellaOps.Notifier.WebService.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Request to create or update a quiet hours schedule.
|
||||
/// </summary>
|
||||
public sealed class QuietHoursUpsertRequest
|
||||
{
|
||||
public required string Name { get; init; }
|
||||
public required string CronExpression { get; init; }
|
||||
public required TimeSpan Duration { get; init; }
|
||||
public required string TimeZone { get; init; }
|
||||
public string? ChannelId { get; init; }
|
||||
public bool? Enabled { get; init; }
|
||||
public string? Description { get; init; }
|
||||
public ImmutableDictionary<string, string>? Metadata { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to create or update a maintenance window.
|
||||
/// </summary>
|
||||
public sealed class MaintenanceWindowUpsertRequest
|
||||
{
|
||||
public required string Name { get; init; }
|
||||
public required DateTimeOffset StartsAt { get; init; }
|
||||
public required DateTimeOffset EndsAt { get; init; }
|
||||
public bool? SuppressNotifications { get; init; }
|
||||
public string? Reason { get; init; }
|
||||
public ImmutableArray<string> ChannelIds { get; init; } = [];
|
||||
public ImmutableArray<string> RuleIds { get; init; } = [];
|
||||
public ImmutableDictionary<string, string>? Metadata { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to create or update a throttle configuration.
|
||||
/// </summary>
|
||||
public sealed class ThrottleConfigUpsertRequest
|
||||
{
|
||||
public required string Name { get; init; }
|
||||
public required TimeSpan DefaultWindow { get; init; }
|
||||
public int? MaxNotificationsPerWindow { get; init; }
|
||||
public string? ChannelId { get; init; }
|
||||
public bool? IsDefault { get; init; }
|
||||
public bool? Enabled { get; init; }
|
||||
public string? Description { get; init; }
|
||||
public ImmutableDictionary<string, string>? Metadata { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to create an operator override.
|
||||
/// </summary>
|
||||
public sealed class OperatorOverrideCreateRequest
|
||||
{
|
||||
public required string OverrideType { get; init; }
|
||||
public required DateTimeOffset ExpiresAt { get; init; }
|
||||
public string? ChannelId { get; init; }
|
||||
public string? RuleId { get; init; }
|
||||
public string? Reason { get; init; }
|
||||
}
|
||||
|
||||
@@ -1,143 +1,143 @@
|
||||
namespace StellaOps.Notifier.WebService.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Retention policy configuration request/response.
|
||||
/// </summary>
|
||||
public sealed record RetentionPolicyDto
|
||||
{
|
||||
/// <summary>
|
||||
/// Retention period for delivery records in days.
|
||||
/// </summary>
|
||||
public int DeliveryRetentionDays { get; init; } = 90;
|
||||
|
||||
/// <summary>
|
||||
/// Retention period for audit log entries in days.
|
||||
/// </summary>
|
||||
public int AuditRetentionDays { get; init; } = 365;
|
||||
|
||||
/// <summary>
|
||||
/// Retention period for dead-letter entries in days.
|
||||
/// </summary>
|
||||
public int DeadLetterRetentionDays { get; init; } = 30;
|
||||
|
||||
/// <summary>
|
||||
/// Retention period for storm tracking data in days.
|
||||
/// </summary>
|
||||
public int StormDataRetentionDays { get; init; } = 7;
|
||||
|
||||
/// <summary>
|
||||
/// Retention period for inbox messages in days.
|
||||
/// </summary>
|
||||
public int InboxRetentionDays { get; init; } = 30;
|
||||
|
||||
/// <summary>
|
||||
/// Retention period for event history in days.
|
||||
/// </summary>
|
||||
public int EventHistoryRetentionDays { get; init; } = 30;
|
||||
|
||||
/// <summary>
|
||||
/// Whether automatic cleanup is enabled.
|
||||
/// </summary>
|
||||
public bool AutoCleanupEnabled { get; init; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Cron expression for automatic cleanup schedule.
|
||||
/// </summary>
|
||||
public string CleanupSchedule { get; init; } = "0 2 * * *";
|
||||
|
||||
/// <summary>
|
||||
/// Maximum records to delete per cleanup run.
|
||||
/// </summary>
|
||||
public int MaxDeletesPerRun { get; init; } = 10000;
|
||||
|
||||
/// <summary>
|
||||
/// Whether to keep resolved/acknowledged deliveries longer.
|
||||
/// </summary>
|
||||
public bool ExtendResolvedRetention { get; init; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Extension multiplier for resolved items.
|
||||
/// </summary>
|
||||
public double ResolvedRetentionMultiplier { get; init; } = 2.0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to update retention policy.
|
||||
/// </summary>
|
||||
public sealed record UpdateRetentionPolicyRequest
|
||||
{
|
||||
public required RetentionPolicyDto Policy { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response for retention policy operations.
|
||||
/// </summary>
|
||||
public sealed record RetentionPolicyResponse
|
||||
{
|
||||
public required string TenantId { get; init; }
|
||||
public required RetentionPolicyDto Policy { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response for retention cleanup execution.
|
||||
/// </summary>
|
||||
public sealed record RetentionCleanupResponse
|
||||
{
|
||||
public required string TenantId { get; init; }
|
||||
public required bool Success { get; init; }
|
||||
public string? Error { get; init; }
|
||||
public required DateTimeOffset ExecutedAt { get; init; }
|
||||
public required double DurationMs { get; init; }
|
||||
public required RetentionCleanupCountsDto Counts { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cleanup counts DTO.
|
||||
/// </summary>
|
||||
public sealed record RetentionCleanupCountsDto
|
||||
{
|
||||
public int Deliveries { get; init; }
|
||||
public int AuditEntries { get; init; }
|
||||
public int DeadLetterEntries { get; init; }
|
||||
public int StormData { get; init; }
|
||||
public int InboxMessages { get; init; }
|
||||
public int Events { get; init; }
|
||||
public int Total { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response for cleanup preview.
|
||||
/// </summary>
|
||||
public sealed record RetentionCleanupPreviewResponse
|
||||
{
|
||||
public required string TenantId { get; init; }
|
||||
public required DateTimeOffset PreviewedAt { get; init; }
|
||||
public required RetentionCleanupCountsDto EstimatedCounts { get; init; }
|
||||
public required RetentionPolicyDto PolicyApplied { get; init; }
|
||||
public required IReadOnlyDictionary<string, DateTimeOffset> CutoffDates { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response for last cleanup execution.
|
||||
/// </summary>
|
||||
public sealed record RetentionCleanupExecutionResponse
|
||||
{
|
||||
public required string ExecutionId { get; init; }
|
||||
public required string TenantId { get; init; }
|
||||
public required DateTimeOffset StartedAt { get; init; }
|
||||
public DateTimeOffset? CompletedAt { get; init; }
|
||||
public required string Status { get; init; }
|
||||
public RetentionCleanupCountsDto? Counts { get; init; }
|
||||
public string? Error { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response for cleanup all tenants.
|
||||
/// </summary>
|
||||
public sealed record RetentionCleanupAllResponse
|
||||
{
|
||||
public required IReadOnlyList<RetentionCleanupResponse> Results { get; init; }
|
||||
public required int SuccessCount { get; init; }
|
||||
public required int FailureCount { get; init; }
|
||||
public required int TotalDeleted { get; init; }
|
||||
}
|
||||
namespace StellaOps.Notifier.WebService.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Retention policy configuration request/response.
|
||||
/// </summary>
|
||||
public sealed record RetentionPolicyDto
|
||||
{
|
||||
/// <summary>
|
||||
/// Retention period for delivery records in days.
|
||||
/// </summary>
|
||||
public int DeliveryRetentionDays { get; init; } = 90;
|
||||
|
||||
/// <summary>
|
||||
/// Retention period for audit log entries in days.
|
||||
/// </summary>
|
||||
public int AuditRetentionDays { get; init; } = 365;
|
||||
|
||||
/// <summary>
|
||||
/// Retention period for dead-letter entries in days.
|
||||
/// </summary>
|
||||
public int DeadLetterRetentionDays { get; init; } = 30;
|
||||
|
||||
/// <summary>
|
||||
/// Retention period for storm tracking data in days.
|
||||
/// </summary>
|
||||
public int StormDataRetentionDays { get; init; } = 7;
|
||||
|
||||
/// <summary>
|
||||
/// Retention period for inbox messages in days.
|
||||
/// </summary>
|
||||
public int InboxRetentionDays { get; init; } = 30;
|
||||
|
||||
/// <summary>
|
||||
/// Retention period for event history in days.
|
||||
/// </summary>
|
||||
public int EventHistoryRetentionDays { get; init; } = 30;
|
||||
|
||||
/// <summary>
|
||||
/// Whether automatic cleanup is enabled.
|
||||
/// </summary>
|
||||
public bool AutoCleanupEnabled { get; init; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Cron expression for automatic cleanup schedule.
|
||||
/// </summary>
|
||||
public string CleanupSchedule { get; init; } = "0 2 * * *";
|
||||
|
||||
/// <summary>
|
||||
/// Maximum records to delete per cleanup run.
|
||||
/// </summary>
|
||||
public int MaxDeletesPerRun { get; init; } = 10000;
|
||||
|
||||
/// <summary>
|
||||
/// Whether to keep resolved/acknowledged deliveries longer.
|
||||
/// </summary>
|
||||
public bool ExtendResolvedRetention { get; init; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Extension multiplier for resolved items.
|
||||
/// </summary>
|
||||
public double ResolvedRetentionMultiplier { get; init; } = 2.0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to update retention policy.
|
||||
/// </summary>
|
||||
public sealed record UpdateRetentionPolicyRequest
|
||||
{
|
||||
public required RetentionPolicyDto Policy { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response for retention policy operations.
|
||||
/// </summary>
|
||||
public sealed record RetentionPolicyResponse
|
||||
{
|
||||
public required string TenantId { get; init; }
|
||||
public required RetentionPolicyDto Policy { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response for retention cleanup execution.
|
||||
/// </summary>
|
||||
public sealed record RetentionCleanupResponse
|
||||
{
|
||||
public required string TenantId { get; init; }
|
||||
public required bool Success { get; init; }
|
||||
public string? Error { get; init; }
|
||||
public required DateTimeOffset ExecutedAt { get; init; }
|
||||
public required double DurationMs { get; init; }
|
||||
public required RetentionCleanupCountsDto Counts { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cleanup counts DTO.
|
||||
/// </summary>
|
||||
public sealed record RetentionCleanupCountsDto
|
||||
{
|
||||
public int Deliveries { get; init; }
|
||||
public int AuditEntries { get; init; }
|
||||
public int DeadLetterEntries { get; init; }
|
||||
public int StormData { get; init; }
|
||||
public int InboxMessages { get; init; }
|
||||
public int Events { get; init; }
|
||||
public int Total { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response for cleanup preview.
|
||||
/// </summary>
|
||||
public sealed record RetentionCleanupPreviewResponse
|
||||
{
|
||||
public required string TenantId { get; init; }
|
||||
public required DateTimeOffset PreviewedAt { get; init; }
|
||||
public required RetentionCleanupCountsDto EstimatedCounts { get; init; }
|
||||
public required RetentionPolicyDto PolicyApplied { get; init; }
|
||||
public required IReadOnlyDictionary<string, DateTimeOffset> CutoffDates { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response for last cleanup execution.
|
||||
/// </summary>
|
||||
public sealed record RetentionCleanupExecutionResponse
|
||||
{
|
||||
public required string ExecutionId { get; init; }
|
||||
public required string TenantId { get; init; }
|
||||
public required DateTimeOffset StartedAt { get; init; }
|
||||
public DateTimeOffset? CompletedAt { get; init; }
|
||||
public required string Status { get; init; }
|
||||
public RetentionCleanupCountsDto? Counts { get; init; }
|
||||
public string? Error { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response for cleanup all tenants.
|
||||
/// </summary>
|
||||
public sealed record RetentionCleanupAllResponse
|
||||
{
|
||||
public required IReadOnlyList<RetentionCleanupResponse> Results { get; init; }
|
||||
public required int SuccessCount { get; init; }
|
||||
public required int FailureCount { get; init; }
|
||||
public required int TotalDeleted { get; init; }
|
||||
}
|
||||
|
||||
@@ -1,33 +1,114 @@
|
||||
namespace StellaOps.Notifier.WebService.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Request for creating or updating a rule.
|
||||
/// </summary>
|
||||
public sealed record RuleUpsertRequest
|
||||
{
|
||||
public string? Name { get; init; }
|
||||
public RuleMatchRequest? Match { get; init; }
|
||||
public IReadOnlyList<RuleActionRequest>? Actions { get; init; }
|
||||
public bool? Enabled { get; init; }
|
||||
public string? Description { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Match criteria for a rule.
|
||||
/// </summary>
|
||||
public sealed record RuleMatchRequest
|
||||
{
|
||||
public string[]? EventKinds { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Action definition for a rule.
|
||||
/// </summary>
|
||||
public sealed record RuleActionRequest
|
||||
{
|
||||
public string? ActionId { get; init; }
|
||||
public string? Channel { get; init; }
|
||||
public string? Template { get; init; }
|
||||
public string? Locale { get; init; }
|
||||
public bool? Enabled { get; init; }
|
||||
}
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace StellaOps.Notifier.WebService.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Request to create or update a notification rule.
|
||||
/// </summary>
|
||||
public sealed record RuleCreateRequest
|
||||
{
|
||||
public required string RuleId { get; init; }
|
||||
public required string Name { get; init; }
|
||||
public string? Description { get; init; }
|
||||
public bool Enabled { get; init; } = true;
|
||||
public required RuleMatchRequest Match { get; init; }
|
||||
public required List<RuleActionRequest> Actions { get; init; }
|
||||
public Dictionary<string, string>? Labels { get; init; }
|
||||
public Dictionary<string, string>? Metadata { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to update an existing rule.
|
||||
/// </summary>
|
||||
public sealed record RuleUpdateRequest
|
||||
{
|
||||
public string? Name { get; init; }
|
||||
public string? Description { get; init; }
|
||||
public bool? Enabled { get; init; }
|
||||
public RuleMatchRequest? Match { get; init; }
|
||||
public List<RuleActionRequest>? Actions { get; init; }
|
||||
public Dictionary<string, string>? Labels { get; init; }
|
||||
public Dictionary<string, string>? Metadata { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rule match criteria.
|
||||
/// </summary>
|
||||
public sealed record RuleMatchRequest
|
||||
{
|
||||
public List<string>? EventKinds { get; init; }
|
||||
public List<string>? Namespaces { get; init; }
|
||||
public List<string>? Repositories { get; init; }
|
||||
public List<string>? Digests { get; init; }
|
||||
public List<string>? Labels { get; init; }
|
||||
public List<string>? ComponentPurls { get; init; }
|
||||
public string? MinSeverity { get; init; }
|
||||
public List<string>? Verdicts { get; init; }
|
||||
public bool? KevOnly { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rule action configuration.
|
||||
/// </summary>
|
||||
public sealed record RuleActionRequest
|
||||
{
|
||||
public required string ActionId { get; init; }
|
||||
public required string Channel { get; init; }
|
||||
public string? Template { get; init; }
|
||||
public string? Digest { get; init; }
|
||||
public string? Throttle { get; init; } // ISO 8601 duration
|
||||
public string? Locale { get; init; }
|
||||
public bool Enabled { get; init; } = true;
|
||||
public Dictionary<string, string>? Metadata { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rule response DTO.
|
||||
/// </summary>
|
||||
public sealed record RuleResponse
|
||||
{
|
||||
public required string RuleId { get; init; }
|
||||
public required string TenantId { get; init; }
|
||||
public required string Name { get; init; }
|
||||
public string? Description { get; init; }
|
||||
public required bool Enabled { get; init; }
|
||||
public required RuleMatchResponse Match { get; init; }
|
||||
public required List<RuleActionResponse> Actions { get; init; }
|
||||
public Dictionary<string, string>? Labels { get; init; }
|
||||
public Dictionary<string, string>? Metadata { get; init; }
|
||||
public string? CreatedBy { get; init; }
|
||||
public DateTimeOffset CreatedAt { get; init; }
|
||||
public string? UpdatedBy { get; init; }
|
||||
public DateTimeOffset UpdatedAt { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rule match response.
|
||||
/// </summary>
|
||||
public sealed record RuleMatchResponse
|
||||
{
|
||||
public List<string> EventKinds { get; init; } = [];
|
||||
public List<string> Namespaces { get; init; } = [];
|
||||
public List<string> Repositories { get; init; } = [];
|
||||
public List<string> Digests { get; init; } = [];
|
||||
public List<string> Labels { get; init; } = [];
|
||||
public List<string> ComponentPurls { get; init; } = [];
|
||||
public string? MinSeverity { get; init; }
|
||||
public List<string> Verdicts { get; init; } = [];
|
||||
public bool KevOnly { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rule action response.
|
||||
/// </summary>
|
||||
public sealed record RuleActionResponse
|
||||
{
|
||||
public required string ActionId { get; init; }
|
||||
public required string Channel { get; init; }
|
||||
public string? Template { get; init; }
|
||||
public string? Digest { get; init; }
|
||||
public string? Throttle { get; init; }
|
||||
public string? Locale { get; init; }
|
||||
public required bool Enabled { get; init; }
|
||||
public Dictionary<string, string>? Metadata { get; init; }
|
||||
}
|
||||
|
||||
@@ -1,305 +1,305 @@
|
||||
namespace StellaOps.Notifier.WebService.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Request to acknowledge a notification via signed token.
|
||||
/// </summary>
|
||||
public sealed record AckRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Optional comment for the acknowledgement.
|
||||
/// </summary>
|
||||
public string? Comment { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Optional metadata to include with the acknowledgement.
|
||||
/// </summary>
|
||||
public IReadOnlyDictionary<string, string>? Metadata { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response from acknowledging a notification.
|
||||
/// </summary>
|
||||
public sealed record AckResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether the acknowledgement was successful.
|
||||
/// </summary>
|
||||
public required bool Success { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The delivery ID that was acknowledged.
|
||||
/// </summary>
|
||||
public string? DeliveryId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The action that was performed.
|
||||
/// </summary>
|
||||
public string? Action { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// When the acknowledgement was processed.
|
||||
/// </summary>
|
||||
public DateTimeOffset? ProcessedAt { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Error message if unsuccessful.
|
||||
/// </summary>
|
||||
public string? Error { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to create an acknowledgement token.
|
||||
/// </summary>
|
||||
public sealed record CreateAckTokenRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// The delivery ID to create an ack token for.
|
||||
/// </summary>
|
||||
public string? DeliveryId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The action to acknowledge (e.g., "ack", "resolve", "escalate").
|
||||
/// </summary>
|
||||
public string? Action { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Optional expiration in hours. Default: 168 (7 days).
|
||||
/// </summary>
|
||||
public int? ExpirationHours { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Optional metadata to embed in the token.
|
||||
/// </summary>
|
||||
public IReadOnlyDictionary<string, string>? Metadata { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response containing the created ack token.
|
||||
/// </summary>
|
||||
public sealed record CreateAckTokenResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// The signed token string.
|
||||
/// </summary>
|
||||
public required string Token { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The full acknowledgement URL.
|
||||
/// </summary>
|
||||
public required string AckUrl { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// When the token expires.
|
||||
/// </summary>
|
||||
public required DateTimeOffset ExpiresAt { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to verify an ack token.
|
||||
/// </summary>
|
||||
public sealed record VerifyAckTokenRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// The token to verify.
|
||||
/// </summary>
|
||||
public string? Token { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response from token verification.
|
||||
/// </summary>
|
||||
public sealed record VerifyAckTokenResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether the token is valid.
|
||||
/// </summary>
|
||||
public required bool IsValid { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The delivery ID embedded in the token.
|
||||
/// </summary>
|
||||
public string? DeliveryId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The action embedded in the token.
|
||||
/// </summary>
|
||||
public string? Action { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// When the token expires.
|
||||
/// </summary>
|
||||
public DateTimeOffset? ExpiresAt { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Failure reason if invalid.
|
||||
/// </summary>
|
||||
public string? FailureReason { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to validate HTML content.
|
||||
/// </summary>
|
||||
public sealed record ValidateHtmlRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// The HTML content to validate.
|
||||
/// </summary>
|
||||
public string? Html { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response from HTML validation.
|
||||
/// </summary>
|
||||
public sealed record ValidateHtmlResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether the HTML is safe.
|
||||
/// </summary>
|
||||
public required bool IsSafe { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// List of security issues found.
|
||||
/// </summary>
|
||||
public required IReadOnlyList<HtmlIssue> Issues { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Statistics about the HTML content.
|
||||
/// </summary>
|
||||
public HtmlStats? Stats { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An HTML security issue.
|
||||
/// </summary>
|
||||
public sealed record HtmlIssue
|
||||
{
|
||||
/// <summary>
|
||||
/// The type of issue.
|
||||
/// </summary>
|
||||
public required string Type { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Description of the issue.
|
||||
/// </summary>
|
||||
public required string Description { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The element name if applicable.
|
||||
/// </summary>
|
||||
public string? Element { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The attribute name if applicable.
|
||||
/// </summary>
|
||||
public string? Attribute { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// HTML content statistics.
|
||||
/// </summary>
|
||||
public sealed record HtmlStats
|
||||
{
|
||||
/// <summary>
|
||||
/// Total character count.
|
||||
/// </summary>
|
||||
public int CharacterCount { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of HTML elements.
|
||||
/// </summary>
|
||||
public int ElementCount { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Maximum nesting depth.
|
||||
/// </summary>
|
||||
public int MaxDepth { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of links.
|
||||
/// </summary>
|
||||
public int LinkCount { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of images.
|
||||
/// </summary>
|
||||
public int ImageCount { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to sanitize HTML content.
|
||||
/// </summary>
|
||||
public sealed record SanitizeHtmlRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// The HTML content to sanitize.
|
||||
/// </summary>
|
||||
public string? Html { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether to allow data: URLs. Default: false.
|
||||
/// </summary>
|
||||
public bool AllowDataUrls { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Additional tags to allow.
|
||||
/// </summary>
|
||||
public IReadOnlyList<string>? AdditionalAllowedTags { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response containing sanitized HTML.
|
||||
/// </summary>
|
||||
public sealed record SanitizeHtmlResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// The sanitized HTML content.
|
||||
/// </summary>
|
||||
public required string SanitizedHtml { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether any changes were made.
|
||||
/// </summary>
|
||||
public required bool WasModified { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to rotate a webhook secret.
|
||||
/// </summary>
|
||||
public sealed record RotateWebhookSecretRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// The channel ID to rotate the secret for.
|
||||
/// </summary>
|
||||
public string? ChannelId { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response from webhook secret rotation.
|
||||
/// </summary>
|
||||
public sealed record RotateWebhookSecretResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether rotation succeeded.
|
||||
/// </summary>
|
||||
public required bool Success { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The new secret (only shown once).
|
||||
/// </summary>
|
||||
public string? NewSecret { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// When the new secret becomes active.
|
||||
/// </summary>
|
||||
public DateTimeOffset? ActiveAt { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// When the old secret expires.
|
||||
/// </summary>
|
||||
public DateTimeOffset? OldSecretExpiresAt { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Error message if unsuccessful.
|
||||
/// </summary>
|
||||
public string? Error { get; init; }
|
||||
}
|
||||
namespace StellaOps.Notifier.WebService.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Request to acknowledge a notification via signed token.
|
||||
/// </summary>
|
||||
public sealed record AckRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Optional comment for the acknowledgement.
|
||||
/// </summary>
|
||||
public string? Comment { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Optional metadata to include with the acknowledgement.
|
||||
/// </summary>
|
||||
public IReadOnlyDictionary<string, string>? Metadata { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response from acknowledging a notification.
|
||||
/// </summary>
|
||||
public sealed record AckResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether the acknowledgement was successful.
|
||||
/// </summary>
|
||||
public required bool Success { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The delivery ID that was acknowledged.
|
||||
/// </summary>
|
||||
public string? DeliveryId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The action that was performed.
|
||||
/// </summary>
|
||||
public string? Action { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// When the acknowledgement was processed.
|
||||
/// </summary>
|
||||
public DateTimeOffset? ProcessedAt { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Error message if unsuccessful.
|
||||
/// </summary>
|
||||
public string? Error { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to create an acknowledgement token.
|
||||
/// </summary>
|
||||
public sealed record CreateAckTokenRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// The delivery ID to create an ack token for.
|
||||
/// </summary>
|
||||
public string? DeliveryId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The action to acknowledge (e.g., "ack", "resolve", "escalate").
|
||||
/// </summary>
|
||||
public string? Action { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Optional expiration in hours. Default: 168 (7 days).
|
||||
/// </summary>
|
||||
public int? ExpirationHours { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Optional metadata to embed in the token.
|
||||
/// </summary>
|
||||
public IReadOnlyDictionary<string, string>? Metadata { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response containing the created ack token.
|
||||
/// </summary>
|
||||
public sealed record CreateAckTokenResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// The signed token string.
|
||||
/// </summary>
|
||||
public required string Token { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The full acknowledgement URL.
|
||||
/// </summary>
|
||||
public required string AckUrl { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// When the token expires.
|
||||
/// </summary>
|
||||
public required DateTimeOffset ExpiresAt { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to verify an ack token.
|
||||
/// </summary>
|
||||
public sealed record VerifyAckTokenRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// The token to verify.
|
||||
/// </summary>
|
||||
public string? Token { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response from token verification.
|
||||
/// </summary>
|
||||
public sealed record VerifyAckTokenResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether the token is valid.
|
||||
/// </summary>
|
||||
public required bool IsValid { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The delivery ID embedded in the token.
|
||||
/// </summary>
|
||||
public string? DeliveryId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The action embedded in the token.
|
||||
/// </summary>
|
||||
public string? Action { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// When the token expires.
|
||||
/// </summary>
|
||||
public DateTimeOffset? ExpiresAt { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Failure reason if invalid.
|
||||
/// </summary>
|
||||
public string? FailureReason { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to validate HTML content.
|
||||
/// </summary>
|
||||
public sealed record ValidateHtmlRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// The HTML content to validate.
|
||||
/// </summary>
|
||||
public string? Html { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response from HTML validation.
|
||||
/// </summary>
|
||||
public sealed record ValidateHtmlResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether the HTML is safe.
|
||||
/// </summary>
|
||||
public required bool IsSafe { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// List of security issues found.
|
||||
/// </summary>
|
||||
public required IReadOnlyList<HtmlIssue> Issues { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Statistics about the HTML content.
|
||||
/// </summary>
|
||||
public HtmlStats? Stats { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An HTML security issue.
|
||||
/// </summary>
|
||||
public sealed record HtmlIssue
|
||||
{
|
||||
/// <summary>
|
||||
/// The type of issue.
|
||||
/// </summary>
|
||||
public required string Type { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Description of the issue.
|
||||
/// </summary>
|
||||
public required string Description { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The element name if applicable.
|
||||
/// </summary>
|
||||
public string? Element { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The attribute name if applicable.
|
||||
/// </summary>
|
||||
public string? Attribute { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// HTML content statistics.
|
||||
/// </summary>
|
||||
public sealed record HtmlStats
|
||||
{
|
||||
/// <summary>
|
||||
/// Total character count.
|
||||
/// </summary>
|
||||
public int CharacterCount { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of HTML elements.
|
||||
/// </summary>
|
||||
public int ElementCount { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Maximum nesting depth.
|
||||
/// </summary>
|
||||
public int MaxDepth { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of links.
|
||||
/// </summary>
|
||||
public int LinkCount { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of images.
|
||||
/// </summary>
|
||||
public int ImageCount { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to sanitize HTML content.
|
||||
/// </summary>
|
||||
public sealed record SanitizeHtmlRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// The HTML content to sanitize.
|
||||
/// </summary>
|
||||
public string? Html { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether to allow data: URLs. Default: false.
|
||||
/// </summary>
|
||||
public bool AllowDataUrls { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Additional tags to allow.
|
||||
/// </summary>
|
||||
public IReadOnlyList<string>? AdditionalAllowedTags { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response containing sanitized HTML.
|
||||
/// </summary>
|
||||
public sealed record SanitizeHtmlResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// The sanitized HTML content.
|
||||
/// </summary>
|
||||
public required string SanitizedHtml { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether any changes were made.
|
||||
/// </summary>
|
||||
public required bool WasModified { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to rotate a webhook secret.
|
||||
/// </summary>
|
||||
public sealed record RotateWebhookSecretRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// The channel ID to rotate the secret for.
|
||||
/// </summary>
|
||||
public string? ChannelId { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response from webhook secret rotation.
|
||||
/// </summary>
|
||||
public sealed record RotateWebhookSecretResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether rotation succeeded.
|
||||
/// </summary>
|
||||
public required bool Success { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The new secret (only shown once).
|
||||
/// </summary>
|
||||
public string? NewSecret { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// When the new secret becomes active.
|
||||
/// </summary>
|
||||
public DateTimeOffset? ActiveAt { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// When the old secret expires.
|
||||
/// </summary>
|
||||
public DateTimeOffset? OldSecretExpiresAt { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Error message if unsuccessful.
|
||||
/// </summary>
|
||||
public string? Error { get; init; }
|
||||
}
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
using System.Collections.Immutable;
|
||||
using System.Text.Json.Nodes;
|
||||
|
||||
namespace StellaOps.Notifier.WebService.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Request to run a historical simulation against past events.
|
||||
/// </summary>
|
||||
public sealed class SimulationRunRequest
|
||||
{
|
||||
public required DateTimeOffset PeriodStart { get; init; }
|
||||
public required DateTimeOffset PeriodEnd { get; init; }
|
||||
public ImmutableArray<string> RuleIds { get; init; } = [];
|
||||
public ImmutableArray<string> EventKinds { get; init; } = [];
|
||||
public int MaxEvents { get; init; } = 1000;
|
||||
public bool IncludeNonMatches { get; init; } = true;
|
||||
public bool EvaluateThrottling { get; init; } = true;
|
||||
public bool EvaluateQuietHours { get; init; } = true;
|
||||
public DateTimeOffset? EvaluationTimestamp { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to simulate a single event against current rules.
|
||||
/// </summary>
|
||||
public sealed class SimulateSingleEventRequest
|
||||
{
|
||||
public required JsonObject EventPayload { get; init; }
|
||||
public ImmutableArray<string> RuleIds { get; init; } = [];
|
||||
public DateTimeOffset? EvaluationTimestamp { get; init; }
|
||||
}
|
||||
using System.Collections.Immutable;
|
||||
using System.Text.Json.Nodes;
|
||||
|
||||
namespace StellaOps.Notifier.WebService.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Request to run a historical simulation against past events.
|
||||
/// </summary>
|
||||
public sealed class SimulationRunRequest
|
||||
{
|
||||
public required DateTimeOffset PeriodStart { get; init; }
|
||||
public required DateTimeOffset PeriodEnd { get; init; }
|
||||
public ImmutableArray<string> RuleIds { get; init; } = [];
|
||||
public ImmutableArray<string> EventKinds { get; init; } = [];
|
||||
public int MaxEvents { get; init; } = 1000;
|
||||
public bool IncludeNonMatches { get; init; } = true;
|
||||
public bool EvaluateThrottling { get; init; } = true;
|
||||
public bool EvaluateQuietHours { get; init; } = true;
|
||||
public DateTimeOffset? EvaluationTimestamp { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to simulate a single event against current rules.
|
||||
/// </summary>
|
||||
public sealed class SimulateSingleEventRequest
|
||||
{
|
||||
public required JsonObject EventPayload { get; init; }
|
||||
public ImmutableArray<string> RuleIds { get; init; } = [];
|
||||
public DateTimeOffset? EvaluationTimestamp { get; init; }
|
||||
}
|
||||
|
||||
@@ -1,30 +1,118 @@
|
||||
using System.Text.Json.Nodes;
|
||||
using StellaOps.Notify.Models;
|
||||
|
||||
namespace StellaOps.Notifier.WebService.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Request for creating or updating a template.
|
||||
/// </summary>
|
||||
public sealed record TemplateUpsertRequest
|
||||
{
|
||||
public string? Key { get; init; }
|
||||
public string? Body { get; init; }
|
||||
public string? Locale { get; init; }
|
||||
public NotifyChannelType? ChannelType { get; init; }
|
||||
public NotifyTemplateRenderMode? RenderMode { get; init; }
|
||||
public NotifyDeliveryFormat? Format { get; init; }
|
||||
public string? Description { get; init; }
|
||||
public IEnumerable<KeyValuePair<string, string>>? Metadata { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request for previewing a template render.
|
||||
/// </summary>
|
||||
public sealed record TemplatePreviewRequest
|
||||
{
|
||||
public JsonNode? SamplePayload { get; init; }
|
||||
public bool? IncludeProvenance { get; init; }
|
||||
public string? ProvenanceBaseUrl { get; init; }
|
||||
public NotifyDeliveryFormat? FormatOverride { get; init; }
|
||||
}
|
||||
using System.Text.Json.Nodes;
|
||||
|
||||
namespace StellaOps.Notifier.WebService.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Request to preview a template rendering.
|
||||
/// </summary>
|
||||
public sealed record TemplatePreviewRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Template ID to preview (mutually exclusive with TemplateBody).
|
||||
/// </summary>
|
||||
public string? TemplateId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Raw template body to preview (mutually exclusive with TemplateId).
|
||||
/// </summary>
|
||||
public string? TemplateBody { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Sample event payload for rendering.
|
||||
/// </summary>
|
||||
public JsonObject? SamplePayload { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Event kind for context.
|
||||
/// </summary>
|
||||
public string? EventKind { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Sample attributes.
|
||||
/// </summary>
|
||||
public Dictionary<string, string>? SampleAttributes { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Output format override.
|
||||
/// </summary>
|
||||
public string? OutputFormat { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response from template preview.
|
||||
/// </summary>
|
||||
public sealed record TemplatePreviewResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// Rendered body content.
|
||||
/// </summary>
|
||||
public required string RenderedBody { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Rendered subject (if applicable).
|
||||
/// </summary>
|
||||
public string? RenderedSubject { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Content hash for deduplication.
|
||||
/// </summary>
|
||||
public required string BodyHash { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Output format used.
|
||||
/// </summary>
|
||||
public required string Format { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Validation warnings (if any).
|
||||
/// </summary>
|
||||
public List<string>? Warnings { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to create or update a template.
|
||||
/// </summary>
|
||||
public sealed record TemplateCreateRequest
|
||||
{
|
||||
public required string TemplateId { get; init; }
|
||||
public required string Key { get; init; }
|
||||
public required string ChannelType { get; init; }
|
||||
public required string Locale { get; init; }
|
||||
public required string Body { get; init; }
|
||||
public string? RenderMode { get; init; }
|
||||
public string? Format { get; init; }
|
||||
public string? Description { get; init; }
|
||||
public Dictionary<string, string>? Metadata { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Template response DTO.
|
||||
/// </summary>
|
||||
public sealed record TemplateResponse
|
||||
{
|
||||
public required string TemplateId { get; init; }
|
||||
public required string TenantId { get; init; }
|
||||
public required string Key { get; init; }
|
||||
public required string ChannelType { get; init; }
|
||||
public required string Locale { get; init; }
|
||||
public required string Body { get; init; }
|
||||
public required string RenderMode { get; init; }
|
||||
public required string Format { get; init; }
|
||||
public string? Description { get; init; }
|
||||
public Dictionary<string, string>? Metadata { get; init; }
|
||||
public string? CreatedBy { get; init; }
|
||||
public DateTimeOffset CreatedAt { get; init; }
|
||||
public string? UpdatedBy { get; init; }
|
||||
public DateTimeOffset UpdatedAt { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Template list query parameters.
|
||||
/// </summary>
|
||||
public sealed record TemplateListQuery
|
||||
{
|
||||
public string? KeyPrefix { get; init; }
|
||||
public string? ChannelType { get; init; }
|
||||
public string? Locale { get; init; }
|
||||
public int? Limit { get; init; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user