using StellaOps.JobEngine.Core.Domain; using StellaOps.JobEngine.Infrastructure.Repositories; namespace StellaOps.JobEngine.WebService.Contracts; // ===== Audit Contracts ===== /// /// Response for an audit entry. /// public sealed record AuditEntryResponse( Guid EntryId, string TenantId, string EventType, string ResourceType, Guid ResourceId, string ActorId, string ActorType, string? ActorIp, string? UserAgent, string? HttpMethod, string? RequestPath, string? OldState, string? NewState, string Description, string? CorrelationId, string? PreviousEntryHash, string ContentHash, long SequenceNumber, DateTimeOffset OccurredAt, string? Metadata) { public static AuditEntryResponse FromDomain(AuditEntry entry) => new( EntryId: entry.EntryId, TenantId: entry.TenantId, EventType: entry.EventType.ToString(), ResourceType: entry.ResourceType, ResourceId: entry.ResourceId, ActorId: entry.ActorId, ActorType: entry.ActorType.ToString(), ActorIp: entry.ActorIp, UserAgent: entry.UserAgent, HttpMethod: entry.HttpMethod, RequestPath: entry.RequestPath, OldState: entry.OldState, NewState: entry.NewState, Description: entry.Description, CorrelationId: entry.CorrelationId, PreviousEntryHash: entry.PreviousEntryHash, ContentHash: entry.ContentHash, SequenceNumber: entry.SequenceNumber, OccurredAt: entry.OccurredAt, Metadata: entry.Metadata); } /// /// List response for audit entries. /// public sealed record AuditEntryListResponse( IReadOnlyList Entries, string? NextCursor); /// /// Response for audit summary. /// public sealed record AuditSummaryResponse( long TotalEntries, long EntriesSince, long EventTypes, long UniqueActors, long UniqueResources, DateTimeOffset? EarliestEntry, DateTimeOffset? LatestEntry) { public static AuditSummaryResponse FromDomain(AuditSummary summary) => new( TotalEntries: summary.TotalEntries, EntriesSince: summary.EntriesSince, EventTypes: summary.EventTypes, UniqueActors: summary.UniqueActors, UniqueResources: summary.UniqueResources, EarliestEntry: summary.EarliestEntry, LatestEntry: summary.LatestEntry); } /// /// Response for chain verification. /// public sealed record ChainVerificationResponse( bool IsValid, Guid? InvalidEntryId, long? InvalidSequence, string? ErrorMessage) { public static ChainVerificationResponse FromDomain(ChainVerificationResult result) => new( IsValid: result.IsValid, InvalidEntryId: result.InvalidEntryId, InvalidSequence: result.InvalidSequence, ErrorMessage: result.ErrorMessage); } // ===== Ledger Contracts ===== /// /// Response for a ledger entry. /// public sealed record LedgerEntryResponse( Guid LedgerId, string TenantId, Guid RunId, Guid SourceId, string RunType, string FinalStatus, int TotalJobs, int SucceededJobs, int FailedJobs, DateTimeOffset RunCreatedAt, DateTimeOffset? RunStartedAt, DateTimeOffset RunCompletedAt, long ExecutionDurationMs, string InitiatedBy, string InputDigest, string OutputDigest, long SequenceNumber, string? PreviousEntryHash, string ContentHash, DateTimeOffset LedgerCreatedAt, string? CorrelationId) { public static LedgerEntryResponse FromDomain(RunLedgerEntry entry) => new( LedgerId: entry.LedgerId, TenantId: entry.TenantId, RunId: entry.RunId, SourceId: entry.SourceId, RunType: entry.RunType, FinalStatus: entry.FinalStatus.ToString(), TotalJobs: entry.TotalJobs, SucceededJobs: entry.SucceededJobs, FailedJobs: entry.FailedJobs, RunCreatedAt: entry.RunCreatedAt, RunStartedAt: entry.RunStartedAt, RunCompletedAt: entry.RunCompletedAt, ExecutionDurationMs: (long)entry.ExecutionDuration.TotalMilliseconds, InitiatedBy: entry.InitiatedBy, InputDigest: entry.InputDigest, OutputDigest: entry.OutputDigest, SequenceNumber: entry.SequenceNumber, PreviousEntryHash: entry.PreviousEntryHash, ContentHash: entry.ContentHash, LedgerCreatedAt: entry.LedgerCreatedAt, CorrelationId: entry.CorrelationId); } /// /// List response for ledger entries. /// public sealed record LedgerEntryListResponse( IReadOnlyList Entries, string? NextCursor); /// /// Response for ledger summary. /// public sealed record LedgerSummaryResponse( long TotalEntries, long EntriesSince, long TotalRuns, long SuccessfulRuns, long FailedRuns, long TotalJobs, long UniqueSources, long UniqueRunTypes, DateTimeOffset? EarliestEntry, DateTimeOffset? LatestEntry) { public static LedgerSummaryResponse FromDomain(LedgerSummary summary) => new( TotalEntries: summary.TotalEntries, EntriesSince: summary.EntriesSince, TotalRuns: summary.TotalRuns, SuccessfulRuns: summary.SuccessfulRuns, FailedRuns: summary.FailedRuns, TotalJobs: summary.TotalJobs, UniqueSources: summary.UniqueSources, UniqueRunTypes: summary.UniqueRunTypes, EarliestEntry: summary.EarliestEntry, LatestEntry: summary.LatestEntry); } // ===== Export Contracts ===== /// /// Request to create a ledger export. /// public sealed record CreateLedgerExportRequest( string Format, DateTimeOffset? StartTime, DateTimeOffset? EndTime, string? RunTypeFilter, Guid? SourceIdFilter); /// /// Response for a ledger export. /// public sealed record LedgerExportResponse( Guid ExportId, string TenantId, string Status, string Format, DateTimeOffset? StartTime, DateTimeOffset? EndTime, string? RunTypeFilter, Guid? SourceIdFilter, int EntryCount, string? OutputUri, string? OutputDigest, long? OutputSizeBytes, string RequestedBy, DateTimeOffset RequestedAt, DateTimeOffset? StartedAt, DateTimeOffset? CompletedAt, string? ErrorMessage) { public static LedgerExportResponse FromDomain(LedgerExport export) => new( ExportId: export.ExportId, TenantId: export.TenantId, Status: export.Status.ToString(), Format: export.Format, StartTime: export.StartTime, EndTime: export.EndTime, RunTypeFilter: export.RunTypeFilter, SourceIdFilter: export.SourceIdFilter, EntryCount: export.EntryCount, OutputUri: export.OutputUri, OutputDigest: export.OutputDigest, OutputSizeBytes: export.OutputSizeBytes, RequestedBy: export.RequestedBy, RequestedAt: export.RequestedAt, StartedAt: export.StartedAt, CompletedAt: export.CompletedAt, ErrorMessage: export.ErrorMessage); } /// /// List response for ledger exports. /// public sealed record LedgerExportListResponse( IReadOnlyList Exports, string? NextCursor); // ===== Manifest Contracts ===== /// /// Response for a signed manifest. /// public sealed record ManifestResponse( Guid ManifestId, string SchemaVersion, string TenantId, string ProvenanceType, Guid SubjectId, string PayloadDigest, string SignatureAlgorithm, bool IsSigned, bool IsExpired, string KeyId, DateTimeOffset CreatedAt, DateTimeOffset? ExpiresAt) { public static ManifestResponse FromDomain(SignedManifest manifest) => new( ManifestId: manifest.ManifestId, SchemaVersion: manifest.SchemaVersion, TenantId: manifest.TenantId, ProvenanceType: manifest.ProvenanceType.ToString(), SubjectId: manifest.SubjectId, PayloadDigest: manifest.PayloadDigest, SignatureAlgorithm: manifest.SignatureAlgorithm, IsSigned: manifest.IsSigned, IsExpired: manifest.IsExpired, KeyId: manifest.KeyId, CreatedAt: manifest.CreatedAt, ExpiresAt: manifest.ExpiresAt); } /// /// Response with full manifest details including statements and artifacts. /// public sealed record ManifestDetailResponse( Guid ManifestId, string SchemaVersion, string TenantId, string ProvenanceType, Guid SubjectId, string Statements, string Artifacts, string Materials, string? BuildInfo, string PayloadDigest, string SignatureAlgorithm, string Signature, string KeyId, DateTimeOffset CreatedAt, DateTimeOffset? ExpiresAt, string? Metadata) { public static ManifestDetailResponse FromDomain(SignedManifest manifest) => new( ManifestId: manifest.ManifestId, SchemaVersion: manifest.SchemaVersion, TenantId: manifest.TenantId, ProvenanceType: manifest.ProvenanceType.ToString(), SubjectId: manifest.SubjectId, Statements: manifest.Statements, Artifacts: manifest.Artifacts, Materials: manifest.Materials, BuildInfo: manifest.BuildInfo, PayloadDigest: manifest.PayloadDigest, SignatureAlgorithm: manifest.SignatureAlgorithm, Signature: manifest.Signature, KeyId: manifest.KeyId, CreatedAt: manifest.CreatedAt, ExpiresAt: manifest.ExpiresAt, Metadata: manifest.Metadata); } /// /// List response for manifests. /// public sealed record ManifestListResponse( IReadOnlyList Manifests, string? NextCursor); /// /// Response for manifest verification. /// public sealed record ManifestVerificationResponse( Guid ManifestId, bool PayloadIntegrityValid, bool IsExpired, bool IsSigned, string? ValidationError);