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

    30-day refund guarantee

    Converts to your local currency at checkout

    Security scanned

    Works with the AI tools you already use

    Claude CodeClaude CodeCursorCursorCodex CLICodex CLIMuseMuseOpenClawOpenClaw+21 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.

    What you get

    Define aggregate roots and transactional consistency boundariesDocument domain invariants and atomic state transitionsEstablish cross-boundary reference and eventual consistency rulesIdentify internal aggregate membership and lifecycle constraints

    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

    How to install

    Works the same in every agent - Claude, Cursor, Codex, Copilot and 20+ more.

    ~30 seconds
    1. 1

      Download the ZIP

      Free skills download straight away. Paid skills unlock right after purchase.

    2. 2

      Unzip into your skills folder

      Every agent reads skills from one folder on your machine. Drop the unzipped folder in there.

    3. 3

      Ask your agent to use it

      Restart the agent if it was already running. It picks the skill up automatically - no config needed.

    Skills folder by agent

    Click the path to copy it. Create the folder if it does not exist yet.

    Reviews

    No reviews yet

    Be one of the first to try it. Every listed skill passes our trust checks below.

    Security scanned

    Passed our 8-point scan before listing

    Fresh listing

    Recently published to Agensi

    30-day refund

    Not a fit? Get your money back

    Trust & safety

    Security scanned

    Verified clean 12 days ago

    • Passed all security checks, Safe to install

    Listed12 days ago

    What's inside

    Frequently Asked Questions