Bounda uses the vocabulary of event sourcing and CQRS, each word for one thing. This page defines them in the order a request meets them; every other page assumes them.
The write side
Section titled “The write side”- Aggregate: a consistency boundary of the domain, such as one order, under
app/domain/<aggregate>/. Each instance is identified by an id. - Command: a request to change one aggregate instance, such as
placeOrder. Itshandlerreads the current state and decides. - Event: a fact the command decided, such as
OrderPlaced, in the past tense. Events are never edited or deleted. - State: what the aggregate’s events add up to.
beginbuilds it from the event that opens the aggregate,evolvefolds every later one into it. - Rejection: a command’s “no”, declared in its
rejectionsand returned withreject. It is an answer to whoever asked, never stored. Not every no is a fact says when a “no” is an event instead.
Storage
Section titled “Storage”- Store: what Bounda runs on: one database, one PostgreSQL schema or one Durable Object. One per app, or one per tenant.
- Event store: the part of the store that keeps the events.
- Stream: the events of one aggregate instance, in order. A command loads it to rebuild the state, and appends to it with optimistic concurrency.
- Global stream: the order of every event in the store, across streams. Each event has a
positionin it; the last position is the head.
The read side
Section titled “The read side”- Read model: a table built from events, under
app/read/<read-model>/, with itsview(the columns) and its queries. - Projection: what keeps a read model up to date; each of its files handles one event. Projections are applied exactly once per batch.
- Query: a named read of a read model, such as
listOrders. Queries never touch the event store. - Rebuild: projecting the global stream again into a fresh table, when a projection changed.
Reactions
Section titled “Reactions”- Policy: “when this event happens, do that”: a handler that runs after an event is stored and may dispatch commands. It keeps no state.
- Process: a process manager. It follows one aggregate instance over time, keeps its own
state, listens to other aggregates’ events and has deadlines, moments its state says it
must act at, each with an
at-<deadline>.tshandler. Its timeout is the deadline that ends it. - Scheduled command: a command dispatched with a
delay, stored and run when it is due. - Saga: not a module. It is the pattern of a multi-step business transaction where each step can be compensated, built from policies or a process (Sagas and compensation).
Policies and processes run at least once, with an inbox: an event already handled is not
handled again, but a handler that fails midway runs again, so calls it makes outside carry an
idempotencyKey.
The runtime
Section titled “The runtime”- Subscriber: a reader of the global stream with its own checkpoint: each read model’s
projection, the policy runner and the process runner.
app.getLag()says how far each is behind the head. - Dispatcher: the loop that hands new events to the subscribers, one pass at a time.
- Inbox: the ledger of which handler has handled which event.
- Dead letter: an event or scheduled command a handler gave up on after its retries, kept with
the error until someone retries or discards it with
bounda dead-letters. - Upcaster: a module next to an event that turns old payloads into today’s shape as they are read (Changing an event’s shape).
Code around the domain
Section titled “Code around the domain”- Port: an interface a module needs from the outside world, such as a notifier or a payment gateway, in a file at the module’s root.
- Implementation: one way to fulfil a port, under
infrastructure/<port>/, chosen by name inbounda.config.tsand replaced by a double in tests (Every module is a hexagon). - Host: what serves the app’s requests: a Node process with the app inside it (a script, a
server, a React Router app), or a Cloudflare Worker with the app in a Durable Object behind it
(its own
fetchor a React Router app).
How Bounda runs puts these together with numbers; Project layout says which file holds each one.