/campaigns/:id/builder (full-screen, no sidebar).
Layout
Node palette (left)
Nodes grouped into Builtin, Contact, Messaging. Drag onto the canvas, or click
+ on an edge.Canvas (middle)
ReactFlow. Pan, zoom, multi-select.
Node config (right)
Drawer opens on node click. Form fields are auto-generated from the node’s schema.
Header toolbar
| Action | What it does |
|---|---|
| AI Generate | Generate a graph from a prompt — see AI Generate. |
| History | Open the execution history modal — view past runs. |
| Link Products | Modal to attach products to the campaign. |
| Save | Auto-save in the background. A spinner shows status. |
Canvas actions
Add a node
Add a node
- Drag from the palette → drop on the canvas
- Click
+on an edge → modal to pick the node inserted in the middle
Connect nodes
Connect nodes
Drag from a handle (small circle) on the source node → handle on the target. An edge can have a
when to branch by the source node’s output.Delete a node / edge
Delete a node / edge
Select it → press
Del, or use the menu on the node.Pan / zoom
Pan / zoom
Pan: drag the canvas background. Zoom: scroll wheel or the floating canvas controls.
Node config drawer
Form fields are auto-generated from the node’s schema. Each field has:- Label + description from the schema
- Inline validation (required, type, enum)
- Variable picker — insert
{{...}} - Template picker (when the field is
templateName) - Credential picker (when the field is
credentialId) — filtered by channel
Variable picker
Click the{ } icon in a field → namespace tree popover:
customer.*
customer.*
firstName/lastName/fullNameemail/linkedinUrl/phone/telegramChatIdlanguage/country/timezonetags[]company.name/company.domain/company.industry
trigger.*
trigger.*
type— manual / schedule / webhook / eventpayload.*— payload data
run.*
run.*
id— workflow run IDstartedAt
node.<id>.output.*
node.<id>.output.*
Output of any upstream node. Example:
node.email-1.output.replied.org.*
org.*
name
{{customer.firstName}} into the field at the cursor.
Edge conditions
Default edge: “always advance when the source node finishes”. To branch:- edge.when (simple)
- Conditional Split + Path (complex)
On a messaging node, an outgoing edge can set:
when: replied→ take this path if the customer replieswhen: clicked→ if they clicked a linkwhen: opened→ opened the mailwhen: bounced→ bounceddefault→ none of the above
Compile errors
A red banner appears on the header when the flow has issues:| Error | Fix |
|---|---|
NO_TRIGGER | Add a Trigger node |
DANGLING_NODE | Node has no path to an Exit — connect more |
INFINITE_CYCLE | A cycle without a Wait — add a Wait or remove the cycle |
MISSING_FIELD | A required field is empty |
INVALID_CREDENTIAL | Referenced credential ID doesn’t exist / is disabled |
INVALID_TEMPLATE | Referenced template name doesn’t exist |
History modal
The History button on the header → execution table for the campaign:- Each row = one run
- Status:
running/completed/failed/partial/canceled - Drill into an execution unit → see node-by-node detail for a specific customer
Unsaved changes
Close the tab with pending changes → a warning modal asks: “Save & leave” or “Discard”.Undo/redo, checkpoint restore (graph version history), explicit Validate button, auto-layout button, canvas lock — coming soon.