ADR-016 Status: Proposed Version 0.1 2026-05-12
Requiemos / Architecture

The Domain
Aggregate Model

Three operational aggregates — Contract Management, Chain of Custody, Case Workflow — sitting over a two-layer substrate of durable Person identity and operational Case state.

In one breath

Make the three-capability mental model that we already use in pitches and PRDs architecturally explicit, and introduce a Person identity layer beneath the case so that pre-need contracts — newly in MVP scope — have a place to live.

Status update 2026-09-30. ADR-010 (module pipeline) and ADR-011 (context envelope), which defined the Case Workflow aggregate’s internals when this page was written, were superseded by ADR-061 and retired 2026-09-12 at substrate-slice-15. The Case Workflow card below is updated to current contents; see ADR-016’s 2026-09-30 Resolution Note. Other framing is kept as a historical explainer.

A two-layer substrate, three operational aggregates

Person identity exists before any case. Case substrate is built on top at need-time. Three aggregates operate over this substrate, each owning its own tables. Scheduling sits beside them as a shared service.

Domain aggregate model diagram AGGREGATE Contract Management What was agreed, what it costs spans both substrate layers AGGREGATE Chain of Custody Physical possession & accountability at-need only AGGREGATE Case Workflow Orchestration & lifecycle execution at-need only pre-need references SUBSTRATE LAYER · AT NEED-TIME Case Substrate cases  ·  case_deceased  ·  case_family_members  ·  branches deceased role attaches a Person to a Case SUBSTRATE LAYER · DURABLE IDENTITY Person Identity people  ·  person_relationships  ·  exists independent of any case CROSS-CUTTING SERVICE Scheduling — calendars, resources, availability; consumed by all three aggregates

The two substrate layers

Identity lives at the base; case state sits above it. Workflow, contracts, and custody all read and write through these layers but never own them.

Substrate · Durable

Person Identity

The base layer. People exist before any case — pre-need clients, repeat-customer families, multi-generational relationships. The substrate is the only writer of identity facts; all aggregates that need to update a Person call substrate services. Identity verification follows a supersession pattern (corrections do not overwrite history).

Substrate · Operational

Case Substrate

Materialized when a death occurs (or a first-call is received). The umbrella record for one active case: who is the deceased, which family members are involved, which branch, which jurisdiction, what status. Case-scoped facts about the deceased (time, place, cause of death) live here — not on the Person record.

The three operational aggregates

Each owns a distinct source of authority. Cross-aggregate writes go through service interfaces; the database does not enforce this, code review does.

01
Contract Management
Spans Person & Case
"What was agreed to, and what it costs."

Sole writer of pricing catalogs, contracts, line items, amendments, signed documents. Pre-need contracts reference a Person directly; at-need contracts reference a Case. At-need conversion is internal to this aggregate — not a cross-aggregate handoff.

Representative tables
  • gpl_packages, gpl_line_items
  • pre_need_contracts
  • case_contracts, amendments
  • case_documents, signature_*
02
Chain of Custody
At-need only
"Physical possession and asset accountability."

The aggregate with the strongest regulatory and legal-discovery requirements. Custody events are immutable, append-only, with supersession for corrections. Custody scans (ChainOfCustody::RecordEvent) write through a service interface — never direct inserts. Asset terminal-state checks block case closure.

Representative tables
  • custody_events (Layer 1)
  • assets
03
Case Workflow
At-need only
"Orchestration and lifecycle execution."

Owns per-case artifact-instance lifecycle state; readiness (requirements, milestones, suggested tasks) is computed on read by the ADR-061 substrate. Requirement, artifact, and milestone definitions live in Tenant Configuration (capability profiles) per ADR-016’s 2026-09-30 note. Reads extensively from substrate, contract, and CoC — writes back only through service interfaces. Activity events are written by typed Workflows::CaseActivity::Recorder calls; services rendered via Contracts::ServicesRendered::Recorder. (The module engine, templates, and context envelope were retired 2026-09-12.)

Representative tables
  • artifact_instances
  • case_activity_events (L3)
  • case_services_rendered (L4)
Cross-cutting

Scheduling is a service, not an aggregate. It owns calendars, resources, and availability — written to by Workflow (most often), Contract Management (arrangement conferences), and CoC (transport). Scheduled events show up on cases as Layer 3 activity events when relevant.

Pre-need is now in MVP scope

A scope discovery on 2026-05-12 added pre-arrangement contracts to MVP. Pre-need agreements predate any case — they reference a living person, with locked-in pricing that activates at need-time. Without a Person identity layer, the data model traps deceased records inside cases and cannot represent a future-deceased who has no case yet.

Pre-need is contract management, not a separate aggregate.

The regulatory grouping (FTC Funeral Rule, BC's Cremation, Interment and Funeral Services Act) treats pre-need and at-need as a single contractual continuum. Pricing structure, GPL catalogs, packages, and amendment patterns are the same.

What differs is the relationship target: pre-need points at a Person, at-need points at a Case. Same aggregate, different reference.

In MVP: pre-need agreement structure, line items, locked-in pricing. Out of MVP: trust accounting, payment schedules, escrow tracking.

PRE-NEED CONTRACT references Person locked-in pricing at need CASE CONTRACT references Case same prices preserved PERSON durable identity CASE materialized at-need conversion is internal to Contract Management

Six boundary rules

Code-organization and review rules, not database constraints. They prevent the aggregate boundaries from drifting as the system grows and turn ambiguous design questions into decided ones.

01

Exclusive write authority

Each aggregate is the only writer of its tables. Cross-aggregate writes happen through published service interfaces.

02

Substrate owns identity facts

Person fields (name, DOB, identity_verified) are updated only by substrate services. Identity verification supersession is enforced here.

03

Pre-need conversion is internal

At-need conversion of a pre-need contract is a Contract Management operation. The trigger is a substrate event Contracts subscribes to.

04

CoC and Workflow require a case

Neither aggregate has a pre-need analog. A pre-need Person has no custody history and no workflow execution. Structural fact, not a constraint.

05

Reconciliation crosses boundaries

services_rendered (Workflow) is read by Contract Management during reconciliation. The most prominent cross-aggregate read; result lands as a contract amendment.

06

Scheduling is consumed, not owned

Multiple aggregates write scheduled events through the scheduling service. The service enforces resource availability; aggregates trust it.