Commands, Queries, and Events are the typed messages a software system exchanges with its collaborators. A command expresses an intention about the future; a query asks about the present; an event records a fact about the past. Events split into four subtypes — internal, external, error, and temporal — each with its own cause, suppression rule, and downstream triggering behavior. This page defines all of them.

Command

A Command is an inbound message expressing an intention to change domain state. A command triggers an entity operation, which produces one or more events as its result. A command must always include an identifier field — this identifier becomes the correlation id of the chain of causality that follows.

A command succeeds or fails. Success implies at least one state change occurred, producing one or more success events. Failure produces an error event.

Naming: verb in present tense or infinitive, followed by a domain noun (the target entity or aggregate type). Examples: PlaceOrder, CancelBooking, AssignDriver.

Example:

command PlaceOrder {
  satisfies [REQ-ORD-002]

  id: CommandId                   // correlation id
  customer: CustomerId
  lines: LineItem[]

  targets Order
  triggers Order.place
  produces OrderPlaced            // success
  produces OrderRejected          // error (see Error Event)
}

Query

A Query is an inbound message requesting current state. A query is safe and idempotent — it produces no side effects, and repeating it yields the same answer given the same state.

A query carries either an identifier (to retrieve one entity) or a set of match fields (to search). Results either succeed (with data, possibly paginated) or fail (not found).

Naming: get + noun for identifier-based, find + noun for criteria-based. Examples: getOrder, findOverdueInvoices.

Example:

query findOverdueInvoices {
  satisfies [REQ-INV-010]

  dueBefore: Date
  customer: CustomerId?

  reads from InvoiceRepository
}

Event

An Event is a recorded fact about something that happened in the domain. An event is raised when an entity reaches a new state after a transition. Events are append-only: they cannot be retracted, only superseded by a subsequent event. An event may reference the command or query identifier that caused it (the correlation link), and an event related to an entity must always include a field that references the entity identifier.

Naming: past participle. Examples: OrderPlaced, PaymentReceived, DriverAssigned.

Events split into four subtypes, defined below: Internal, External, Error, and Temporal.

Internal Event

An Internal Event is raised within the bounded context from an entity state transition. It is synchronous with the operation that produced it, and it can trigger reactions (a.k.a. policies) within the same context.

Example:

event OrderPlaced {
  satisfies [REQ-ORD-002]

  orderId: OrderId               // entity reference, required
  commandId: CommandId           // correlation id from PlaceOrder
  customer: CustomerId
  total: Money
  placedAt: DateTime

  raised by Order.place
}

External Event

An External Event originates from an upstream bounded context. It enters as an asynchronous input — the system consumes it but does not produce it. If the incoming event does not carry an identifier, the system must add one that will act as the correlation id for the downstream chain of causality.

External events trigger commands: the reactions the system deduces from consuming the event. This is the canonical difference from internal events, which trigger policies.

Example:

externalEvent PaymentAuthorized {
  from PaymentContext

  id: CorrelationId              // added if not present upstream
  orderId: OrderId
  amount: Money
  authorizedAt: DateTime

  triggers MarkOrderPaid         // a command
}

Error Event

An Error Event is a special case of event: the error raised by an operation. It is synchronous with the operation that produced it. Error events can be referenced by reactions (policies), just like internal events. They are part of the public event stream — errors must be modeled as explicit domain facts, not hidden exceptions.

Example:

errorEvent OrderRejected {
  satisfies [REQ-ORD-004]

  commandId: CommandId           // correlation id from PlaceOrder
  reason: RejectionReason        // tied to the violated precondition
  rejectedAt: DateTime

  raised by Order.place
}

Temporal Event

A Temporal Event is a domain fact caused by the passage of time. Unlike internal events (caused by an operation) or external events (caused by an upstream context), a temporal event fires because a time condition — anchored to a domain reference — has been met.

A temporal event is still an event: it is a recorded fact, append-only, can trigger policies, and maintains the causality chain. Every temporal event has a domain-rooted causetime alone is never the cause; the cause is the domain event, entity field, or schedule that establishes the temporal reference.

A temporal event has three flavors, determined by its trigger type.

Relative temporal event

Fires after a duration elapses from a reference event. If the reference event never fires, the temporal event never exists.

Constraints:

  • reference: the event that starts the countdown.
  • offset: a duration expression — fixed (5 minutes) or computed over entity state (ride.estimatedDriverArrivalTime + 5 minutes).
  • guard: a predicate over entity state, evaluated at firing time.

Typical use: “Driver arrival deadline elapsed” — fires ride.estimatedDriverArrivalTime + 5 minutes after RideCreated, guarded by ride.status = driverEnRoute. If the driver arrives before the deadline, the guard becomes false and the event is suppressed.

Absolute temporal event

Fires at a specific instant described by an entity field. Causality flows from the operation that set the field: if the entity is never created, no temporal event exists.

Constraints:

  • instant: a reference to an entity field of type datetime that defines when the event fires.
  • guard: a predicate over entity state evaluated at firing time.

Typical use: “Promotional credit expired” — fires at credit.expiryDate, guarded by credit.status = active. If the credit was already used, the guard is false and the event is suppressed.

Recurring temporal event

Fires on each occurrence of a schedule expression. Causality is the schedule itself — a standing domain commitment established at system design time.

Constraints:

  • schedule: a cron-like expression defining the recurrence.
  • guard: a predicate over system state evaluated at each occurrence.

Typical use: “Weekly payout cycle due” — fires every Monday at 00:00 UTC, guarded by true (always fires on schedule).

Guard Expression

The guard is the mechanism that absorbs both cancellation and conditional firing for temporal events. At firing time, the system evaluates the guard predicate against current entity state. If the guard evaluates to false, the temporal event is silently suppressed — no event is recorded, no policy triggers. No separate armed/fired/cancelled lifecycle is needed; the guard replaces it.

A temporal event with no guard (or guard: true) fires unconditionally when its time condition is met. The guard has access to the entity state referenced by the temporal event’s context.

Recomputation Heuristic

When the reference instant can change after a temporal event is armed — for example, a route recalculation updates an ETA — the modeler must define an explicit recomputation policy that:

  1. Listens to the event that changes the reference value.
  2. Cancels or re-arms the temporal event with the updated firing time.

The recomputation policy is a regular reaction — no special metamodel construct is needed. The metamodel documents this as a modeling heuristic: whenever a temporal event’s offset or instant depends on a mutable value, the modeler must identify which events can change that value and define a policy that re-arms the deadline accordingly. Failing to do so is a modeling gap that can be caught by audit.

Differentiators with Other Event Types

The four event subtypes differ along four axes: what causes them, when they fire, whether they can be suppressed, and what they trigger downstream.

Internal Event External Event Error Event Temporal Event
Cause An operation within the BC An upstream BC An operation failure Time, anchored to a domain reference
Firing Synchronous with operation Asynchronous from upstream Synchronous with operation Asynchronous from clock
Suppression Cannot be suppressed Cannot be suppressed Cannot be suppressed Guard can suppress at firing time
Triggers Policies Commands Policies Policies (same as internal)

The key asymmetry: only external events trigger commands (they enter the system as raw input and must be translated into intentions), and only temporal events can be suppressed (by their guard). Everything else, once produced, is a recorded fact.