Skip to content

Aggregate Designer

Part of the Designer guide. Previous: Bounded Context Editor · Next: Process Designer.

An aggregate is the consistency boundary of your model. In the Aggregate Designer you decide which tables belong to it, which entity is the root and how they relate, as an ER diagram. One click on Build generates the complete code tree from it.

Aggregate Designer: ER model with root entity, PK/FK/UK markers and cardinalities

The Tabs

The Designer leads from table selection to finished code, all in one surface:

TabWhat you see
TablesThe imported BC schema — tables, columns, keys. Here you pick the subset that belongs to the aggregate.
DesignerThe ER canvas: tables as nodes, relationships as edges.
CodeThe generated PHP code, read-only in the browser. See Code, API & Reports.
APIThe exposed command/query/event surface of the aggregate, read-only.
Report / ValidationBuild status and validator findings.

The Tables tab: the imported schema as the starting point

Step by Step

  1. Choose tables — in the Tables tab, select the aggregate's tables from the BC schema. They appear as nodes on the canvas.
  2. Mark the root — the set-as-root header on the node establishes the root entity. It is the only door into the entity graph.
  3. Draw relationships — edges between nodes represent the ER structure (PK/FK/UK/IK). A freshly drawn edge is immediately selected and gets confirmed or discarded in the side panel.
  4. Maintain details — a side panel opens on the right for each node (see below).
  5. Save & Build — Save persists the current state; Build generates the code.

The node side panel with the Defaults and Order tabs

The Node Side Panel

Each node opens a side panel with two tabs:

  • Defaults — presets in two modes. onCreate sets values once at birth (constants, UUID7, FK references such as <entity>.id). sync re-inherits ancestor fields (<entity>.field) on every persist. The mode follows automatically from the value type: a wrong placement isn't possible here.
  • Order — the OrderBy sort order for 1:n relationships.

The Edge Side Panel

Clicking an edge shows its variant in the same side panel: swap parent/child, 1:1 vs. 1:n cardinality, and (for aggregate-internal edges) the required / optional toggle (the existence invariant of the relationship, default required). This is directly visible on the canvas: a required edge is drawn solid, an optional edge dashed and slightly dimmed.

Auto-Layout

A kebab entry Auto-Layout arranges the graph hierarchically from left to right along the edges; it collects unconnected tables as a compact block below. This only changes the in-memory positions: they are persisted only on the next Save/Build.

Draft and Build Lock

Save always succeeds. If the canvas is inconsistent (e.g. a table is unreachable from the root), Jardis persists the state as a draft instead of aborting with an error: the last consistent state remains untouched. A draft badge appears, with the kebab action "discard draft".

As long as a draft is open, Build is blocked, at every entry point (build dialog, headless build, CLI). Headless this surfaces as a DRAFT_EXISTS error (MCP).

From Model to Code

A build generates a hermetic, generator-owned tree per aggregate under {BC}/Aggregate/{Agg}/. Never edit by hand. It holds two facades:

  • Read facade {Agg}Read — the "front door": get{Agg}ById / ByIds / By{Key} and {agg}List. Reachable via the BC facade: $bc->{agg}().
  • Write facade {Agg} — commands and event(); reachable only family-internally via the Kernel seam, not from the transport layer.

Write flows therefore go through processes, not directly against the aggregate. How you wire the generated code in is shown in Get Started; depth is in the skills (platform-usage, platform-implementation).

Need a new operation?

A new aggregate operation is created by remodeling in the Designer, not by hand-editing the generated code. A flow spanning several aggregates belongs in a process.