| name | ddd-aggregate-modeling |
| description | Guides aggregate modeling decisions for DDD services: aggregate root boundaries, child entity vs value object decisions, invariants, snapshot/primitives mapping, specification/criteria usage, and repository contract design. Invoked when the user asks to model or refactor domain entities and aggregate behavior.
|
| version | 1.0.0 |
| tags | ["backend","ddd","aggregates","domain-modeling"] |
| resources | ["aggregate-modeling-checklist.md"] |
| vendor_support | {"claude":"native","opencode":"native","copilot":"prompt-inject","codex":"prompt-inject","gemini":"prompt-inject"} |
DDD Aggregate Modeling Skill
Step 1 - Define Context and Ubiquitous Language
- Identify the bounded context owning the behavior.
- Name entities, value objects, and commands using domain language.
- Reject generic names (
Manager, Helper, Data) unless they are domain terms.
Step 2 - Choose the Aggregate Root
- Pick one root that owns consistency for the invariant set.
- Ensure external callers reference only root IDs, not child internals.
- Keep the aggregate small; if many transactions touch disjoint invariants, split aggregates.
Step 3 - Classify Members Correctly
Use this decision table:
| Case | Model as |
|---|
| Needs identity inside aggregate lifecycle | Child Entity |
| Structural equality only, immutable meaning | Value Object |
| External persistence detail | Adapter DTO / Row Model (not domain) |
Value object categories to model explicitly:
- constrained strings (
Email, Name, VatId)
- bounded numbers/ranges (
Lanes, Port, Quantity)
- enumerations (
Language, Role, SystemType)
Step 4 - Encode Invariants in Domain Behavior
- Validate on constructor/factory and on every mutating method.
- Keep aggregate state private; expose intent methods (
Create, Update, Delete, Verify).
- Guard temporal ordering when needed (ignore/reject stale updates deterministically).
- Keep authorization outside entities; enforce in application handlers.
Step 5 - Model Snapshot/Primitives Boundaries
- Add explicit primitives/snapshot structures for adapter boundaries.
- Use
ToPrimitives/Snapshot and FromPrimitives/RestoreFromSnapshot.
- Do not pass transport or ORM models directly into domain behavior.
- Keep mapping explicit; avoid reflection-based generic mappers.
Step 6 - Define Repository and Collection Contracts
- Define repository interfaces in domain/application, implementations in infrastructure.
- Split reader/writer contracts when beneficial.
- Return aggregates or domain collections, not adapter structs.
- Add domain collections when query semantics have domain meaning.
Step 7 - Add Criteria/Specification for Queries
- Represent query intent via criteria/specification objects.
- Keep filtering/sorting/pagination rules reusable and testable.
- Translate criteria to SQL/ORM query builders only in adapters.
Step 8 - Validate with the Checklist
Run the checklist from aggregate-modeling-checklist.md before finalizing model changes.