| name | ddd |
| description | Domain-Driven Design. Bounded contexts, context mapping, ubiquitous language, aggregates, entities, value objects, domain events, repositories, event storming. |
DDD — Domain-Driven Design
Activate When
- User invokes
/godmode:ddd
- User says "model the domain", "define bounded contexts", "design aggregates"
- User says "event storming", "domain events", "ubiquitous language"
- When
/godmode:architect identifies that domain boundaries need clarification
- When
/godmode:pattern detects an anemic domain model anti-pattern
- When business logic complexity outgrows simple CRUD operations
- When multiple teams need clear ownership boundaries
Workflow
Step 1: Domain Discovery
Understand the business domain before modeling:
DOMAIN CONTEXT:
Business: <what does the business do?>
Core domain: <the thing that differentiates this business>
Supporting domains: <necessary but not differentiating>
Generic domains: <commodity — auth, billing, email>
Key stakeholders: <who are the domain experts?>
Known pain points: <where does the current model break down?>
Identify the core domain. This is where you invest the most modeling effort. Generic domains get off-the-shelf solutions. Supporting domains get simple implementations. Only the core domain gets full DDD treatment.
Step 2: Ubiquitous Language
Establish the shared vocabulary between developers and domain experts:
UBIQUITOUS LANGUAGE — <Domain Name>:
| Term | Definition |
|--|--|
| <Term 1> | <Precise definition as understood by domain experts |
| | AND developers. No ambiguity.> |
| <Term 2> | <Definition. Note: "Order" in the Sales context |
| | means something different than in Fulfillment.> |
| <Term 3> | <Definition. Include what it is NOT if ambiguous.> |
LANGUAGE RULES:
- These terms are used in code (class names, method names, variable names)
- These terms are used in conversations with stakeholders
- If a term means different things in different contexts, it belongs in
different bounded contexts with different definitions
- When a new term emerges, add it to this glossary immediately
Step 3: Event Storming
Facilitate a structured event storming session to discover domain events, commands, aggregates, and boundaries:
Phase 1: Chaotic Exploration (Domain Events)
List every domain event — things that happened in the past tense:
DOMAIN EVENTS (unordered):
🟧 OrderPlaced
🟧 PaymentReceived
🟧 PaymentFailed
🟧 InventoryReserved
🟧 InventoryOutOfStock
🟧 OrderShipped
🟧 OrderDelivered
🟧 OrderCancelled
🟧 RefundIssued
🟧 CustomerRegistered
🟧 PriceChanged
🟧 PromotionApplied
Phase 2: Timeline (Temporal Ordering)
Arrange events in chronological order:
TIMELINE:
CustomerRegistered → OrderPlaced → InventoryReserved → PaymentReceived
→ OrderShipped → OrderDelivered
ALTERNATE FLOWS:
OrderPlaced → InventoryOutOfStock → OrderCancelled → RefundIssued
OrderPlaced → InventoryReserved → PaymentFailed → OrderCancelled
OrderShipped → OrderDelivered → RefundIssued (return)
Phase 3: Commands & Actors
Identify what triggers each event:
COMMANDS AND TRIGGERS:
| Command | Actor | Produces Event |
|--|--|--|
| PlaceOrder | Customer | OrderPlaced |
| ProcessPayment | Payment Gateway | PaymentReceived |
| ReserveInventory | System (auto) | InventoryReserved |
| ShipOrder | Warehouse Staff | OrderShipped |
| CancelOrder | Customer/System | OrderCancelled |
| IssueRefund | Support Agent | RefundIssued |
Phase 4: Aggregates
Group events around the entities that own them:
AGGREGATES:
<<Aggregate>> Order
Commands: PlaceOrder, CancelOrder
Events: OrderPlaced, OrderCancelled,
OrderShipped, OrderDelivered
Invariants:
- Order total stays > 0
- Cannot cancel a delivered order
- Cannot ship without payment
<<Aggregate>> Inventory
Commands: ReserveInventory, ReleaseInventory
Phase 5: Bounded Context Discovery
Draw boundaries around aggregates that share a ubiquitous language:
BOUNDED CONTEXTS (list each with its aggregates and ubiquitous language):
[ORDERING CONTEXT]
Aggregates: Order, Cart
"Order" here means: items a customer wants to buy
[FULFILLMENT CONTEXT]
Aggregates: Shipment, Inventory
"Order" here means: items to pick and ship from warehouse
Step 4: Context Mapping
Define relationships between bounded contexts:
CONTEXT MAP:
Ordering ──── Partnership ────► Fulfillment
│ │ │ │
Customer/ Customer/
Supplier Supplier
│ │ │ │
▼ ▼
Billing ──── Conformist ────► Payment Gateway (External)
Identity ──── Open Host Service ────► All Contexts
(Published Language)
Reporting ──── ACL ────► Legacy ERP System
Step 5: Tactical Design — Aggregate Internals
For each aggregate in the core domain, design the internal structure:
AGGREGATE DESIGN — <Aggregate Name>:
Root Entity: <AggregateRootName>
ID: <type and generation strategy>
State: <key properties>
Invariants:
1. <business rule that must always be true>
2. <business rule that must always be true>
Entities (within this aggregate):
- <EntityName>: <purpose, ID type, key properties>
- <EntityName>: <purpose, ID type, key properties>
Value Objects:
- <ValueObjectName>: <immutable, defined by attributes not identity>
Aggregate Design Rules
AGGREGATE BOUNDARY RULES:
1. CONSISTENCY BOUNDARY: Everything inside an aggregate is immediately
consistent. Cross-aggregate operations are eventually consistent.
2. TRANSACTION BOUNDARY: One aggregate = one transaction. Never modify
two aggregates in the same transaction.
3. SIZE RULE: Keep aggregates small. If an aggregate has more than
3-4 entities, split it.
4. REFERENCE RULE: Aggregates reference each other by ID only, never
by direct object reference.
5. CASCADE RULE: External code references only the aggregate root.
Internal entities are accessed through the root.
Step 6: Domain Event Catalog
Document all domain events for cross-context communication:
DOMAIN EVENT CATALOG:
| Event | Source | Payload |
| | Context | |
| OrderPlaced | Ordering | orderId, customerId, items[], |
| | | totalAmount, placedAt |
| PaymentReceived | Billing | paymentId, orderId, amount, |
| | | method, paidAt |
| InventoryReserved | Fulfillment | reservationId, orderId, items[], |
| | | warehouseId, reservedAt |
| OrderShipped | Fulfillment | shipmentId, orderId, trackingNo, |
Step 7: Implementation Scaffold
Generate the directory structure and skeleton code:
DIRECTORY STRUCTURE:
src/
├── <context-name>/
│ ├── domain/
│ │ ├── model/
│ │ │ ├── <AggregateRoot>.ts # Aggregate root entity
│ │ │ ├── <Entity>.ts # Child entities
│ │ │ └── <ValueObject>.ts # Value objects
│ │ ├── events/
│ │ │ └── <DomainEvent>.ts # Domain events
│ │ ├── commands/
│ │ │ └── <Command>.ts # Commands
│ │ ├── repositories/
│ │ │ └── <Repository>.ts # Repository interface (port)
│ │ └── services/
Step 8: Artifacts & Transition
- Save domain model:
docs/domain/<context>-domain-model.md
- Save event catalog:
docs/domain/event-catalog.md
- Save context map:
docs/domain/context-map.md
- Save ubiquitous language:
docs/domain/ubiquitous-language.md
- Commit:
"ddd: <context> — bounded contexts, aggregates, and event catalog"
- Suggest next steps:
- "Domain modeled. Run
/godmode:architect to select the architecture for this domain."
- "Domain modeled. Run
/godmode:plan to decompose aggregate implementation into tasks."
- "Domain modeled. Run
/godmode:pattern to select implementation patterns for each aggregate."
Key Behaviors
Never ask to continue. Loop autonomously until done.
grep -rn "class.*Aggregate\|class.*Entity\|class.*ValueObject" src/ --include="*.ts" --include="*.py"
grep -rn "Event\|EventHandler\|DomainEvent" src/ --include="*.ts" --include="*.py" | head -20
IF aggregate has > 4 entities: split into smaller aggregates.
WHEN same term means different things in 2 contexts: correct — separate glossary entries.
IF domain events > 50: group by context, verify no cross-context coupling.
- Start with events, not entities. Events reveal behavior.
- Ubiquitous language non-negotiable. Code = domain language.
- Bounded contexts are social. Follow team/language boundaries.
- Aggregates are small. Max 3-4 entities per aggregate.
- Reference by ID across aggregates. Never direct object refs.
- Eventual consistency between contexts. Use domain events.
- Not everything needs DDD. CRUD and reports don't benefit.
- Event storming is collaborative. Structured thinking catches errors.
On failure: revert with git reset --hard HEAD~1.
Flags & Options
| Flag | Description |
|---|
| (none) | Full DDD session: discovery, event storming, contexts, tactical design |
--strategic | Strategic design only (bounded contexts, context map, ubiquitous language) |
--tactical | Tactical design only (aggregates, entities, value objects, events) |
Quality Targets
- Cross-aggregate refs: <1 direct reference
- Command latency: <500ms per aggregate
- Aggregate size: <100 entities maximum
HARD RULES
- NEVER start with the database schema. Model the domain first. Persistence is derived.
- NEVER create a God Aggregate — if an aggregate has more than 3-4 entities, split it.
- NEVER share domain objects across bounded contexts. Each context owns its model.
- NEVER hold direct object references across aggregate boundaries. Use IDs only.
- NEVER force immediate consistency across aggregates — use domain events and eventual consistency.
- ALWAYS define ubiquitous language before writing code — code speaks the domain language.
- ALWAYS start with events, not entities — events reveal real behavior, entities emerge from grouping events.
- git commit BEFORE verify — commit domain model artifacts, then validate against DDD principles.
- TSV logging — log every DDD session:
timestamp domain bounded_contexts aggregates events value_objects verdict
Auto-Detection
AUTO-DETECT:
1. Scan for domain dirs: find src/ -type d -name "domain" -o -name "aggregates" -o -name "events"
2. Scan for domain objects: grep -r "class.*Entity\|class.*Aggregate\|class.*ValueObject" src/ -l
3. Scan for domain events: grep -r "Event\|EventHandler\|EventBus" src/ -l
4. Anemic model detection: models with only getters/setters, no behavior methods
Output Format
Print on completion:
DDD SESSION: {domain_name}
Core domain: {core_domain_name}
Keep/Discard
KEEP if: improvement verified. DISCARD if: regression or no change. Revert discards immediately.
Stop Conditions
Stop when: target reached, budget exhausted, or >5 consecutive discards.