UMS-specific: No Evolith upstream. The
ParentResourceId+DomainMethodresource hierarchy is specific to UMS’s authorization domain model. The generic DDD base class pattern is covered by Evolith ADR-0071.
Status: Accepted
Date: 2026-06-03
Decision Owner: Architecture
Related:
The authorization system models access control at the domain level through DomainResource objects. Initially only Aggregate and Entity types were supported. Domain-Driven Design also defines DomainMethods — operations exposed by an Aggregate that carry business logic and require explicit permission grants (e.g. ResetPassword(), ApproveOrder()).
Three design questions arose:
DomainResource?ParentResourceId column?DomainResourceType valueDomainMethod is added as a third variant of the existing DomainResourceType enum (DomainMethod = new(3, ...)), not as a separate entity. A DomainResource row can now be one of Aggregate(1) | Entity(2) | DomainMethod(3).
| Option | Rejected reason |
|---|---|
Separate DomainMethod entity |
Duplicates query paths and complicates the auth graph builder |
| Custom action on the Aggregate | Loses the addressability needed by the auth graph |
| Extension via join table | Over-engineered for a two-level hierarchy |
ParentResourceId on the same tableA nullable Guid? ParentResourceId column on DOMAIN_RESOURCE provides the parent reference. This avoids a join table while keeping the hierarchy queryable in a single read.
Constraint rules enforced by the SystemSuite aggregate:
DomainMethod must have a non-null ParentResourceId.DomainMethod (prevents nesting beyond one level).SystemSuite.Entity may optionally reference a parent Aggregate; this is not enforced as a hard rule.All hierarchy invariants are enforced inside SystemSuite.AddDomainResource(moduleId, parentResourceId, type, ...). The application layer passes the resolved parentResourceId and the aggregate validates it. This keeps the rules close to the data and testable without a database.
The auth graph builder (IAuthorizationGraphBuilder) includes DomainMethod nodes as addressable permission targets, linked to their parent Aggregate or Entity. Permission templates can now grant access to specific domain operations, not just whole resources.
Aggregate and Entity rows have ParentResourceId = null; no migration data change required.