Skip to main content

Node Configuration

Nodes are the building blocks of workflows. Each node type has specific properties and behaviors.

Node Properties

All nodes share common properties:

Basic Properties

  • Code (required) – Unique identifier within workflow
  • Name (required) – Display name
  • Label – Short label for UI
  • Description – Detailed description

Position

  • X, Y – Canvas coordinates (automatically set when dragging)

Data Properties

  • UI – UI configuration object
  • Exec – Execution configuration object
  • Actions – Array of action buttons
  • Input Handle – Input connection point
  • Output Handles – Output connection points

State Node

State nodes represent steps in the workflow that require user interaction.

UI Configuration

{
type: "MODEL_FORM" | "CUSTOM_FORM" | "OTP_FORM" | "PASSWORD_FORM" | "PIN_FORM" | "DISCLAIMER_PAGE" | "END_PAGE",
formClass?: string, // For CUSTOM_FORM
model?: string, // For MODEL_FORM
title?: string,
subtitle?: string,
fields?: FieldConfig[], // For MODEL_FORM
}

Run Type

  • "0" – UI mode (requires user interaction)
  • "1" – Exec mode (runs automatically)

Actions

Array of action buttons:

{
id: string,
code?: string,
name?: string,
label: string,
type: "NEXT" | "SKIP" | "SUBMIT" | "VERIFY" | "FUNCTION",
handle?: string, // Output handle to follow
url?: string, // API endpoint for SUBMIT
}

Example Configuration

{
code: "personal-data",
name: "Personal Data",
label: "Personal Info",
description: "Enter your personal information",
ui: {
type: "MODEL_FORM",
model: "Person",
title: "Personal Information",
subtitle: "Please fill in your details",
},
runType: "0",
actions: [
{
id: "next",
label: "Next",
type: "NEXT",
handle: "0",
},
],
}

Decision Node

Decision nodes branch workflows based on conditions.

Conditions

Array of conditions to evaluate:

{
field: string, // Field path in workflow values
operator: "equals" | "notEquals" | "greaterThan" | "lessThan" | "greaterThanOrEqual" | "lessThanOrEqual",
value: any, // Value to compare against
}

Output Handles

Each handle represents a condition outcome:

  • Handle "0" – First condition true
  • Handle "1" – Second condition true
  • Handle "default" – No conditions match

Example Configuration

{
code: "check-age",
name: "Check Age",
description: "Verify user is 18 or older",
conditions: [
{
field: "person.age",
operator: "greaterThanOrEqual",
value: 18,
},
],
outputHandles: [
{ id: "0", label: "Adult" },
{ id: "1", label: "Minor" },
],
}

Start Node

Entry point of workflow. Must have exactly one output handle.

Configuration

{
code: "start",
name: "Start",
description: "Workflow entry point",
}

End Node

Exit point of workflow.

Configuration

{
code: "end",
name: "End",
description: "Workflow completion",
ui: {
type: "END_PAGE",
title: "Complete",
message: "Thank you for completing the workflow",
},
}

UI Types

MODEL_FORM

Auto-generated form from model definition:

{
type: "MODEL_FORM",
model: "Person", // Model name from @xond/api
title: "Personal Information",
subtitle: "Enter your details",
fields: [
// Optional: override field configuration
{
fieldName: "name",
label: "Full Name",
fieldWidth: "wide",
},
],
}

CUSTOM_FORM

Custom React component:

{
type: "CUSTOM_FORM",
formClass: "PersonalDataForm", // Must be registered in FormRegistryContext
title: "Custom Form",
subtitle: "Custom form description",
}

OTP_FORM

One-time password input:

{
type: "OTP_FORM",
title: "Verify OTP",
subtitle: "Enter the code sent to your phone",
length: 6, // OTP length
fieldName: "otpCode", // Field name in workflow values
}

PASSWORD_FORM

Password input:

{
type: "PASSWORD_FORM",
title: "Set Password",
subtitle: "Choose a secure password",
fieldName: "password",
confirmFieldName: "confirmPassword",
}

PIN_FORM

PIN code input:

{
type: "PIN_FORM",
title: "Set PIN",
subtitle: "Enter a 6-digit PIN",
length: 6,
fieldName: "pin",
}

DISCLAIMER_PAGE

Terms and conditions page:

{
type: "DISCLAIMER_PAGE",
title: "Terms and Conditions",
content: "By proceeding, you agree to...",
checkboxLabel: "I agree to the terms",
fieldName: "agreed",
}

END_PAGE

Completion page:

{
type: "END_PAGE",
title: "Complete",
message: "Thank you for completing the workflow",
showActions: false, // Hide action buttons
}

Action Types

NEXT

Proceed to next node:

{
type: "NEXT",
label: "Next",
handle: "0", // Output handle to follow
}

SKIP

Skip to specified handle:

{
type: "SKIP",
label: "Skip",
handle: "1", // Output handle to skip to
}

SUBMIT

Submit data to API endpoint:

{
type: "SUBMIT",
label: "Submit",
url: "/api/submit",
handle: "0", // Output handle on success
}

VERIFY

Verify data (e.g., OTP):

{
type: "VERIFY",
label: "Verify",
url: "/api/verify-otp",
handle: "0", // Output handle on success
errorHandle: "1", // Output handle on failure
}

FUNCTION

Execute custom function:

{
type: "FUNCTION",
label: "Custom Action",
functionName: "customFunction",
handle: "0",
}

Workflow Values

Nodes can access values from previous nodes:

// Access values in conditions
{
field: "person.name", // Access person.name from workflow values
operator: "equals",
value: "John",
}

// Values are merged from all previous nodes
// Use copyToRoot: true to make values available to all subsequent nodes

Best Practices

  1. Use meaningful codes – Make node codes descriptive
  2. Add descriptions – Help users understand each step
  3. Configure UI properly – Set titles and subtitles for better UX
  4. Handle errors – Add error handles for SUBMIT and VERIFY actions
  5. Test conditions – Verify decision node conditions work correctly
  6. Use MODEL_FORM when possible – Leverage auto-generated forms
  7. Register custom forms – Add custom forms to FormRegistryContext

Next Steps