Domain Event
The business fact frozen in time becoming the temporal boundary between bounded contexts — foundation of any serious event-driven architecture.
Problem
An EDI hub receives an INVOIC from a partner. Three independent teams need it: finance to book it, logistics to release payment, audit to archive 10 years with signature. If the reception service calls all three directly (synchronous HTTP), it knows their existence and API. A new team (machine learning, tax compliance) must be wired in explicitly each time. Worse: if finance is down, reception blocks. We have re-created a distributed monolith over HTTP.
Forces
- The consequences of a business fact are many. An invoice received triggers accounting, payment, archive, KPIs, fraud detection.
- The producer must not know the consumers. Otherwise, adding a consumer means modifying the producer.
- Consumers have different cadences. Accounting = real-time; KPIs = daily batch; ML = quarterly.
- Business history is valuable. An invoice received on May 12 at 14:32 remains true even if the system is replayed 6 months later.
Solution
Model the business fact as an immutable Domain Event
named in the past tense: InvoiceReceived, OrderApproved, ShipmentDispatched. The
producer emits the event on a bus (Kafka, AWS EventBridge, NATS),
with a unique id, a signed timestamp, and a payload carrying the
data needed for autonomous consumption. Consumers subscribe. Adding
a consumer has no impact on the producer. Events are persisted —
replayable — and can ground Event
Sourcing.
{
"type": "InvoiceReceived",
"eventId": "01H...ULID",
"occurredAt": "2026-05-16T08:30:12.345Z",
"aggregateId": "invoice-INV-2026-0001234",
"aggregateVersion": 1,
"payload": {
"invoiceNumber": "INV-2026-0001234",
"supplierId": "GLN-3010234567890",
"buyerId": "GLN-3060987654321",
"amount": { "value": 12500.00, "currency": "EUR" },
"issueDate": "2026-05-15",
"dueDate": "2026-06-14"
},
"metadata": {
"source": "edi.parser.edifact",
"traceId": "00-abc...-01"
}
}
EDI implementation
Concrete case: the EDIFACT parser receives an INVOIC, validates
syntax/semantics, and publishes InvoiceReceived on
Kafka edi.events.v1. Three independent consumers: (1)
accounting service creates a journal entry, (2) archive service
XAdES-signs and stores in S3 Object Lock for 10 years, (3)
notification service emails the client. If tomorrow we add a fraud
ML detection service, we create a new consumer: the parser is
untouched. Events are versioned (InvoiceReceived.v1, InvoiceReceived.v2) to handle schema evolution. The Outbox
pattern publishes the event atomically with the DB commit. Apache
Camel, Spring Modulith, Axon Framework tool this pattern in Java; EventCatalog documents
the schemas.
Anti-patterns
- Events named in the present.
SendInvoiceorCreateInvoiceare commands, not events. Confusing the two creates disguised coupling. - Events too fine (CRUD events).
InvoiceFieldUpdatedfor each field: noise, loss of business meaning. EmitInvoiceCorrectedwith the new business snapshot. - Events too rich. If the payload carries every possible state, we return to a shared library. The consumer must be able to use it and ask for extras through APIs if needed (Content Enricher).
- Events tied to infrastructure.
KafkaMessageReceivedorJmsMessageDeliveredare not business events. They may be useful technically but do not carry domain meaning.
Related patterns
- Event Message — the EIP brick of event transport.
- Event Sourcing — persisting the event log as source of truth.
- Saga Choreography — loose coupling between contexts via domain events.
- Outbox — to publish the event atomically with the DB commit.
- Bounded Context — domain events cross contexts telling their story.
Sources
- Evans E. — Domain-Driven Design, Addison-Wesley 2003. Founding concept; expanded in later editions and by the DDD community.
- Fowler M. — Domain Event (martinfowler.com, 2005). The pedagogical definition. martinfowler.com — DomainEvent
- Vernon V. — Implementing Domain-Driven Design, Addison-Wesley 2013. Chap. 8 "Domain Events" with Java examples.
- Microsoft Architecture Center — Domain events: design and implementation. The pattern transposed to .NET. learn.microsoft.com — Domain events
- CloudEvents spec. The CNCF standard for cross-system event serialisation. cloudevents.io