Actions, events, and rules
Behavior is modeled as intent, outcome, and constraint. Commands request change, mutations describe its effect, events record what happened, and rules determine when it is allowed.
Actions
Section titled “Actions”The product-facing action vocabulary has three kinds:
- mutates: a user or system requests a state change;
- reads: an actor asks a question;
- triggers: behavior starts from an event or timer rather than a person.
A mutating action materializes as a command with typed parameters, allowed actors, row scope, mutations, emitted events, and possible domain errors.
Prefer product language:
ConfirmAppointmentCancelAppointmentRecordPaymentAuthorizationUpdateAppointment hides intent and makes permissions, rules, and tests harder to express.
Mutations
Section titled “Mutations”Mutations connect command inputs or declared values to real object fields. They may set a parameter value, use a constant, copy existing state, compute a result, stamp the current time, generate an identifier, or modify a collection.
Every mutation target must resolve. A required creation field must have an explicit source. The generator must not guess a mapping from similarly named parameters when the result would be ambiguous.
Events
Section titled “Events”An event is a past-tense domain fact emitted after a successful change:
AppointmentConfirmedPaymentAuthorizationFailedMemberInvited
Events carry enough data for observers and reactions to act without reading hidden request state. They can notify actors, trigger cross-object reactions, or feed audit and integration behavior.
Reactions and timers
Section titled “Reactions and timers”A reaction connects an event to another command. It can map event fields to command parameters and, for a cascade, declare how affected rows are matched.
A timer triggers a command from a schedule or time condition. Model the business meaning—such as expiring a reservation—rather than only the scheduler expression.
Choose synchronous dispatch only when the initiating request needs the result and can tolerate the dependency. Async dispatch needs idempotency, retry policy, observability, and a defined failure outcome.
Rules and errors
Section titled “Rules and errors”Rules express constraints, calculations, and preconditions. Bind them to the relevant action or lifecycle transition.
CancelAppointment is rejected when startsAt < now + 24 hours.ConfirmAppointment is rejected when the slot is already occupied.A rule should point to a typed domain error with product-facing language. “Validation failed” is not enough for a user or an operator.
State machines
Section titled “State machines”Use a state machine when an object’s status has a closed lifecycle. Declare states, allowed transitions, triggering actions, and emitted events. This lets backend validation, UI action availability, and executable scenarios derive from one source.
Do not rely on the frontend to hide invalid actions. The generated backend must enforce the rule at the authoritative write boundary.
Atomicity
Section titled “Atomicity”Changes inside one aggregate should complete atomically. Cross-aggregate reactions and external calls require an explicit consistency strategy; do not imply a distributed transaction that the runtime cannot provide.
Next, model the read side with Queries and computed values.
