Flow Workflows
Flow workflows enable you to create complex, multi-step user processes using@databite/flow
. This guide shows you how to build sophisticated workflows for user onboarding, data processing, approval processes, and more.
Overview
Flow workflows in Databite provide:- Multi-step Processes with conditional logic
- User Interactions through forms, confirmations, and displays
- API Integration with external services
- Data Transformation and validation
- Error Handling and recovery
- State Management across workflow steps
Basic Workflow Structure
Simple Linear Workflow
Copy
Ask AI
import { FlowBuilder } from "@databite/flow";
const onboardingFlow = new FlowBuilder()
.generic("welcome", {
title: "Welcome to Our Service",
description: "Let's get you set up with your account",
buttonText: "Get Started",
action: "collect_info",
})
.form("collect_info", {
title: "Your Information",
description: "Please provide some basic information",
fields: [
{
name: "name",
type: "string",
label: "Full Name",
required: true,
},
{
name: "email",
type: "email",
label: "Email Address",
required: true,
},
{
name: "company",
type: "string",
label: "Company",
required: false,
},
],
submitText: "Continue",
action: "verify_email",
})
.http("verify_email", {
method: "POST",
url: "https://api.service.com/verify-email",
body: {
email: "{{form.email}}",
name: "{{form.name}}",
},
})
.confirm("email_sent", {
title: "Check Your Email",
description: "We've sent a verification link to {{form.email}}",
confirmText: "I've verified my email",
action: "complete_onboarding",
})
.transform("complete_onboarding", {
user_id: "{{response.user_id}}",
name: "{{form.name}}",
email: "{{form.email}}",
company: "{{form.company}}",
status: "verified",
})
.build();
Conditional Workflow
Copy
Ask AI
const conditionalFlow = new FlowBuilder()
.generic("start", {
title: "Choose Your Path",
description: "What would you like to do?",
buttonText: "Continue",
action: "select_option",
})
.form("select_option", {
title: "Select Option",
description: "Choose an option to proceed",
fields: [
{
name: "option",
type: "select",
label: "Option",
required: true,
options: [
{ value: "basic", label: "Basic Setup" },
{ value: "advanced", label: "Advanced Setup" },
{ value: "custom", label: "Custom Setup" },
],
},
],
submitText: "Continue",
action: "route_option",
})
.generic("route_option", {
title: "Routing...",
description: "Processing your selection...",
buttonText: "Continue",
action: "{{form.option}}_setup",
})
.form("basic_setup", {
title: "Basic Setup",
description: "Configure basic settings",
fields: [
{
name: "setting1",
type: "string",
label: "Setting 1",
required: true,
},
],
submitText: "Complete",
action: "finish",
})
.form("advanced_setup", {
title: "Advanced Setup",
description: "Configure advanced settings",
fields: [
{
name: "setting1",
type: "string",
label: "Setting 1",
required: true,
},
{
name: "setting2",
type: "string",
label: "Setting 2",
required: true,
},
{
name: "setting3",
type: "boolean",
label: "Enable Feature",
required: false,
},
],
submitText: "Complete",
action: "finish",
})
.form("custom_setup", {
title: "Custom Setup",
description: "Configure custom settings",
fields: [
{
name: "custom_config",
type: "textarea",
label: "Custom Configuration",
required: true,
placeholder: "Enter your custom configuration...",
},
],
submitText: "Complete",
action: "finish",
})
.transform("finish", {
setup_type: "{{form.option}}",
completed_at: "{{now}}",
status: "completed",
})
.build();
Advanced Workflow Patterns
Approval Workflow
Copy
Ask AI
const approvalFlow = new FlowBuilder()
.form("submit_request", {
title: "Submit Request",
description: "Submit your request for approval",
fields: [
{
name: "title",
type: "string",
label: "Request Title",
required: true,
},
{
name: "description",
type: "textarea",
label: "Description",
required: true,
},
{
name: "amount",
type: "number",
label: "Amount",
required: true,
minimum: 0,
},
{
name: "priority",
type: "select",
label: "Priority",
required: true,
options: [
{ value: "low", label: "Low" },
{ value: "medium", label: "Medium" },
{ value: "high", label: "High" },
],
},
],
submitText: "Submit Request",
action: "create_request",
})
.http("create_request", {
method: "POST",
url: "https://api.service.com/requests",
body: {
title: "{{form.title}}",
description: "{{form.description}}",
amount: "{{form.amount}}",
priority: "{{form.priority}}",
status: "pending",
},
})
.transform("extract_request_id", {
request_id: "{{response.id}}",
title: "{{form.title}}",
amount: "{{form.amount}}",
priority: "{{form.priority}}",
})
.generic("request_submitted", {
title: "Request Submitted",
description:
"Your request has been submitted and is pending approval. Request ID: {{request_id}}",
buttonText: "View Status",
action: "check_status",
})
.http("check_status", {
method: "GET",
url: "https://api.service.com/requests/{{request_id}}",
})
.generic("status_display", {
title: "Request Status",
description: "Status: {{response.status}}",
buttonText: "Refresh",
action: "check_status",
})
.build();
Multi-User Workflow
Copy
Ask AI
const multiUserFlow = new FlowBuilder()
.form("initiate_process", {
title: "Initiate Process",
description: "Start a multi-user process",
fields: [
{
name: "process_name",
type: "string",
label: "Process Name",
required: true,
},
{
name: "participants",
type: "array",
label: "Participants",
required: true,
itemSchema: {
type: "object",
properties: {
email: { type: "string" },
role: { type: "string" },
},
},
},
],
submitText: "Start Process",
action: "create_process",
})
.http("create_process", {
method: "POST",
url: "https://api.service.com/processes",
body: {
name: "{{form.process_name}}",
participants: "{{form.participants}}",
status: "active",
},
})
.transform("extract_process_id", {
process_id: "{{response.id}}",
name: "{{form.process_name}}",
participants: "{{form.participants}}",
})
.generic("process_created", {
title: "Process Created",
description:
'Process "{{name}}" has been created and participants have been notified.',
buttonText: "View Process",
action: "view_process",
})
.http("view_process", {
method: "GET",
url: "https://api.service.com/processes/{{process_id}}",
})
.generic("process_status", {
title: "Process Status",
description:
"Process: {{response.name}}<br/>Status: {{response.status}}<br/>Participants: {{response.participants.length}}",
buttonText: "Refresh",
action: "view_process",
})
.build();
Data Processing Workflows
ETL Workflow
Copy
Ask AI
const etlFlow = new FlowBuilder()
.form("configure_etl", {
title: "Configure ETL Process",
description:
"Set up your data extraction, transformation, and loading process",
fields: [
{
name: "source_type",
type: "select",
label: "Source Type",
required: true,
options: [
{ value: "api", label: "API" },
{ value: "database", label: "Database" },
{ value: "file", label: "File Upload" },
],
},
{
name: "source_config",
type: "object",
label: "Source Configuration",
required: true,
schema: {
type: "object",
properties: {
url: { type: "string" },
credentials: { type: "object" },
},
},
},
{
name: "transformations",
type: "array",
label: "Transformations",
required: false,
itemSchema: {
type: "object",
properties: {
field: { type: "string" },
operation: { type: "string" },
value: { type: "string" },
},
},
},
],
submitText: "Start ETL",
action: "execute_etl",
})
.http("execute_etl", {
method: "POST",
url: "https://api.service.com/etl/execute",
body: {
source_type: "{{form.source_type}}",
source_config: "{{form.source_config}}",
transformations: "{{form.transformations}}",
},
})
.transform("extract_job_id", {
job_id: "{{response.job_id}}",
status: "{{response.status}}",
})
.generic("etl_started", {
title: "ETL Process Started",
description: "Your ETL process has been started. Job ID: {{job_id}}",
buttonText: "Monitor Progress",
action: "monitor_progress",
})
.http("monitor_progress", {
method: "GET",
url: "https://api.service.com/etl/jobs/{{job_id}}",
})
.generic("progress_display", {
title: "ETL Progress",
description:
"Status: {{response.status}}<br/>Progress: {{response.progress}}%<br/>Records Processed: {{response.records_processed}}",
buttonText: "Refresh",
action: "monitor_progress",
})
.build();
Data Validation Workflow
Copy
Ask AI
const validationFlow = new FlowBuilder()
.form("upload_data", {
title: "Upload Data",
description: "Upload your data file for validation",
fields: [
{
name: "file",
type: "file",
label: "Data File",
required: true,
accept: ".csv,.json,.xlsx",
},
{
name: "validation_rules",
type: "object",
label: "Validation Rules",
required: false,
schema: {
type: "object",
properties: {
required_fields: { type: "array" },
data_types: { type: "object" },
constraints: { type: "object" },
},
},
},
],
submitText: "Validate Data",
action: "validate_data",
})
.http("validate_data", {
method: "POST",
url: "https://api.service.com/validate",
body: {
file: "{{form.file}}",
rules: "{{form.validation_rules}}",
},
})
.transform("extract_validation_results", {
validation_id: "{{response.validation_id}}",
status: "{{response.status}}",
errors: "{{response.errors}}",
warnings: "{{response.warnings}}",
})
.generic("validation_results", {
title: "Validation Results",
description:
"Status: {{status}}<br/>Errors: {{errors.length}}<br/>Warnings: {{warnings.length}}",
buttonText: "View Details",
action: "view_details",
})
.http("view_details", {
method: "GET",
url: "https://api.service.com/validate/{{validation_id}}/details",
})
.generic("detailed_results", {
title: "Detailed Validation Results",
description: "{{response.details}}",
buttonText: "Fix Issues",
action: "fix_issues",
})
.build();
Error Handling and Recovery
Robust Error Handling
Copy
Ask AI
const robustFlow = new FlowBuilder()
.generic("start", {
title: "Start Process",
description: "Click to start the process",
buttonText: "Start",
action: "api_call",
})
.http("api_call", {
method: "GET",
url: "https://api.service.com/data",
headers: {
Authorization: "Bearer {{tokens.api_key}}",
},
onError: "handle_api_error",
})
.generic("handle_api_error", {
title: "API Error",
description: "The API call failed. Would you like to retry?",
buttonText: "Retry",
action: "api_call",
})
.generic("handle_network_error", {
title: "Network Error",
description:
"Network connection failed. Please check your internet connection and try again.",
buttonText: "Retry",
action: "api_call",
})
.generic("handle_auth_error", {
title: "Authentication Error",
description: "Authentication failed. Please check your credentials.",
buttonText: "Re-authenticate",
action: "re_auth",
})
.form("re_auth", {
title: "Re-authenticate",
description: "Please enter your credentials again",
fields: [
{
name: "api_key",
type: "password",
label: "API Key",
required: true,
},
],
submitText: "Authenticate",
action: "api_call",
})
.transform("process_data", {
result: "{{response.data}}",
processed_at: "{{now}}",
})
.build();
Retry Logic
Copy
Ask AI
const retryFlow = new FlowBuilder()
.generic("start", {
title: "Start Process",
description: "Click to start the process",
buttonText: "Start",
action: "api_call_with_retry",
})
.http("api_call_with_retry", {
method: "GET",
url: "https://api.service.com/data",
retry: {
attempts: 3,
delay: 1000,
backoff: "exponential",
},
onError: "handle_retry_exhausted",
})
.generic("handle_retry_exhausted", {
title: "Retry Exhausted",
description:
"All retry attempts have been exhausted. Please try again later or contact support.",
buttonText: "Try Again",
action: "api_call_with_retry",
})
.transform("process_data", {
result: "{{response.data}}",
processed_at: "{{now}}",
})
.build();
React Integration
FlowRenderer Component
Copy
Ask AI
import React from "react";
import { FlowRenderer, useFlowExecution } from "@databite/flow/react";
function WorkflowComponent() {
const { executeFlow, state, error } = useFlowExecution(approvalFlow);
const handleStart = () => {
executeFlow({
config: {
apiUrl: "https://api.service.com",
},
});
};
return (
<div>
<button onClick={handleStart}>Start Workflow</button>
<FlowRenderer flow={approvalFlow} state={state} onAction={executeFlow} />
{error && <div className="error">Error: {error.message}</div>}
</div>
);
}
Custom Flow Components
Copy
Ask AI
import React from "react";
import { FlowBlock, FlowState } from "@databite/flow";
interface CustomWorkflowBlockProps {
block: FlowBlock;
state: FlowState;
onAction: (action: string, data?: any) => void;
}
function CustomWorkflowBlock({
block,
state,
onAction,
}: CustomWorkflowBlockProps) {
const handleAction = (action: string, data?: any) => {
onAction(action, data);
};
return (
<div className="custom-workflow-block">
<h3>{block.title}</h3>
<p>{block.description}</p>
{block.type === "form" && (
<form
onSubmit={(e) => {
e.preventDefault();
handleAction(block.action, new FormData(e.currentTarget));
}}
>
{block.fields?.map((field) => (
<div key={field.name}>
<label htmlFor={field.name}>{field.label}</label>
<input
id={field.name}
name={field.name}
type={field.type}
required={field.required}
/>
</div>
))}
<button type="submit">{block.submitText}</button>
</form>
)}
{block.type === "generic" && (
<button onClick={() => handleAction(block.action)}>
{block.buttonText}
</button>
)}
</div>
);
}
// Register custom component
FlowRenderer.registerComponent("custom_workflow", CustomWorkflowBlock);
Testing Workflows
Unit Testing
Copy
Ask AI
import { FlowBuilder } from "@databite/flow";
describe("Workflow Testing", () => {
it("should execute workflow successfully", async () => {
const flow = new FlowBuilder()
.generic("start", {
title: "Start",
action: "process",
})
.transform("process", {
result: "success",
})
.build();
const result = await flow.execute({
config: {},
});
expect(result.success).toBe(true);
expect(result.data.result).toBe("success");
});
it("should handle errors gracefully", async () => {
const flow = new FlowBuilder()
.generic("start", {
title: "Start",
action: "error_step",
})
.generic("error_step", {
title: "Error",
action: "handle_error",
})
.generic("handle_error", {
title: "Error Handled",
action: "finish",
})
.build();
const result = await flow.execute({
config: {},
});
expect(result.success).toBe(true);
});
});
Integration Testing
Copy
Ask AI
describe("Workflow Integration", () => {
it("should complete full workflow", async () => {
const flow = new FlowBuilder()
.form("collect_data", {
title: "Collect Data",
fields: [
{
name: "input",
type: "string",
label: "Input",
required: true,
},
],
submitText: "Submit",
action: "process_data",
})
.http("process_data", {
method: "POST",
url: "https://api.service.com/process",
body: {
input: "{{form.input}}",
},
})
.transform("extract_result", {
result: "{{response.result}}",
})
.build();
const result = await flow.execute({
config: {
apiUrl: "https://api.service.com",
},
form: {
input: "test",
},
});
expect(result.success).toBe(true);
expect(result.data.result).toBeDefined();
});
});
Best Practices
Workflow Design
Keep workflows focused and single-purpose. Break complex processes into
smaller, manageable workflows.
Copy
Ask AI
// ✅ Good: Focused workflow
const userOnboardingFlow = new FlowBuilder()
.form("collect_info", {
/* collect user info */
})
.http("create_account", {
/* create account */
})
.build();
// ✅ Good: Separate workflow for verification
const emailVerificationFlow = new FlowBuilder()
.http("send_verification", {
/* send email */
})
.confirm("verify_email", {
/* confirm verification */
})
.build();
// ❌ Bad: Monolithic workflow
const everythingFlow = new FlowBuilder()
.form("collect_info", {
/* collect user info */
})
.http("create_account", {
/* create account */
})
.http("send_verification", {
/* send email */
})
.confirm("verify_email", {
/* confirm verification */
})
.form("setup_preferences", {
/* setup preferences */
})
.http("send_welcome", {
/* send welcome email */
})
.build();
Error Handling Strategy
Always implement comprehensive error handling in your workflows to provide a
good user experience.
Copy
Ask AI
const errorHandlingFlow = new FlowBuilder()
.generic("start", {
title: "Start Process",
action: "api_call",
})
.http("api_call", {
method: "GET",
url: "https://api.service.com/data",
onError: "handle_error",
})
.generic("handle_error", {
title: "Error Occurred",
description: "An error occurred. Please try again or contact support.",
buttonText: "Retry",
action: "api_call",
})
.build();
State Management
Copy
Ask AI
const statefulFlow = new FlowBuilder()
.form("step1", {
title: "Step 1",
fields: [
{
name: "data1",
type: "string",
label: "Data 1",
required: true,
},
],
submitText: "Next",
action: "step2",
})
.form("step2", {
title: "Step 2",
description: "Previous data: {{form.data1}}",
fields: [
{
name: "data2",
type: "string",
label: "Data 2",
required: true,
},
],
submitText: "Next",
action: "step3",
})
.form("step3", {
title: "Step 3",
description: "Data 1: {{form.data1}}, Data 2: {{form.data2}}",
fields: [
{
name: "data3",
type: "string",
label: "Data 3",
required: true,
},
],
submitText: "Complete",
action: "finish",
})
.build();
Common Issues and Solutions
Issue: Workflow State Management
Use proper state management to maintain data across workflow steps and handle
user navigation.
Copy
Ask AI
// ✅ Good: Proper state management
const statefulFlow = new FlowBuilder()
.form("step1", {
title: "Step 1",
fields: [
{
name: "data1",
type: "string",
label: "Data 1",
required: true,
},
],
submitText: "Next",
action: "step2",
})
.form("step2", {
title: "Step 2",
description: "Previous data: {{form.data1}}",
fields: [
{
name: "data2",
type: "string",
label: "Data 2",
required: true,
},
],
submitText: "Next",
action: "step3",
})
.build();
Issue: Error Recovery
Copy
Ask AI
// ✅ Good: Comprehensive error recovery
const errorRecoveryFlow = new FlowBuilder()
.generic("start", {
title: "Start Process",
action: "api_call",
})
.http("api_call", {
method: "GET",
url: "https://api.service.com/data",
onError: "handle_error",
})
.generic("handle_error", {
title: "Error Occurred",
description: "An error occurred. Please try again or contact support.",
buttonText: "Retry",
action: "api_call",
})
.build();
Next Steps
Now that you understand flow workflows, you can:- Build Complex Processes: Create sophisticated multi-step workflows
- Implement Error Handling: Add robust error handling and recovery
- Optimize User Experience: Improve workflow usability and performance
- Add Testing: Implement comprehensive testing for your workflows