The document projection flow editor uses a directed graph of typed nodes to control how model data is iterated, filtered, branched, and rendered into published document content. Nodes are placed on a grid and connected by edges. Context (the current data scope) propagates along edges, accumulating as the flow passes through selectors and loops.
FlowNodeType Union
export type FlowNodeType =
| 'selector'
| 'loop'
| 'filter'
| 'decision'
| 'scalar-output'
| 'array-output'
| 'chart-output'
| 'responsive-row'
| 'terminator';
Common Node Fields
Every node in the flow shares the following base fields.
| Field | Type | Description |
|---|
| id | string (UUID) | Unique identifier for the node. |
| type | FlowNodeType | Discriminator that determines which config interface applies. |
| gridX | number | Grid column position. |
| gridY | number | Grid row position. |
| gridW | number | Width in grid cells. |
| gridH | number | Height in grid cells. |
| label | string | Display label shown on the node in the flow canvas. |
| config | object | null | Node-specific configuration. Shape varies by type. |
Default Node Sizes
| Node Type | Width (cells) | Height (cells) |
|---|
| selector | 2 | 1 |
| loop | 2 | 1 |
| filter | 2 | 1 |
| decision | 2 | 2 |
| scalar-output | 2 | 1 |
| array-output | 2 | 1 |
| chart-output | 2 | 1 |
| responsive-row | 2 | 1 |
| terminator | 1 | 1 |
Source Root (Terminator)
The source root is a special terminator node that is auto-created when a document projection flow is initialised. It serves as the entry point and cannot be deleted or edited. It anchors the top of the flow and provides the initial context scope containing all model entities.
| Aspect | Detail |
|---|
| Type value | terminator |
| Config | null (no configuration) |
| Deletable | No |
| Editable | No |
| Context output | All model entities and their properties are available in the downstream scope. |
| Visual | Neutral grey circle with stop icon. |
Selector
Scopes the flow context into a specific entity. All downstream nodes operate within the context of the selected entity until another selector or loop changes scope.
| Config Field | Type | Required | Description |
|---|
| entityId | string | Yes | The ID of the model entity to scope into. |
| Aspect | Detail |
|---|
| Context effect | Adds an entity scope frame to the context. Downstream nodes see the selected entity's properties and metadata. |
| Visual | Blue rectangle with target icon. |
| Default label | Select entity |
Loop
Iterates over a collection in the current context, executing all downstream nodes once per item. The loop body receives a new context frame for each iteration.
| Config Field | Type | Required | Description |
|---|
| loopType | LoopType | Yes | What collection to iterate over: 'entity', 'property', 'quality-rule', 'enum-value', or 'relationship'. |
| entityId | string | No | For property, quality-rule, enum-value, and relationship loops: which entity to iterate within. Inherited from context if omitted. |
| Loop Type | Iterates Over | Context Frame Added |
|---|
| entity | All entities in the model (or filtered set) | One entity scope per iteration with all entity metadata and properties. |
| property | All properties of the current entity | One property scope per iteration with property name, type, constraints, governance, etc. |
| quality-rule | All quality rules on the current entity or property | One quality-rule scope per iteration. |
| enum-value | All enum values of the current property (if type is enum) | One enum-value scope per iteration. |
| relationship | All relationships the current entity participates in | One relationship scope per iteration with target entity, cardinality, etc. |
Filter
Reduces a collection in the current context based on one or more conditions. Only items matching all conditions (AND mode) or any condition (OR mode) pass through to downstream nodes.
| Config Field | Type | Required | Description |
|---|
| filterTarget | LoopType | Yes | What collection to filter. Auto-detected from context: entity, property, quality-rule, enum-value, or relationship. |
| conditions | FilterCondition[] | Yes | Array of conditions to apply. Each condition has fieldPath, operator, and optional value. |
| joinMode | FilterJoinMode | Yes | How to combine conditions: 'and' (all must match) or 'or' (any must match). Default is 'and'. |
| Aspect | Detail |
|---|
| Context effect | Reduces the collection that downstream loops iterate over. Does not change the scope type. |
| Filter-aware pills | Downstream output nodes show filtered counts in their source field pills. |
| Visual | Orange rectangle with filter icon. |
| Default label | Filter |
Decision
A conditional branch that evaluates a single condition against the current context and routes the flow along one of two paths: pass (true) or fail (false).
| Config Field | Type | Required | Description |
|---|
| fieldPath | string | Yes | Context field path to evaluate (e.g. 'property.governance.classification'). |
| operator | DecisionOperator | Yes | Comparison operator to apply. |
| value | string | No | Comparison value. Not required for 'exists' and 'not-exists' operators. |
Decision Operators
| Operator | Description | Requires Value |
|---|
| exists | Field is present and non-null | No |
| not-exists | Field is absent or null | No |
| equals | Field equals the specified value | Yes |
| not-equals | Field does not equal the specified value | Yes |
| greater-than | Field is greater than the value (numeric comparison) | Yes |
| less-than | Field is less than the value (numeric comparison) | Yes |
| in-set | Field is one of the comma-separated values | Yes |
| contains | Field contains the value as a substring | Yes |
| not-contains | Field does not contain the value as a substring | Yes |
| count-equals | Count of items equals the value | Yes |
| count-greater-than | Count of items is greater than the value | Yes |
| count-less-than | Count of items is less than the value | Yes |
| Aspect | Detail |
|---|
| Outgoing edges | Two: one with outcome 'pass' and one with outcome 'fail'. Each edge can carry a display label. |
| Visual | Green diamond shape (rotated square) with branch icon. |
| Default label | Condition |
Scalar Output
Produces a single block of rich text content in the published document. The content is an HTML string that can include pill spans referencing context fields and inline expressions.
| Config Field | Type | Required | Description |
|---|
| content | string (HTML) | Yes | Rich text content with embedded pill spans. Pills are replaced with resolved values at publish time. |
| skipCondition | SkipCondition | No | Optional condition. When true, this node produces no output for the current iteration. |
| Aspect | Detail |
|---|
| Published output | An rte (rich text) content block in the page. |
| Visual | Violet rectangle with file-text icon. |
| Default label | Content |
Array Output
Produces a table, bulleted list, or numbered list from an array in the current context. Commonly used inside loops to render property tables or relationship lists.
| Config Field | Type | Required | Description |
|---|
| arrayPath | string | Yes | Path to the array in the current context to iterate. |
| format | ArrayOutputFormat | Yes | 'table', 'bullets', or 'numbered'. |
| tableHeaders | string[] | For table format | Column header labels. Auto-named from field selection. |
| tableColumnBindings | string[] | For table format | One field path per column, binding each column to a data field. |
| listTemplate | string (HTML) | For list format | HTML template with pill spans for each list item. |
| rowFilter | ArrayRowFilter | No | Optional filter to include only items matching a condition. |
| skipCondition | SkipCondition | No | Optional condition. When true, this node produces no output. |
| Aspect | Detail |
|---|
| Published output | A table content block (for table format) or rte content block with list markup (for bullets/numbered). |
| Column reordering | Table columns can be reordered using up/down controls in the config panel. |
| Parent scope fields | Table columns can reference fields from the parent scope (e.g. entity name in a property table). |
| Visual | Violet rectangle with table icon. |
| Default label | Array |
Chart Output
Produces a data-driven chart (rendered with ECharts and SVG) from the current context. Supports 5 chart types and 4 data modes.
| Config Field | Type | Required | Description |
|---|
| chartType | ChartType | Yes | 'bar-horizontal', 'bar-vertical', 'stacked-bar', 'donut', or 'gauge'. |
| dataSource | ChartDataSource | Yes | Defines what data drives the chart. See data modes below. |
| title | string | No | Chart title displayed above the visualisation. |
| xAxisLabel | string | No | Label for the X axis (bar charts only). |
| yAxisLabel | string | No | Label for the Y axis (bar charts only). |
| maxItems | number | No | Maximum items to display. Excess items are grouped as 'Other'. |
| sortOrder | string | No | 'value-desc', 'value-asc', 'label-asc', 'label-desc', or 'natural'. |
| showValues | boolean | No | Whether to display data labels on the chart. |
| showLegend | boolean | No | Whether to display a legend. |
| skipCondition | SkipCondition | No | Optional condition. When true, this node produces no output. |
| templateId | string | No | ID of the pre-built template this chart was created from. |
Chart Data Modes
| Mode | Description | Key Fields |
|---|
| per-entity | One bar or segment per entity. Value is a count or sum of a field. | valueField (optional), valueFilter (optional) |
| distribution | Group items by a field value and count per group. | groupByField |
| stacked-per-entity | One bar per entity with segments stacked by a category field. | stackField |
| gauge | Single percentage value calculated as numerator divided by denominator. | gaugeNumerator, gaugeDenominator, gaugeLabel |
| Aspect | Detail |
|---|
| Published output | A chart content block rendered using ECharts with SVG renderer. |
| Templates | 22 pre-built templates across 6 categories are available in the template picker. |
| Auto-capping | When placed inside a responsive row, charts are auto-capped at 10 items. |
| Visual | Teal rectangle with bar-chart icon. |
| Default label | Chart |
Responsive Row
A flex-wrap container holding multiple cells that adapt to available width. Each cell can contain text (RTE), a table, or a chart. Cells wrap to new rows when the container is too narrow.
| Config Field | Type | Required | Description |
|---|
| cells | ResponsiveCell[] | Yes | Array of cells in this row. Each cell has its own type and configuration. |
| gap | number | Yes | Gap between cells in pixels. Default is 16. |
| skipCondition | SkipCondition | No | Optional condition. When true, this row produces no output. |
ResponsiveCell Fields
| Field | Type | Description |
|---|
| id | string (UUID) | Unique identifier for stable identity and reordering. |
| cellType | ResponsiveCellType | 'text', 'table', or 'chart'. |
| minWidth | number | Minimum width in pixels for flexbox layout. Default is 300. |
| fixedHeight | number (optional) | Fixed height in pixels. When set, text and tables scroll and charts use dataZoom. 0 or undefined means auto height. |
| textContent | string (HTML) | For text cells: RTE content with pill spans. |
| tableConfig | ArrayOutputConfig | For table cells: reuses the array output configuration. |
| chartConfig | ChartOutputConfig | For chart cells: reuses the chart output configuration. |
| Aspect | Detail |
|---|
| Published output | A responsive-row content block with nested cells. |
| Full-screen expand | Each cell supports a full-screen expand toggle in the published viewer. |
| Inline RTE editing | Text cells support inline rich text editing in the config panel. |
| Visual | Amber rectangle with columns icon. |
| Default label | Responsive Row |
Edges
Edges connect nodes in the flow graph and carry context from source to target. Decision nodes produce edges with an outcome field.
| Field | Type | Description |
|---|
| id | string (UUID) | Unique edge identifier. |
| sourceNodeId | string | ID of the source node. |
| targetNodeId | string | ID of the target node. |
| outcome | 'pass' | 'fail' (optional) | For decision nodes: which output branch this edge represents. |
| label | string (optional) | Display label shown on the edge (e.g. 'Has PII', 'No PII'). |
Skip Conditions
Scalar output, array output, chart output, and responsive row nodes support an optional skip condition. When the condition evaluates to true, the node produces no output for the current iteration. The skip condition uses the same operator set as decision nodes.
| Field | Type | Description |
|---|
| fieldPath | string | Context field path to evaluate. |
| operator | DecisionOperator | Comparison operator (same set as decision nodes). |
| value | string (optional) | Comparison value for non-exists operators. |