Skip to main content

The Domain Model

The domain section of the spec is the complete business layer of your application. It owns your data model, event contracts, business rules, and read models — co-located in a single, runtime-agnostic declaration.

Why this exists

Business logic in most applications is not co-located with its data model, its event semantics, or its read model. Commands are in route handlers. Read models are in ORM queries. Events are emitted as side effects with no contract. Invariants are scattered across validation libraries and database constraints.

This distribution makes it impossible to understand what the application does from any single artifact, enforce invariants consistently, or test against the real execution engine.

The Gooi domain model defines all of these as first-class spec concepts. The domain section is the single place you declare what your application does and what rules govern it.

The six domain concepts

The domain section contains six sub-concepts in a defined dependency order.

collections  ←  the data store
signals ← events emitted when data changes
capabilities ← reusable logic, pure and in-process
actions ← atomic commands that write, emit, and call capabilities
flows ← stateful orchestration triggered by signals
projections ← read-optimized derived views, never mutate state

Nothing in the domain is public by default. Actions are exposed externally only via mutations. Projections are exposed externally only via queries.

Concepts

  • Collections — named, typed record sets with structural invariants
  • Signals — typed domain events emitted by actions and consumed by flows and projections
  • Capabilities — reusable pure functions (domain) and external operation contracts (provider)
  • Actions — atomic commands that own all writes, emissions, and capability calls
  • Flows — stateful orchestration of action sequences in response to signals
  • Projections — read-optimized derived views with four strategy tiers

The $expr expression DSL

The $expr DSL is a restricted expression language used wherever computed values appear. It cannot call arbitrary functions. All operators are declared in the spec schema.

Common operators: var, if, and, or, !, ==, !==, cat, to_lower, contains, !contains, +, -.

value:
$expr:
if:
- "==": [{ var: principal.subject }, { var: row.user_id }]
- owner
- viewer

What's next

  • Queries and Mutations: how to expose domain actions and projections publicly
  • Scenarios: how to write behavioral tests using the same guard language as your domain