Skip to main content

Entities, Fields & Actions

Entities, fields, and actions are the data-and-behaviour core of an AUSUS domain. This page describes them as graph concepts; the builder methods that declare them are in The PHP DSL.

Entities​

An entity is a domain record type — invoice, customer, order. In the graph it is an EntityNode with:

  • fqn — {plugin}.{local name}, e.g. billing.invoice.
  • tenantScoped — always true in v0.1.0; every entity is tenant-scoped.
  • fields — the field list (system + user fields).
  • actionFqns, projectionFqns, workflowFqns — what is attached to it.

One entity maps to one SQL table; see SQL Persistence.

Fields​

A field (FieldNode) has a name, a type, a nullable flag, optional typeOptions, and an optional default.

Field types​

v0.1.0 supports eight field types:

TypePurposeOptions
stringtextmaxLength
integerwhole numbers—
enuma fixed set of string valuesoptions
moneyan amount + currencycurrency
datetimea timestamp—
identitythe record id (system)—
versionthe optimistic-lock token (system)—
system_stringinternal string column (system)—

identity, version, and system_string are system types — you do not declare them; the kernel injects them.

System fields​

Every entity automatically gets five system fields, in this order:

FieldTypeRole
ididentityprimary key — a 26-char ULID
tenant_idsystem_stringthe owning tenant
_versionversionoptimistic-concurrency token (a ULID)
created_atdatetimecreation timestamp
updated_atdatetimelast-update timestamp

You declare only your domain fields. The money type stores the amount in the column and resolves currency from the field's typeOptions.

Actions​

An action is the only way to change data. In the graph an ActionNode has an fqn, the entityFqn it belongs to, a policyFqn, an effectClass, an input list, a subjectRequired flag, and a kind.

v0.1.0 has two action kinds, both backed by built-in effects:

Create actions​

A create action inserts a new record. It declares which fields are inputs:

'create' => Action::create('number', 'customer_name', 'amount')
->requireRole('invoice.creator'),
  • subjectRequired is false — there is no existing record to act on.
  • The effect is kernel.builtin.create.
  • If the entity has an enum field with a default (a workflow state field), the create effect applies that default automatically.

Transition actions​

A transition action moves a record between workflow states:

'issue' => Action::transition('status', from: 'DRAFT', to: 'ISSUED')
->stamp('issued_at')
->requireRole('invoice.issuer'),
  • subjectRequired is true — you must pass a Reference to the record.
  • The effect is kernel.builtin.transition.
  • ->stamp('issued_at') writes the current timestamp to a field as part of the transition.
  • ->andTransition(...) adds another (from, to) pair to the same action — so one action can be legal from several source states.

Transition actions are what workflows are built from.

Current v0.1.0 limitations​

  • The only action kinds are create and transition, both built-in. There is no built-in update or delete action, and custom Effect-class actions, while supported by the dispatcher, are not exercised by the v0.1.0 sample domain.
  • Field validation is limited to type coercion and presence. maxLength and unique are recorded in the graph but are not enforced as runtime validation rules in v0.1.0.
  • All entities are tenant-scoped; there is no global (un-scoped) entity.