a2e742c78d
- 3 API endpoints: POST /approvals, GET /approvals, POST /approvals/{id}/approve
- State machine: DRAFT → PROPOSED → APPROVED → ACTIVE
- RBAC enforcement: Maker ≠ Checker separation of duties
- Evidence linkage: PBO/DSR/OOS artifact URLs stored
- Schema: Append-only events with correlation_id
- Tests: 5+ unit/integration scenarios
- Documentation: Full API contracts + compliance procedures
- AGENTS.md v16.0 13/13 compliance ✅
Closes workstream H (Phase 2 implementation).
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
110 lines
3.4 KiB
C#
110 lines
3.4 KiB
C#
namespace KArtSell.Modules.ModelOperations.ApprovalWorkflow;
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
|
|
public class ApprovalProposal
|
|
{
|
|
public Guid Id { get; set; }
|
|
public Guid ModelId { get; set; }
|
|
public ApprovalStatus Status { get; set; }
|
|
public string CreatedBy { get; set; } = null!;
|
|
public DateTimeOffset CreatedAt { get; set; }
|
|
public string Justification { get; set; } = null!;
|
|
public DateOnly EffectiveAt { get; set; }
|
|
|
|
public DateTimeOffset? ProposedAt { get; set; }
|
|
public string? ApprovedBy { get; set; }
|
|
public DateTimeOffset? ApprovedAt { get; set; }
|
|
public string? ApprovalNotes { get; set; }
|
|
|
|
public string? ActivatedBy { get; set; }
|
|
public DateTimeOffset? ActivatedAt { get; set; }
|
|
|
|
public DateTimeOffset PublishedAt { get; set; }
|
|
public int Revision { get; set; }
|
|
public Guid CorrelationId { get; set; }
|
|
|
|
public List<ApprovalEvidence> Evidence { get; set; } = [];
|
|
public List<ApprovalEvent> Events { get; set; } = [];
|
|
|
|
public bool CanBeProposed => Status == ApprovalStatus.Draft && CreatedBy is not null;
|
|
public bool CanBeApproved => Status == ApprovalStatus.Proposed;
|
|
public bool CanBeActivated => Status == ApprovalStatus.Approved;
|
|
}
|
|
|
|
public enum ApprovalStatus
|
|
{
|
|
Draft,
|
|
Proposed,
|
|
Approved,
|
|
Active,
|
|
Rejected
|
|
}
|
|
|
|
public class ApprovalEvidence
|
|
{
|
|
public Guid Id { get; set; }
|
|
public Guid ApprovalProposalId { get; set; }
|
|
public string EvidenceType { get; set; } = null!;
|
|
public string EvidenceUrl { get; set; } = null!;
|
|
public string? ReviewerComment { get; set; }
|
|
public DateTimeOffset PublishedAt { get; set; }
|
|
public Guid CorrelationId { get; set; }
|
|
}
|
|
|
|
public class ApprovalEvent
|
|
{
|
|
public Guid Id { get; set; }
|
|
public Guid ApprovalProposalId { get; set; }
|
|
public string EventType { get; set; } = null!;
|
|
public string ActorEmail { get; set; } = null!;
|
|
public DateTimeOffset EventAt { get; set; }
|
|
public Dictionary<string, object>? Details { get; set; }
|
|
public DateTimeOffset PublishedAt { get; set; }
|
|
public Guid CorrelationId { get; set; }
|
|
}
|
|
|
|
public class CreateApprovalProposalRequest
|
|
{
|
|
public Guid ModelId { get; set; }
|
|
public DateOnly EffectiveAt { get; set; }
|
|
public string Justification { get; set; } = null!;
|
|
}
|
|
|
|
public class ApproveApprovalRequest
|
|
{
|
|
public string ApprovalNotes { get; set; } = null!;
|
|
public List<EvidenceItem> Evidence { get; set; } = [];
|
|
}
|
|
|
|
public class EvidenceItem
|
|
{
|
|
public string Type { get; set; } = null!;
|
|
public string Url { get; set; } = null!;
|
|
public string? Comment { get; set; }
|
|
}
|
|
|
|
public class ApprovalProposalResponse
|
|
{
|
|
public Guid Id { get; set; }
|
|
public Guid ModelId { get; set; }
|
|
public string Status { get; set; } = null!;
|
|
public string CreatedBy { get; set; } = null!;
|
|
public DateTimeOffset CreatedAt { get; set; }
|
|
public string Justification { get; set; } = null!;
|
|
public DateOnly EffectiveAt { get; set; }
|
|
public string? ApprovedBy { get; set; }
|
|
public DateTimeOffset? ApprovedAt { get; set; }
|
|
public string? ApprovalNotes { get; set; }
|
|
public List<ApprovalEvidenceResponse> Evidence { get; set; } = [];
|
|
}
|
|
|
|
public class ApprovalEvidenceResponse
|
|
{
|
|
public Guid Id { get; set; }
|
|
public string EvidenceType { get; set; } = null!;
|
|
public string EvidenceUrl { get; set; } = null!;
|
|
public string? ReviewerComment { get; set; }
|
|
}
|