Vyuh Workflow Engine
Business Process Orchestration
A powerful, extensible workflow engine for Dart and Flutter applications. Build complex business processes, approval flows, and stateful automations with a clean, composable API.
Why Workflow Engine?
Visual Process Modeling
Define executable workflows with a fluent builder or load persisted workflow definitions from storage.
Human-in-the-Loop
Built-in support for user tasks, approvals, and signal-based interactions.
Persistent State
Storage repositories persist definitions, instances, user tasks, and append-only workflow events.
Fully Extensible
Type registries for custom task executors, conditions, signals, and more.
Getting Started
Core Concepts
- Workflow — The blueprint for your business process
- Workflow Instance — A running execution of a workflow
- Workflow Descriptor — Register executors with the engine
- Tokens — Track execution position through the graph
- Data Flow — How data moves through your workflow
- Type Registries — Extend the engine with custom executors
Node Types
| Node | Purpose |
|---|---|
| Start/End | Entry and exit points |
| Task | Automated tasks |
| User Task | Human interactions |
| Signal Wait | Wait for external events |
| Gateways | Branching and merging |
Patterns & Examples
Control FlowBranching, looping, and parallel executionApprovalsCanonical CDX approval template and domain dispatchError HandlingCompensation and retry strategiesCDX IntegrationTemplates, Supabase, feature inboxes, protocol, and editor wiringSimple ApprovalBasic approval workflow exampleParallel TasksConcurrent task execution
Quick Example
dart
final context = RegistryTypeResolver(
descriptors: [DefaultWorkflowDescriptor()],
);
final engine = WorkflowEngine(
context: context,
storage: InMemoryStorage(),
executionMode: ExecutionMode.production,
);
await engine.initialize();
// Define a simple approval workflow
final workflow = WorkflowBuilder('expense-approval', 'Expense Approval')
.start('begin')
.task('validate-expense', execute: (ctx) async {
return {'valid': true};
})
.userTask('manager-review',
signal: 'approval_decision',
schemaType: 'userTask.approval',
assignToRole: 'managers',
storeAs: 'approvalResult')
.oneOf('decision', [
Branch.whenTrue('approvalResult.approved', then: 'process-payment'),
Branch.otherwise(then: 'notify-rejection'),
])
.task('process-payment', execute: (ctx) async {
return {'processed': true};
})
.end('completed')
.from('decision').to('notify-rejection')
.task('notify-rejection', execute: (ctx) async {
return {'notified': true};
})
.end('rejected')
.build();
// Register and start the workflow
engine.registerWorkflow(workflow);
final instance = await engine.startWorkflow(
workflowCode: workflow.code,
input: {'amount': 500, 'description': 'Conference travel'},
);For production CDX approvals, prefer the canonical ApprovalTemplate from cdx_workflow_templates and load its stored approval definition at boot. See Approval Workflows and CDX Integration.