Bounded Context: Approvals
Aggregate Root: DocumentType
Module: Ums.Domain.Approvals.DocumentType
Status: Production
The DocumentType aggregate governs the classifications, rules, and policy schemas for user-uploaded documents (e.g. Passports, Certification documents). It declares critical thresholds (Criticity), binds recurring notification intervals (NotificationRule entities), and configures proactive security enforcement actions (EnforcementPolicy entity) to run automatically when a mandatory document expires or is deleted. NotificationRule specifies how many days before expiration a user must be alerted, and which communication channels are authorized.
DocumentType is the aggregate root. Defining enforcement actions or configuring notification alerts (NotificationRule) must go through it to enforce invariants. NotificationRule is an owned entity and cannot exist or undergo state transitions outside the lifecycle constraints of DocumentType.
DocumentType must possess a unique Code within its TenantId namespace.DaysBefore) in the owned NotificationRules must be unique across the rules list.DocumentType is set to Critical, it must have exactly one active EnforcementPolicy defined to secure system compliance.EnforcementPolicy is permitted per DocumentType.BlockUser or RestrictProfile enforcement actions.NotificationRule.DaysBefore must be a positive integer strictly greater than zero.NotificationRule.Channels collection must contain at least one valid notification channel (Email, SMS, WebPortal) and cannot be null or empty.NotificationRule is fully controlled by the parent DocumentType.| Entity / VO | Type | Ownership |
|—|—|—|
| DocumentTypeId | Value Object | Guid-based aggregate root identifier |
| DocumentCriticity | Enum | LOW · MEDIUM · HIGH · CRITICAL |
| NotificationRule | Entity | Owned |
| NotificationRuleId | Value Object | Entity unique identifier |
| NotificationChannel | Enum | EMAIL · SMS · IN_APP · WEB_PUSH |
| EnforcementPolicy | Entity | Owned child detailing grace periods and blocks |
| AuditValueObject | Value Object | Tracks creation and modification metadata |
| Code | Value Object | Alpha-numeric camelCase notification type identifier |
| Event | Trigger |
|—|—|
| DocumentTypeRegisteredEvent | A new document category is successfully registered |
| NotificationRuleConfiguredEvent | An expiration pre-alert rule is configured |
| NotificationRuleRemovedEvent | A pre-alert rule is removed |
| EnforcementPolicyDefinedEvent | An enforcement block is defined |
| EnforcementPolicyUpdatedEvent | The enforcement parameters are updated |
| Command | Description |
|—|—|
| CreateDocumentTypeCommand | Register a new document type with default parameters |
| ConfigureNotificationRuleCommand | Configure a new alert threshold and channels |
| RemoveNotificationRuleCommand | Remove an existing notification pre-alert rule |
| DefineEnforcementPolicyCommand | Add a blocking or profile downgrade enforcement policy |
| UpdateEnforcementPolicyCommand | Modify the actions or grace periods of a policy |
IDocumentTypeRepository — Persists classification schemas.TenantId to prevent multi-tenant configuration cross-overs.DocumentType (Aggregate Root)
├── Props: DocumentTypeProps
│ ├── Id: DocumentTypeId
│ ├── TenantId: TenantId
│ ├── Code: Code
│ ├── Name: Name
│ ├── Description: Description
│ ├── Criticity: DocumentCriticity
│ └── Audit: AuditValueObject
├── Children
│ └── IReadOnlyCollection<NotificationRule>
│ └── Props: NotificationRuleProps
│ ├── Id: NotificationRuleId
│ ├── DaysBefore: int
│ ├── Channels: NotificationChannel[]
│ ├── Code: Code
│ └── Description: Description
└── Child (Nullable)
└── EnforcementPolicy
classDiagram
direction LR
class DocumentType {
+Guid Id
+Guid TenantId
+Code Code
+Name Name
+Description Description
+DocumentCriticity Criticity
+List~NotificationRule~ NotificationRules
+EnforcementPolicy EnforcementPolicy
+Create()
+ConfigureNotificationRule()
+RemoveNotificationRule()
+DefineEnforcementPolicy()
}
class DocumentCriticity {
<<enumeration>>
LOW
MEDIUM
HIGH
CRITICAL
}
class NotificationRule {
+Guid Id
+int DaysBefore
+NotificationChannel[] Channels
+Code Code
+Description Description
+Create()
}
class NotificationChannel {
<<enumeration>>
EMAIL
SMS
IN_APP
WEB_PUSH
}
class EnforcementPolicy {
+Guid Id
+AccessEnforcementAction ActionOnExpiration
+int? GracePeriodDays
}
DocumentType "1" *-- "1" DocumentCriticity
DocumentType "1" *-- "0..*" NotificationRule
NotificationRule "1" *-- "1..*" NotificationChannel
DocumentType "1" *-- "0..1" EnforcementPolicy
sequenceDiagram
participant C as TenantAdmin
participant H as DefinePolicyHandler
participant R as IDocumentTypeRepository
participant D as DocumentType (AR)
C->>H: DefineEnforcementPolicyCommand(docTypeId, action, graceDays)
H->>R: GetById(docTypeId)
R-->>H: DocumentType (AR)
H->>D: DefineEnforcementPolicy(action, graceDays, actorId)
D->>D: Guard INV-DT4 (non-critical restrictions)
D->>D: Guard INV-DT3 (single policy limit)
D->>D: Raise EnforcementPolicyDefinedEvent
H->>R: Save(docType)
R-->>H: ok
H-->>C: ok
erDiagram
TENANT ||--o{ DOCUMENT_TYPE : "configures"
DOCUMENT_TYPE ||--o{ NOTIFICATION_RULE : "defines"
DOCUMENT_TYPE ||--o| ENFORCEMENT_POLICY : "restricts"
DOCUMENT_TYPE {
uniqueidentifier DocumentTypeId PK
uniqueidentifier TenantId FK
nvarchar Code "Unique per TenantId"
nvarchar Name
nvarchar Description
nvarchar Criticity "LOW-MEDIUM-HIGH-CRITICAL"
datetime2 UpdatedAt
uniqueidentifier UpdatedBy
}
NOTIFICATION_RULE {
uniqueidentifier RuleId PK
uniqueidentifier DocumentTypeId FK
int DaysBefore "Unique per DocumentTypeId"
nvarchar ChannelsJson "Serialized channels array"
nvarchar Code
nvarchar Description
}
ENFORCEMENT_POLICY {
uniqueidentifier PolicyId PK
uniqueidentifier DocumentTypeId FK
nvarchar ActionOnExpiration "BlockUser-RestrictProfile-Notify"
int GracePeriodDays "Nullable"
}
TenantId. All verification routing queries enforce isolation limits.NOTIFICATION_RULE is scoped via its parent aggregate DocumentType. Inherits all platform multi-tenant database filtering constraints.Identity (validating tenant registers).UserDocument to check alert thresholds, and AccessEnforcementPolicy during compliance check passes. Alerts triggered are processed by background compliance runners to notify users from the Identity context.CreateDocumentTypeCommand -> Inputs: TenantId, Code, Name, Description, Criticity -> Returns: GuidConfigureNotificationRuleCommand -> Inputs: DocumentTypeId, DaysBefore, Channels, Code, Description -> Returns: voidRemoveNotificationRuleCommand -> Inputs: DocumentTypeId, RuleId -> Returns: voidDefineEnforcementPolicyCommand -> Inputs: DocumentTypeId, Action, GracePeriodDays? -> Returns: voidTenantId, Code.DocumentTypeId, DaysBefore to secure threshold uniqueness.DOCUMENT_TYPE database transaction.Tenant:Admin roles. Rule configurations are inherited from the parent DocumentType.NotificationRule and EnforcementPolicy models as child elements inside the DocumentType aggregate protects domain boundaries from split constraints.ChannelsJson) within a single database column guarantees database flexibility without massive schema join overheads.