Bounded Context: Approvals
Aggregate Root: ApprovalRequest
Module: Ums.Domain.Approvals.ApprovalRequest
Status: Production
The ApprovalRequest aggregate represents a concrete runtime execution of an approval process. When a user requests a high-privilege administrative action (like a profile promotion or security configuration modification), UMS instantiates an ApprovalRequest linked to a specific ApprovalWorkflow to track the state, approvals, rejections, and audit details of that operational decision.
Pending to Approved or Rejected through authenticated signatures.ApprovalRequest is the aggregate root. All state transitions (Approving, Rejecting) must flow through it to ensure constraints.
Pending status.Pending to Approved or Rejected. Once a request has been finalized (Approved or Rejected), its status is permanently locked and cannot be edited.WorkflowId and TargetUserId.| Entity / VO | Type | Ownership |
|—|—|—|
| ApprovalRequestId | Value Object | Guid-based aggregate root identifier |
| ApprovalStatus | Enum | PENDING · APPROVED · REJECTED |
| AuditValueObject | Value Object | Tracks creation and modification metadata |
| Event | Trigger |
|—|—|
| ApprovalRequestCreatedEvent | A new approval request is registered and set to Pending |
| ApprovalRequestApprovedEvent | The request is marked as Approved, triggering downstream activations |
| ApprovalRequestRejectedEvent | The request is marked as Rejected, aborting downstream activations |
| Command | Description |
|—|—|
| CreateApprovalRequestCommand | Instantiate an approval request instance for a user action |
| ApproveRequestCommand | Approve a pending request with the authorized actor ID |
| RejectRequestCommand | Reject a pending request and cancel the target elevation |
IApprovalRequestRepository — Manages request lifecycles.TenantId (inherited via the target workflow and user configurations).ApprovalRequest (Aggregate Root)
└── Props: ApprovalRequestProps
├── Id: ApprovalRequestId
├── WorkflowId: ApprovalWorkflowId
├── TargetUserId: UserId
├── TargetProfileId?: ProfileId
├── Status: ApprovalStatus
└── Audit: AuditValueObject
classDiagram
direction LR
class ApprovalRequest {
+Guid Id
+Guid WorkflowId
+Guid TargetUserId
+Guid? TargetProfileId
+ApprovalStatus Status
+Create()
+Approve()
+Reject()
}
class ApprovalStatus {
<<enumeration>>
PENDING
APPROVED
REJECTED
}
ApprovalRequest "1" *-- "1" ApprovalStatus
sequenceDiagram
participant U as Requester
participant H as RequestHandler
participant R as IApprovalRequestRepository
participant A as ApprovalRequest (AR)
participant E as EventPublisher
U->>H: CreateApprovalRequestCommand(workflowId, targetUserId, targetProfileId)
H->>A: ApprovalRequest.Create(workflowId, targetUserId, targetProfileId, actorId)
A->>A: Set Status = Pending
A->>A: Raise ApprovalRequestCreatedEvent
H->>R: Save(request)
R-->>H: ok
H-->>U: RequestId
Note over U,A: Administrative Review
Admin->>H: ApproveRequestCommand(requestId)
H->>R: GetById(requestId)
R-->>H: ApprovalRequest (AR)
H->>A: Approve(adminActorId)
A->>A: Transition Status -> Approved
A->>A: Raise ApprovalRequestApprovedEvent
H->>R: Save(request)
R-->>H: ok
H->>E: Publish ApprovalRequestApprovedEvent
erDiagram
APPROVAL_WORKFLOW ||--o{ APPROVAL_REQUEST : "routes"
USER_ACCOUNT ||--o{ APPROVAL_REQUEST : "targets"
PROFILE ||--o{ APPROVAL_REQUEST : "elevates-to"
APPROVAL_REQUEST {
uniqueidentifier RequestId PK
uniqueidentifier WorkflowId FK
uniqueidentifier TargetUserId FK
uniqueidentifier TargetProfileId FK "Nullable"
nvarchar Status "PENDING-APPROVED-REJECTED"
datetime2 UpdatedAt
uniqueidentifier UpdatedBy
}
Approvals context. Directly targets user identifiers from Identity and profiles from Authorization.IGA context.CreateApprovalRequestCommand -> Inputs: WorkflowId, TargetUserId, TargetProfileId? -> Returns: GuidApproveRequestCommand -> Inputs: RequestId -> Returns: voidRejectRequestCommand -> Inputs: RequestId -> Returns: voidRequestId, with non-clustered composite index on TargetUserId, Status.