Graph Model
The graph is built from nodes and edges with structure driven by persisted relationships.
Species
Current taxonomy has exactly 4 species.
| Level | Species | Role | React Flow node type |
|---|---|---|---|
| 1 | flow | Ordered sequence container | flow |
| 0 | view | Reusable page/screen | view |
| — | data-model | Data entity/table | dataModel |
| — | api-endpoint | API endpoint | apiEndpoint |
Config source: lib/config/species.ts
Canvas Visibility
- Canvas rendering currently shows only
flowandviewas visible React Flow nodes. data-modelandapi-endpointremain persisted graph species and can still be edited from panels/import-export, but they are not rendered as standalone canvas cards.- View cards surface API relationships inline via embedded actions instead of separate API nodes.
Source: app/project/[id]/canvas/page.tsx, components/graph/nodes/ViewNode.tsx
Library Views
Project library is available at /project/[id]/library with two browsing modes:
- Gallery: card grid with title, prefixed ID, species/status badges, platforms, and flow playlist preview.
- Directory: sortable table for
id,title,species,status, andused inflow count.
Filtering:
- Species filter supports
all,flow,view,data-model,api-endpoint. - Search matches node title and description text.
Library source:
- app/project/[id]/library/page.tsx
- components/library/LibraryFilterBar.tsx
- components/library/NodeCard.tsx
- components/library/NodeTable.tsx
Composition Model
Root Node
project.root_node_idis the explicit canvas anchor when present.- If
root_node_idis not set, the canvas infers roots from nodes with no incomingcomposesedge.
Source: app/project/[id]/canvas/page.tsx, lib/data/types.ts
Playlist Expansion
- Persisted parent/child links are
composesedges. - Child ordering is read from
node.metadata.playlist.entries. - When playlist entries do not reference all compose-edge children, missing children are appended after playlist-derived ordering.
Source: app/project/[id]/canvas/page.tsx
All flows start collapsed. Any visible flow can be expanded in-canvas. Top-level expansion (root flow and/or direct flow children of project.root_node_id, or inferred root flows when no explicit root exists) is accordion-style: opening one top-level flow collapses any other top-level flow already open.
Expanded flow children follow a strict alternating drill layout:
- Root children are rendered horizontally below the root.
- Level 2 children are rendered vertically below each level 1 node.
- Level 3 children are rendered horizontally below each level 2 node.
- The pattern continues alternating by depth.
- Vertical drill segments always use top/bottom handles for both
flowandviewnodes.
Layout is computed by elkjs (Eclipse Layout Kernel, layered algorithm). The page builds a flat list of nodes and compose edges with position: {x:0, y:0}, then an async useEffect calls computeElkLayout() which runs the ELK layered algorithm and returns positioned nodes.
Layout source: lib/utils/elk-layout.ts
Source: app/project/[id]/canvas/page.tsx
Node Reuse
viewandflownodes are reusable and can appear multiple times across playlists.- Reuse is many-to-many: a single node can be referenced by many flow playlists, and one flow playlist can reference many nodes.
- The source of truth for sequence semantics is the playlist (
metadata.playlist.entries), whilecomposesedges provide structural connectivity. - The detail panel's where-used UI derives reverse references by scanning all flow playlists.
Source: components/panels/NodeDetailPanel.tsx, lib/utils/where-used.ts, lib/data/types.ts
Playlist Entry Types
flow nodes store ordered playlist data in node.metadata.playlist.entries.
| Entry Type | Required Fields | Notes |
|---|---|---|
view | view_id | Reference to an existing view node |
flow | flow_id | Reference to an existing flow node (cycle-checked before persist) |
condition | label, if_true, if_false | Two branch lists, each a recursive PlaylistEntry[] |
junction | label, cases[] | Each case has label + entries: PlaylistEntry[] |
Editing source: components/panels/PlaylistEditor.tsx, components/panels/PlaylistEntryRow.tsx
Type source: lib/data/types.ts
Status Model
Statuses are configured in:
Rollup behavior:
viewis the only species with editable per-platform status values (metadata.platformStatuses).flowstatus is computed for display by recursively walking playlist entries and aggregating descendant view platform statuses, including nested sub-flows and branch entries.data-modelandapi-endpointuse single lifecycle status.
Sources:
Platforms
Platforms are configured in:
Views can target one or more platforms; per-platform notes/statuses are stored in node metadata.
Source:
Edge Types
| Edge Type | Use |
|---|---|
composes | Composition hierarchy and ordered flow sequences |
calls | View to API relationship |
displays | View to data-model relationship |
queries | API to data-model relationship |
Config source: lib/config/edge-types.ts
Rendering mapping source: app/project/[id]/canvas/page.tsx
calls edges between a view and API endpoint are projected into View card UI:
- API -> View: inbound/read affordance (
cloud-downloadicon) - View -> API: outbound/write affordance (
cloud-uploadicon)
Source: app/project/[id]/canvas/page.tsx, components/graph/nodes/ViewNode.tsx
Node And Edge Components
Node registration is in:
Current custom registrations:
flow->FlowNodeview->ViewNodedataModel->DataModelNodeapiEndpoint->ApiEndpointNode
dataModel and apiEndpoint remain registered node types for compatibility, but the current project page renderer does not add those species into visibleNodes.
Edge registration is also in components/graph/Canvas.tsx.
Taxonomy Update Checklist
- Update config array in
lib/config/*. - Update page mappings and rendering filters in app/project/[id]/canvas/page.tsx.
- Update Canvas registrations in components/graph/Canvas.tsx.
- Update forms/panels that branch by species.
- Update seed data in seed/pebbles.json.
- Update this document.