Flow Engine — Workflow Automation System

Visual drag-and-drop workflow automation built on xyflow. Create flows that connect triggers, conditions, and actions into automated pipelines.


Overview

The Flow Engine lets workspace admins build multi-step automations without code. Flows are stored as xyflow graph definitions (nodes + edges) and executed server-side by the flow-engine edge function.

Access: /admin/flows

Edge Functions:


Architecture

Admin builds flow (drag-and-drop xyflow canvas)
    ↓
Flow saved to DB (flows table — nodes + edges JSON)
    ↓
Triggered by: cron schedule | incoming webhook | manual | event emission
    ↓
flow-engine edge function walks the graph:
  - Resolves {{template}} variables from execution context
  - Evaluates condition nodes (branches to true/false/case_N)
  - Executes action nodes (SMS, email, HTTP, notification, etc.)
    ↓
Execution log written to flow_runs table

Node Types

Trigger Nodes

Define when a flow starts. One trigger node per flow.

Trigger Type Description
manual Triggered via UI or API call
cron Runs on a schedule (managed by flow-scheduler-cron)
webhook Triggered by incoming webhook POST to flow-webhook
event Fires on platform events (product created, quote submitted, etc.)

Condition Nodes

Branch the flow based on data values.

Condition Type Description
if_else Evaluates field vs value → true / false branches
switch Matches field against N cases → case_0, case_1, … branches
filter Evaluates multiple conditions with AND / OR logic
delay Pauses execution for a duration (capped at 30s in edge function)

Supported Operators for if_else:

Operator Meaning
equals Exact match
not_equals Not equal
contains String contains substring
not_contains String does not contain
starts_with String prefix
ends_with String suffix
gt / gte Greater than / greater than or equal
lt / lte Less than / less than or equal
is_empty Empty string, undefined, or null
is_not_empty Non-empty value

Action Nodes

Perform side effects. Templated values like {{trigger.data.user_email}} are resolved at runtime.

Action Type What it does Cost
send_sms Sends SMS via messaging-api Twilio per-message
send_email Sends email via email-api SES per-message
http_request Makes outbound HTTP call (GET/POST/PUT/DELETE) None
create_notification Inserts record into notifications table None
send_quote Generates and sends quote PDF via generate-quote-pdf Included

Template Variables

Action configs support {{path.to.value}} syntax. The context is built from execution data:

{{trigger.data.field}}          — data from the trigger event
{{node_id.output.field}}        — output of a previous node

Example: An SMS action with to: "{{trigger.data.customer_phone}}" resolves the phone number from whatever data triggered the flow.


Execution Modes

execute-flow

Runs the flow for real. All actions fire (SMS sent, emails sent, etc.).

POST /functions/v1/flow-engine
{
  "action": "execute-flow",
  "flow_id": "uuid",
  "trigger_data": { "customer_phone": "+30...", "name": "Basil" }
}

test-flow

Dry-run. Templates are resolved but no external actions fire. Returns the resolved config for each node so you can verify the output.

POST /functions/v1/flow-engine
{
  "action": "test-flow",
  "flow_id": "uuid",
  "trigger_data": { "customer_phone": "+30...", "name": "Basil" }
}

trigger-event

Auto-dispatch mode used by DB triggers and internal services. Finds all flows with trigger_type = 'event' and event_type matching the event, then runs them.

POST /functions/v1/flow-engine
{
  "action": "trigger-event",
  "event_type": "quote.submitted",
  "event_data": { ... }
}

Scheduling

flow-scheduler-cron runs every minute (pg_cron). It:

  1. Queries all flows where trigger_type = 'cron' and enabled = true
  2. Checks if the cron schedule is due (uses cron expression from flow config)
  3. Invokes flow-engine with action: 'execute-flow' for each due flow
  4. Updates last_run_at and next_run_at in the flows table

Webhooks

flow-webhook exposes a public endpoint for external systems to trigger flows:

POST /functions/v1/flow-webhook?flow_id=<uuid>
Content-Type: application/json

{ "any": "payload", "from": "external-system" }

The payload is passed as trigger.data in the execution context.

Security: Flows with webhook triggers can optionally require an HMAC signature header (X-Webhook-Signature).


Database Tables

Table Purpose
flows Flow definitions (name, graph JSON, trigger config, enabled state)
flow_runs Execution log (status, duration, node results, errors)

Credit Usage

Individual actions may consume credits (e.g., send_sms via Twilio, http_request to paid APIs). Credit deduction is handled by the individual invoked functions, not the flow engine itself.


Error Handling


Last Updated: March 2026