Documentation Index
Fetch the complete documentation index at: https://docs.encoreos.io/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Technical reference for Workflow Builder React components, hooks, and types in the FW core.
React Components
WorkflowCanvas
Visual canvas for designing workflows with React Flow.
import { WorkflowCanvas } from '@/cores/fw/components/workflow/WorkflowCanvas';
<WorkflowCanvas
nodes={nodes}
edges={edges}
onNodesChange={handleNodesChange}
onEdgesChange={handleEdgesChange}
onNodeClick={handleNodeClick}
onPaneClick={handlePaneClick}
onDrop={handleDrop}
onDragOver={handleDragOver}
/>
Props:
nodes: Node[] - Array of workflow nodes
edges: Edge[] - Array of connections between nodes
onNodesChange: (changes: NodeChange[]) => void - Node state changes
onEdgesChange: (changes: EdgeChange[]) => void - Edge state changes
onNodeClick?: (event: React.MouseEvent, node: Node) => void - Node click handler
onPaneClick?: () => void - Canvas click handler
onDrop?: (event: React.DragEvent) => void - Node drop handler
onDragOver?: (event: React.DragEvent) => void - Drag over handler
NodePalette
Sidebar with draggable node types.
import { NodePalette } from '@/cores/fw/components/workflow/NodePalette';
<NodePalette />
Features:
- Categorized node groups (Triggers, Actions, Control Flow, etc.)
- Drag-to-add interface
- Search/filter capability
- Collapsible categories
NodePropertiesPanel
Configuration panel for selected node.
import { NodePropertiesPanel } from '@/cores/fw/components/workflow/NodePropertiesPanel';
<NodePropertiesPanel
selectedNode={selectedNode}
onNodeUpdate={handleNodeUpdate}
onDeleteNode={handleDeleteNode}
/>
Props:
selectedNode: Node | null - Currently selected node
onNodeUpdate: (nodeId: string, data: any) => void - Update handler
onDeleteNode: (nodeId: string) => void - Delete handler
ExecutionTrace
Timeline visualization of workflow execution.
import { ExecutionTrace } from '@/cores/fw/components/workflow/ExecutionTrace';
<ExecutionTrace
executionId={executionId}
execution={execution}
/>
Props:
executionId: string - Execution record ID
execution: WorkflowExecution - Execution data with node states
WorkflowValidation
Pre-execution validation and error display.
import { WorkflowValidation } from '@/cores/fw/components/workflow/WorkflowValidation';
<WorkflowValidation
nodes={nodes}
edges={edges}
onValidate={(result) => console.log(result)}
/>
Props:
nodes: Node[] - Workflow nodes to validate
edges: Edge[] - Workflow edges to validate
onValidate?: (result: ValidationResult) => void - Validation callback
ValidationResult:
interface ValidationResult {
valid: boolean;
errors: ValidationError[];
warnings: ValidationWarning[];
}
ErrorDisplay
Error presentation component.
import { ErrorDisplay } from '@/cores/fw/components/workflow/ErrorDisplay';
<ErrorDisplay
error={error}
variant="card" // or "inline"
/>
Props:
error: WorkflowError | string - Error to display
variant?: 'inline' | 'card' - Display style (default: ‘inline’)
React Hooks
useWorkflowDefinition
Fetch and save workflow canvas state.
import { useWorkflowDefinition } from '@/cores/fw/hooks/useWorkflowDefinition';
const {
definition,
isLoading,
isSaving,
saveDefinition
} = useWorkflowDefinition(ruleId);
// Save changes
saveDefinition(nodes, edges, viewport);
Parameters:
ruleId: string - Automation rule ID
Returns:
definition: WorkflowDefinition | null - Current canvas state
isLoading: boolean - Loading state
isSaving: boolean - Saving state
saveDefinition: (nodes, edges, viewport?) => Promise<void> - Save function
useWorkflowExecution
Manage workflow execution state.
import { useWorkflowExecution } from '@/cores/fw/hooks/useWorkflowExecution';
const {
execution,
isLoading,
pauseExecution,
resumeExecution,
cancelExecution
} = useWorkflowExecution(executionId);
Parameters:
executionId: string - Execution record ID
Returns:
execution: WorkflowExecution | null - Execution data
isLoading: boolean - Loading state
pauseExecution: () => Promise<void> - Pause function
resumeExecution: () => Promise<void> - Resume function
cancelExecution: () => Promise<void> - Cancel function
useWorkflowApprovals
Fetch and manage approval tasks.
import { useWorkflowApprovals } from '@/cores/fw/hooks/useWorkflowApprovals';
const {
approvals,
isLoading,
approveTask,
rejectTask
} = useWorkflowApprovals(organizationId);
// Approve task
await approveTask(approvalId, 'Looks good!');
// Reject task
await rejectTask(approvalId, 'Need more information');
Parameters:
organizationId: string - Organization ID
Returns:
approvals: WorkflowApproval[] - Pending approvals
isLoading: boolean - Loading state
approveTask: (id, notes?) => Promise<void> - Approve function
rejectTask: (id, notes?) => Promise<void> - Reject function
useSubflows
Manage reusable subflows.
import { useSubflows } from '@/cores/fw/hooks/useSubflows';
const {
subflows,
isLoading,
createSubflow,
updateSubflow,
deleteSubflow
} = useSubflows(organizationId);
// Create new subflow
await createSubflow({
name: 'Employee Setup',
description: 'Standard onboarding process',
input_schema: [...],
output_schema: [...]
});
Parameters:
organizationId: string - Organization ID
Returns:
subflows: Subflow[] - Available subflows
isLoading: boolean - Loading state
createSubflow: (data) => Promise<void> - Create function
updateSubflow: (id, data) => Promise<void> - Update function
deleteSubflow: (id) => Promise<void> - Delete function
useExecutionTrace
Fetch real-time execution trace.
import { useExecutionTrace } from '@/cores/fw/hooks/useExecutionTrace';
const { data: execution, isLoading } = useExecutionTrace(executionId);
Parameters:
executionId: string | null - Execution record ID
Returns:
- React Query result with
execution data
- Auto-polling while execution status is ‘running’ or ‘paused’
useWorkflowVersions
Manage workflow version history, rollback, and comparison.
import { useWorkflowVersions } from '@/cores/fw/hooks/useWorkflowVersions';
const {
versions,
isLoading,
error,
getVersion,
createVersion,
isCreatingVersion,
rollback,
isRollingBack,
compareVersions,
} = useWorkflowVersions(ruleId);
Parameters:
ruleId: string | undefined - Automation rule ID
Returns:
versions: WorkflowVersion[] - All versions for the rule (newest first)
isLoading: boolean - Loading state for initial fetch
error: Error | null - Error state
getVersion: (version: number) => Promise<WorkflowVersion | null> - Fetch specific version
createVersion: (options: CreateVersionOptions) => Promise<number> - Create new version snapshot
isCreatingVersion: boolean - Creating version loading state
rollback: (options: RollbackOptions) => Promise<void> - Rollback to previous version
isRollingBack: boolean - Rollback loading state
compareVersions: (versionA: number, versionB: number) => Promise<VersionDiff> - Compare two versions
Types:
interface WorkflowVersion {
id: string;
organization_id: string;
rule_id: string;
version: number;
published_by: string;
published_at: string;
workflow_snapshot: {
nodes: WorkflowNode[];
edges: WorkflowEdge[];
viewport?: { x: number; y: number; zoom: number };
};
notes?: string;
tags?: string[];
created_at: string;
}
interface CreateVersionOptions {
notes?: string;
tags?: string[];
}
interface RollbackOptions {
target_version: number;
notes?: string;
}
interface VersionDiff {
versionA: WorkflowVersion;
versionB: WorkflowVersion;
diff: {
nodes: {
added: WorkflowNode[];
removed: WorkflowNode[];
modified: WorkflowNode[];
};
edges: {
added: WorkflowEdge[];
removed: WorkflowEdge[];
};
};
}
Examples:
// Create new version
const versionNum = await createVersion({
notes: 'Added approval gates for budget requests',
tags: ['production', 'v2.1']
});
console.log(`Created version ${versionNum}`);
// Rollback to version 2
await rollback({
target_version: 2,
notes: 'Emergency rollback - approval node timeout issue'
});
// Compare current version with version 2
const diff = await compareVersions(2, 4);
console.log('Added nodes:', diff.diff.nodes.added.length);
console.log('Removed nodes:', diff.diff.nodes.removed.length);
console.log('Modified nodes:', diff.diff.nodes.modified.length);
// Get specific version
const version = await getVersion(3);
console.log('Published by:', version.published_by);
console.log('Published at:', version.published_at);
console.log('Nodes:', version.workflow_snapshot.nodes.length);
TypeScript Types
Node Types
interface WorkflowNode {
id: string;
type: 'start' | 'action' | 'branch' | 'switch' | 'loop' | 'parallel_fork' | 'parallel_join' | 'approval' | 'subflow' | 'delay' | 'end';
position: { x: number; y: number };
data: NodeData;
}
// Node-specific data types
interface StartNodeData {
label?: string;
}
interface ActionNodeData {
label?: string;
actionType: 'send_email' | 'send_notification' | 'update_record' | 'create_record' | 'call_webhook';
config: Record<string, any>;
}
interface BranchNodeData {
label?: string;
conditions: BranchCondition[];
}
interface BranchCondition {
field: string;
operator: 'equals' | 'not_equals' | 'contains' | 'greater_than' | 'less_than' | 'is_empty';
value: any;
}
interface SwitchNodeData {
label?: string;
switchField: string;
cases: SwitchCase[];
}
interface SwitchCase {
value: any;
label?: string;
}
interface LoopNodeData {
label?: string;
loopType: 'for_each' | 'while';
collectionField: string;
itemVariable: string;
maxIterations: number;
}
interface ApprovalNodeData {
label?: string;
assigneeUser?: string;
assigneeRole?: string;
instructions?: string;
timeoutHours?: number;
timeoutAction?: 'approve' | 'reject';
}
interface SubflowNodeData {
label?: string;
subflowId: string;
inputMapping: Record<string, string>;
outputMapping: Record<string, string>;
}
Workflow Execution Types
interface WorkflowExecution {
id: string;
rule_id: string;
organization_id: string;
status: 'running' | 'completed' | 'paused' | 'failed' | 'cancelled';
started_at: string;
completed_at?: string;
paused_at?: string;
resumed_at?: string;
current_node_id?: string;
error_node_id?: string;
error_message?: string;
node_states: Record<string, any>;
execution_path: string[];
variables: Record<string, any>;
parallel_branches: any[];
retry_count: number;
}
interface WorkflowApproval {
id: string;
execution_id: string;
node_id: string;
organization_id: string;
status: 'pending' | 'approved' | 'rejected' | 'timeout';
assignee_user_id?: string;
assignee_role?: string;
decided_by?: string;
decided_at?: string;
decision_notes?: string;
timeout_at?: string;
timeout_action?: string;
created_at: string;
}
Subflow Types
interface Subflow {
id: string;
organization_id: string;
name: string;
description?: string;
nodes: WorkflowNode[];
edges: WorkflowEdge[];
viewport?: Viewport;
input_schema: SubflowParameter[];
output_schema: SubflowParameter[];
usage_count: number;
created_at: string;
updated_at: string;
created_by: string;
updated_by?: string;
}
interface SubflowParameter {
name: string;
type: 'string' | 'number' | 'boolean' | 'object' | 'array';
required: boolean;
default?: any;
description?: string;
}
Edge Function API
POST /automation-executor
Execute workflow based on trigger data.
Endpoint: https://{project-ref}.supabase.co/functions/v1/automation-executor
Headers:
Authorization: Bearer {anon-key}
Content-Type: application/json
Request Body:
{
trigger_data: {
trigger_type: 'form_submitted' | 'form_updated' | 'schedule' | 'webhook' | 'manual';
submission_id: string;
form_id: string;
organization_id: string;
site_id?: string;
submitted_by?: string;
submission_data: Record<string, any>;
old_status?: string;
new_status?: string;
},
dry_run?: boolean; // Test mode (no actions executed)
}
Response:
{
success: boolean;
dry_run: boolean;
rules_evaluated: number;
results: Array<{
rule_id: string;
rule_name: string;
workflow_execution?: boolean;
success: boolean;
nodes_executed?: number;
node_states?: Record<string, any>;
error?: string;
}>;
}
Database Schema
fw_workflow_definitions
CREATE TABLE fw_workflow_definitions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
organization_id UUID NOT NULL REFERENCES pf_organizations(id),
rule_id UUID NOT NULL REFERENCES fw_automation_rules(id),
nodes JSONB NOT NULL DEFAULT '[]',
edges JSONB NOT NULL DEFAULT '[]',
viewport JSONB,
version INTEGER NOT NULL DEFAULT 1,
custom_fields JSONB NOT NULL DEFAULT '{}',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
created_by UUID NOT NULL REFERENCES pf_profiles(id),
updated_by UUID REFERENCES pf_profiles(id),
UNIQUE(rule_id, version)
);
fw_workflow_executions
CREATE TABLE fw_workflow_executions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
rule_id UUID NOT NULL REFERENCES fw_automation_rules(id),
organization_id UUID NOT NULL REFERENCES pf_organizations(id),
log_id UUID REFERENCES fw_automation_logs(id),
status TEXT NOT NULL DEFAULT 'running',
started_at TIMESTAMPTZ NOT NULL DEFAULT now(),
completed_at TIMESTAMPTZ,
paused_at TIMESTAMPTZ,
resumed_at TIMESTAMPTZ,
current_node_id TEXT,
error_node_id TEXT,
error_message TEXT,
node_states JSONB NOT NULL DEFAULT '{}',
execution_path JSONB NOT NULL DEFAULT '[]',
variables JSONB NOT NULL DEFAULT '{}',
parallel_branches JSONB NOT NULL DEFAULT '[]',
retry_count INTEGER NOT NULL DEFAULT 0,
custom_fields JSONB NOT NULL DEFAULT '{}'
);
fw_subflows
CREATE TABLE fw_subflows (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
organization_id UUID NOT NULL REFERENCES pf_organizations(id),
name TEXT NOT NULL,
description TEXT,
nodes JSONB NOT NULL DEFAULT '[]',
edges JSONB NOT NULL DEFAULT '[]',
viewport JSONB,
input_schema JSONB NOT NULL DEFAULT '[]',
output_schema JSONB NOT NULL DEFAULT '[]',
usage_count INTEGER NOT NULL DEFAULT 0,
custom_fields JSONB NOT NULL DEFAULT '{}',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
created_by UUID NOT NULL REFERENCES pf_profiles(id),
updated_by UUID REFERENCES pf_profiles(id)
);
Examples
Creating a Simple Workflow Programmatically
const nodes = [
{
id: '1',
type: 'start',
position: { x: 0, y: 0 },
data: { label: 'Start' }
},
{
id: '2',
type: 'action',
position: { x: 0, y: 100 },
data: {
label: 'Send Email',
actionType: 'send_email',
config: {
to: '{{submission_data.email}}',
subject: 'Form Received',
body: 'Thank you for your submission'
}
}
},
{
id: '3',
type: 'end',
position: { x: 0, y: 200 },
data: { label: 'End' }
}
];
const edges = [
{ id: 'e1-2', source: '1', target: '2' },
{ id: 'e2-3', source: '2', target: '3' }
];
await saveDefinition(nodes, edges);
Triggering a Workflow
const { data, error } = await supabase.functions.invoke('automation-executor', {
body: {
trigger_data: {
trigger_type: 'form_submitted',
submission_id: 'sub-123',
form_id: 'form-456',
organization_id: 'org-789',
submitted_by: 'user-abc',
submission_data: {
email: 'user@example.com',
name: 'John Doe'
}
},
dry_run: false
}
});
Monitoring Execution
const { data: execution } = useExecutionTrace(executionId);
// Check status
if (execution.status === 'paused') {
// Find approval task
const approval = execution.node_states[execution.current_node_id];
console.log('Waiting for approval:', approval);
}
// Check for errors
if (execution.status === 'failed') {
console.error('Failed at node:', execution.error_node_id);
console.error('Error:', execution.error_message);
}
Best Practices
- Keep workflows under 50 nodes for optimal performance
- Use parallel execution for independent actions
- Set reasonable
maxIterations on loops
- Lazy load node configuration forms
Error Handling
- Always validate workflows before execution
- Provide default/else paths in branches
- Set timeouts on approval nodes
- Use try-catch in custom functions
Security
- Validate all user inputs
- Use RLS policies on all tables
- Sanitize dynamic values in emails/webhooks
- Audit approval decisions
Maintainability
- Use descriptive node labels
- Extract reusable logic into subflows
- Document complex workflows
- Version control workflow definitions
Support
For additional API documentation and support:
- Review workflow examples in
workflow-examples.md
- Check the user guide in
workflow-builder-guide.md
- Contact technical support for assistance