Skip to content

Events, By the Book - the North Star

The platform's event architecture, judged against Brandolini's Introducing EventStorming, Evans' Domain-Driven Design, and Dilger's Understanding Eventsourcing - all read in full against the as-built system (164 registered types, verified 2026-08-29). This page is the standing north star for how the event model evolves; the interventions below are discussed in the design review and adopted through workshops with domain experts.

Scorecard: 7 right · 16 partial · 2 wrong · 6 missing across 31 extracted principles. Headline: the mechanics are unusually strong - several exceed what the books ask. The method is inverted: events were discovered by reading code, and every "missing" verdict traces to that inversion.

Provenance, stated honestly

The initial service and API shapes were deliberately taken from Socotra - a mature insurance-platform model (the locator scheme and policy/quote/claims surfaces conform to it). In Evans' vocabulary that is a considered Conformist relationship with a knowledge-rich upstream: a stable skeleton, with our own domain language growing on top as we learn. The event layer is where that learning lives, and the spec is iteratively refinable precisely because consumers depend on facts, not internals.

Where we are right

PrincipleSourceWhy
The registry is a real Published LanguageEvans Ch. 14 pp. 374-377Schema, versioning, producers/consumers, docs and goldens per type - Open Host Service done properly
Test-protected boundaries, beyond the bookEvans pp. 356-358Goldens in CI + e2e gate + runtime verdicts: drift is a red verdict on a live walk, not an incident
Behavior-first, no shared databaseBrandolini p. 66Facts are the only inter-service contract; per-consumer projections translate at the boundary
Not event-sourcing is orthodoxEvans Ch. 6Mutable rows + published facts is the book's shape; argue any change from a concrete need, never purity
Choreography, no orchestratorDilger p. 504"Simply act on the facts in the system. That's it."
Buy-generic distillation in practiceEvans Ch. 15Novu, Temporal, Keycloak, Frappe - effort goes to the differentiating core
The rename machinery the books beg forBrandolini p. 186schemaVersion + priorVersions + tested goldens, built before the naming debt came due

Where we are wrong

  1. The discovery inversion (missing) - zero workshops at any altitude; events from grep. Brandolini: "I just don't trust the official version" (p. 85); reverse narrative typically uncovers 30-40% more system (p. 97). Every other finding is a symptom of this one.
  2. The internal model is the interchange medium (wrong; Evans p. 375) - event-carried state freezes the complete internal row, pinning producers' shapes and making every consumer a conformist. Dilger lands the same blow from privacy: fat events scatter PII ("the simplest data to handle is the data that doesn't exist", p. 554). Fix: slim state to the consumer-verified field set - computable from the registry.
  3. Commands unmodelled (missing) - only outcomes are published; intent survives nowhere but the frontend's activityName. Name the triggering operation per type; validate at invariant-heavy boundaries. No command bus needed.
  4. No context map, noun test never run (missing; Evans p. 345) - what do policy, coverage, member mean per service? Enrollment fuses quoting and policy-admin; identity's 49 onboarding types are a context in hiding. First cut is nearly free from registry edges.
  5. All 164 events implicitly public (partial; Dilger Ch. 5) - no integration/internal/audit classification; everything carries public-contract weight and feeds the warehouse.
  6. Choreography's reliability half missing outside billing/eligibility (partial) - consumers can bury failures with lag at zero; no work-owed recomputation. Dilger's processor-TODO-list is the self-healing answer, and the books' consensus highest-leverage fix.
  7. Read models by aggregation, not projection (partial; Dilger p. 261) - PAS REST-aggregates, timeline pull-aggregates, though every entity already arrives pre-calculated. The PAS field audit was Dilger's information-completeness check (p. 60), done manually, unnamed, unrepeatable.
  8. Strategic layer undocumented (partial) - no pivotal-event phase structure (computable: rank by consumer count), no core-domain vision page, no named aggregates/invariant owners.
  9. GDPR forget-me (missing; Dilger Ch. 41) - the live warehouse-erasure gap has a book playbook: minimalism, crypto-shredding ("delete the encryption key", p. 558), and a party.data_purged purge-propagation event.
  10. Upcast notes are prose, not code (partial; Dilger Ch. 28) - ship tested upcasters with the registry so consumers only ever see the latest version.

The plan

#MoveCost
P1Big Picture storm on quote-and-buy, run blind, then diff wall vs registry - divergences are the findings; Socotra-derived language that loses to expert language becomes renameshalf a day
P2Reverse-narrative walks from policy.activated and claim.paid2h each
P3Noun test then context map from registry edges; settle enrollment split + identity boundary on paper2 sessions
P4Registry fields: audience, command, policy names per consumer edgedays, mechanical
P5State minimalism per consumer-verified fields (identity and party types first)incremental
P6Forget-me pipeline: party.data_purged + warehouse purge + crypto-shredthe real project
P7Reliability floor: durable inbox standard + work-owed processor + alerting on red verdictspattern exists ×2
P8Executable upcasters, then rename quote.updated, element.addedsmall

The rule going forward

New event types are storm-validated with domain experts before registration; emit-site sweeps become a drift detector, never a discovery mechanism. The registry stays the living model - Brandolini's paper roll dies ("we seldom look back to the model", p. 133); ours is enforced in CI, e2e and at runtime, so it cannot drift silently. What changes is the intake.

Olly Health Insurance Platform