Domain-Driven Design Aggregate Contract Design

    1

    Designs DDD aggregate boundaries: aggregate roots, encapsulation, transaction invariants, and domain event contracts.

    $5

    Secure checkout via Stripe

    Money-back guarantee

    Converts to your local currency at checkout

    Security scanned

    Works with the AI Agents you already use

    Claude CodeClaude CodeCursorCursorCodex CLICodex CLIDeepSeekDeepSeekMuseMuse+22 more

    Domain-Driven Design Aggregate Contract Design

    Example session with this skill installed

    Design Domain-Driven Design (DDD) aggregate boundary and invariants for our Commercial Loan Disbursement Aggregate.

    • Subject: loan-disbursement-aggregate v2.0 (run-id: banking-aggregate-001) managing multi-tranche commercial credit facilities up to $50M.
    • Deciders: Lead Domain Architect (David O'Reilly) and Head of Commercial Credit (Elena Rostova).
    • Invariants & Scale: Enforcing credit limit caps, interest rate margin floors (>= 2.50%), tranche sequencing, and zero over-allocation across 35 tranches.
    • Tension: Developers proposed a mega-aggregate merging BorrowerAccount, LoanFacility, DisbursementTranche, and CollateralPledge into one transaction; David O'Reilly and Elena Rostova strictly reject mega-aggregates, citing incident DB-4910 where concurrent tranche approvals caused 45-minute lock cascades. They mandate: LoanDisbursement as the isolated Aggregate Root, explicit Value Objects (Money, Margin, Schedule), reference-by-identity, single-transaction consistency, and outbox domain events.

    Write the aggregate contract specification under docs/.

    • Read your context and instructions
    • Compiled the domain-driven design aggregate

    Wrote docs/architecture/tasks/banking-aggregate-001/aggregate-design/aggregate-contract-spec.md. Complete Domain-Driven Design aggregate specification establishing LoanDisbursement aggregate root boundaries, Value Object encapsulation, reference-by-identity rules, and transactional event outbox contracts.


    skill: aggregate-design

    DDD Aggregate Contract Specification: Commercial Loan Disbursement [AGG-LOAN-001]

    Summary

    This specification establishes the Domain-Driven Design (DDD) aggregate boundaries, invariant enforcement rules, entity lifecycle contracts, and domain event outbox specifications for loan-disbursement-aggregate v2.0 under run ID banking-aggregate-001. It governs commercial credit facilities up to $50M executing across multi-tranche disbursement schedules. It decisively eliminates the database lock contention and transaction failures demonstrated in incident DB-4910 (where a monolithic mega-aggregate spanning borrower, collateral, and loan entities induced massive database deadlocks, freezing commercial credit operations for 45 minutes). The architecture establishes LoanDisbursement as an isolated

    Aggregate Root, models immutable concepts as

    Value Objects (Money, InterestRateMargin, DisbursementSchedule), enforces strict

    reference-by-identity for external entities (BorrowerId, CollateralId), restricts database ACID transactions to a single aggregate boundary, and emits transactional outbox domain events (TrancheDisbursedEvent).

    Detailed Description

    In complex financial domains, developers frequently design "mega-aggregates" that cluster disparate business concepts into a single entity hierarchy. When an aggregate boundary grows too large, multiple concurrent business operations (such as collateral revaluations and tranche disbursements) contend for the exact same database row lock, inducing thread starvation and deadlocks. A formal DDD aggregate boundary defines an atomic consistency island: internal entities are encapsulated behind the Aggregate Root, external aggregates are referenced exclusively by immutable identity keys, and inter-aggregate synchronization is achieved asynchronously via domain events.

    Commercial Credit Operation (Disburse Tranche $2.5M)
                               │
                               ▼
    [ LoanDisbursement Aggregate Root (Boundary Boundary) ]
      ├── 1. Internal Encapsulated Entities:
      │      └── `DisbursementTranche` (Entity: ID, Amount, Status)
      ├── 2. Immutable Value Objects:
      │      ├── `Money` (Currency, Decimal Value, Rounding Mode)
      │      ├── `InterestRateMargin` (Spread Floor: >= 2.50%)
      │      └── `DisbursementState` (Enum: PENDING, DISBURSED, CANCELLED)
      ├── 3. External References by Identity (Zero Direct Object Graphs):
      │      ├── `BorrowerId`: "borr_corp_8812"
      │      └── `CollateralPledgeId`: "collat_pledge_9941"
      └── 4. Invariant Assertion Gate:
             Asserts: Sum(Tranches) <= CreditFacilityCap ($50M)
                               │
           ┌───────────────────┴───────────────────┐
           ▼ (Atomic Commit: Single Aggregate)     ▼ (Invariant Breach: Over-Allocation)
    [ Aurora PostgreSQL 16 (Optimistic Lock) ] [ Business Rule Exception ]
      ├── 1. Updates `LoanDisbursement` Row      └── Throws `CreditLimitExceededException`
      └── 2. Writes `TrancheDisbursedEvent`          Rolls back local transaction in < 2ms
             to Transactional Outbox Table
    

    Criteria and weights

    CriterionWhy it matters hereWeightSource of the weight
    Zero Multi-Aggregate Transaction DeadlocksConcurrent operations on borrower accounts must never block tranche disbursements (DB-4910).0.40David O'Reilly (Lead Domain Architect)
    Transactional Invariant IntegrityAggregate must mathematically guarantee total disbursements never exceed facility caps ($50M).0.30Elena Rostova (Head of Commercial Credit)
    Reference-by-Identity Boundary HygieneAggregates must reference external entities by ID only, avoiding massive object graph memory churn.0.15Core Banking Engineering Standard
    Concurrency Performance (Optimistic Locking)Operations must execute in under 15 ms without database pessimistic row lock serialization.0.15Banking Transaction SLA

    Comparison

    Aggregate Design CandidateBoundary ScopeExternal Entity ReferencingTransaction ConcurrencyEvaluation
    Option A: Monolithic Mega-AggregateBorrower + Loan + CollateralDirect in-memory object graphsPessimistic DB row locks (FOR UPDATE)Rejected: Caused DB-4910 45-minute deadlock disaster.
    Option B: Anemic Data EntitiesSeparate flat database tablesDatabase Foreign KeysExposed public setters (Zero encapsulation)Rejected: Business logic scatters into services; invariants leak.
    Option C: Isolated DDD Aggregate Root (Chosen)LoanDisbursement + TranchesReference-by-Identity (BorrowerId)Optimistic concurrency (version column)Selected: Atomic invariants, zero deadlocks, sub-15ms execution.

    Result

    Option C is selected. LoanDisbursement encapsulates tranche lifecycle logic; reference-by-identity eliminates cross-aggregate deadlocks; optimistic versioning guarantees race-free commits.


    Required Mechanisms

    1. Aggregate Root Boundary & Encapsulation [MC-AR-01]
    • Aggregate Root: LoanDisbursement (Root entity owning lifecycle).
    • Internal Entities: DisbursementTranche:
      • Tranches have local entity IDs scoped within the aggregate root.
      • External callers cannot query or mutate DisbursementTranche directly; all additions or state transitions must invoke methods on LoanDisbursement:
        loanDisbursement.requestTrancheDisbursement(trancheId, amount, margin);
        
    2. Value Object Classification & Immutability [MC-VO-01]

    Money: Contains BigDecimal amount and Currency currency. Enforces Banker's Rounding (half-even); prohibits arithmetic across mismatched currencies.

    InterestRateMargin: Enforces business invariant: spread must be >=

    2.50% (250 basis points). Instantiation with $< 2.50%$ throws IllegalArgumentException.

    DisbursementSchedule: Encapsulates tranche due dates and maturity windows as an immutable value object collection.

    3. Transactional Invariant Enforcement [MC-IE-01]
    • Invariant 1 (INV-FACILITY-CAP):
      $$\sum_{i=1}^{N} \text{Tranche}_i.\text{amount} \le \text{FacilityCeiling} \quad ($50,000,000.00)$$
      If a new tranche causes the aggregate total to exceed $50M, the operation throws FacilityCeilingExceededException and aborts.

    Invariant 2 (INV-TRANCHE-SEQ): Tranche $N$ cannot be disbursed unless Tranche $N-1$ has achieved status SETTLED or CANCELLED.

    4. Reference-by-Identity & Domain Event Outbox [MC-EV-01]
    • Identity References:
      • BorrowerId: String identifier (borr_corp_8812).
      • CollateralId: String identifier (collat_pledge_9941).
    • Domain Event Contract:
      • Upon successful tranche disbursement, the root appends TrancheDisbursedEvent to its internal domain events collection:
        {
          "event_id": "evt_01J8N6B5H2QZ3R8V8",
          "aggregate_id": "disb_facility_881204",
          "event_type": "loan.tranche.disbursed",
          "occurred_at": "2026-09-15T14:22:00.123Z",
          "borrower_id": "borr_corp_8812",
          "tranche_id": "trn_04",
          "amount_cents": 250000000,
          "currency": "USD"
        }
        
      • Saved atomically to the local outbox table in the same database transaction.

    Invariants and Contracts

    Single Aggregate Transaction Boundary [INV-AGG-01]
      A single database transaction must mutate exactly one aggregate instance.
      Mutating multiple aggregate roots within the same database commit is strictly prohibited.
    
    Reference-by-Identity Invariant [INV-AGG-02]
      Aggregates must not hold direct memory references or object pointers to external aggregate roots.
      External entities must be referenced exclusively via immutable identity value objects.
    
    Optimistic Concurrency Control Floor [INV-AGG-03]
      The aggregate persistence entity must maintain a numerical version column (`@Version`).
      Concurrent race conditions must trigger `OptimisticLockingFailureException` and roll back cleanly.
    

    Explicit Unknowns

    • Eventual consistency latency when downstream accounting ledgers consume TrancheDisbursedEvent during peak Kafka broker rebalances (G-1).
    • Maximum cardinality of historical tranche entities per loan facility before aggregate rehydration latency exceeds 10 ms (G-2).

    Traceability

    ClaimClassificationSourceFreshness
    Commercial credit facilities up to $50MprovidedCredit domain scope intakeCurrent
    Incident DB-4910 45-minute deadlock freezeprovidedHistorical post-mortemHistorical
    Interest rate margin floor >= 2.50%providedCredit risk policy intakeCurrent
    Single-aggregate transaction boundary ruledecidedDavid O'Reilly (Lead Domain Architect)2026-09-15
    Reference-by-identity standard (BorrowerId)decidedElena Rostova (Commercial Credit)2026-09-15
    Optimistic concurrency versioningdecidedArchitectural invariant INV-AGG-032026-09-15

    Verification

    No validator was supplied, so no command was run.

    Reviewer self-check against aggregate design standards:

    • Boundary Cleanliness: PASS. LoanDisbursement is the sole root; internal tranches are strictly encapsulated.
    • Reference Hygiene: PASS. External borrower and collateral entities referenced exclusively by identity strings.
    • Invariant Rigor: PASS. Mathematical facility cap ($50M) and tranche sequencing enforced within the root.
    • Markdown Hygiene: PASS. Native Markdown syntax strictly adheres to rule_markdown.md.

    Open Decisions

    • DEC-AGG-01: David O'Reilly to determine whether completed loans older than 3 years should be pruned from the active aggregate table and archived to cold Parquet lakehouses (Owner: David O'Reilly).

    Next steps

    1. Core Engineering implements the LoanDisbursement aggregate root and Money Value Object in Java 21.
    2. Platform team sets up the transactional outbox table schema and Debezium Kafka publisher.
    3. Conduct concurrency stress drill simulating 35 parallel tranche disbursement requests on the same facility to verify race-free optimistic locking.

    Connects securely to your tools. The creator never sees your data.

    About this skill

    What it does

    This skill groups supplied domain state and invariants into the smallest consistency boundaries needed by a declared domain decision. It identifies aggregate roots, internal membership, lifecycle, atomic state transitions, concurrency assumptions, external references and unresolved evidence.

    Use it when

    Use when authoritative invariants and state transitions exist, but it is unclear which state must change atomically, which entity controls mutation, what can remain eventually consistent, or where references cross boundaries.

    For example: “In our warehouse management app, two pickers can claim the last item from a bin at the exact same time, causing negative inventory counts and broken fulfillment orders.”

    What you get

    • DDD Aggregate Model
    • Aggregate Boundary Spec
    • Invariant Rules Documentation

    Written as Markdown to <your output folder>/architecture/tasks/<run-id>/aggregate-design/.

    What it will not do

    Do not use merely to discover entities/value objects/events, design bounded contexts, scaffold DDD code, define repository/ORM/database schemas, choose event sourcing/CQRS, design services/APIs/workflows/sagas, implement tests, or refactor code.

    How it works

    1. Check consistency boundary requirement.
    2. Identify domain invariants.
    3. Select the aggregate root.
    4. Define internal boundary membership.
    5. Establish cross-boundary reference rules.
    6. Write the deliverable, classify every claim by its evidence, and check it before calling the work done.

    What's in the package

    Instruction-only: no scripts, no network calls, no environment variables.

    • LICENSE.txt
    • SKILL.md
    • agents/openai.yaml
    • assets/output-template-task.md
    • references/domain-rules.md
    • references/operating-rules.md
    • references/output-contract.md

    Find more skills like this on the Claude Skills Marketplace, the Codex Skills Marketplace and the Gemini Skills Marketplace, or browse Claude Skills for APIs & Backend.

    Do not use merely to discover entities/value objects/events, design bounded contexts, scaffold DDD code, define repository/ORM/database schemas, choose event sourcing/CQRS, design services/APIs/workflows/sagas, implement tests, or refactor code.

    How to use

    1. 1

      Connect your agent to the Agensi MCP

      Copy the prompt and paste it into Claude, ChatGPT, Cursor or any agent that supports MCP. It sets up the connection for you. Manual setup

    2. 2

      Sign in to Agensi

      Your agent shows a sign-in link. Sign in and click Allow.

    3. 3

      Ask for what you need

      Your agent loads this skill and uses it on your task. It always asks before buying a skill.

    Reviews

    No reviews yet

    Be one of the first to try it. Every listed skill goes through the trust checks below.

    Security scanned

    Checked by our 8-point scan before listing

    Fresh listing

    Recently published to Agensi

    Money-back guarantee

    Doesn't do what its page promises? You get your money back.

    Trust & safety

    Security scan

    Security scan passed 1 month ago

    Permissions

    Read Files
    Write Files

    Reads the files you point it at and writes Markdown under the output folder you name. No network access, no environment variables, and no bundled scripts.

    Listed1 month ago

    What's inside

    Frequently Asked Questions

    No. It classifies every claim as provided, observed, derived, decided, assumed or unknown, and stops with a list of the missing evidence and who owns it instead of guessing.

    No. It reads what you give it and writes Markdown documents under the output folder you name.

    Any agent that supports SKILL.md skills, including Claude Code, Codex CLI, Cursor and Gemini CLI. It has no scripts and makes no network calls.

    Unzip it into your agent's skills folder, for example: unzip aggregate-design.zip -d ~/.claude/skills/

    New in APIs & Backend