Architecture
Use a restricted workflow DSL in Dart. A workflow function may use normal control flow, but every durable boundary goes through WorkflowContext:
serviceTask/activityfor I/O and side effects;userTaskfor assigned work;waitForSignalfor external events;sleepfor durable time;- a stable operation
idon every await.
Direct I/O, wall-clock reads, randomness, mutable globals, and unregistered futures are forbidden in orchestration code.
WorkflowRuntime is the canonical runtime. LegacyWorkflowEngine is the graph compatibility surface for in-flight product runs.
Component Split
| Component | Owns | Must not own |
|---|---|---|
| Workflow definition | Deterministic orchestration and await IDs | I/O, clocks, randomness |
| Decider / runtime | Replay, commands, retries, status | Business side effects or SQL |
| Activity worker | Versioned handlers, heartbeats, idempotency | Workflow control-flow state |
| User-task API | Assignment, completion, validation, expiry | A long-lived process |
| Storage interface | Atomic run/history/command transitions | Supabase-specific SQL |
| Postgres adapter | Transactions, row locks, SKIP LOCKED, fencing | Workflow-domain branching |
| Timer / recovery | Timers, expiry, expired leases, interrupted decisions | Arbitrary business code |
| Designer | Constrained document and visualization | Runtime state |
API, decider, worker, and recovery roles can be separate processes or one WorkflowServerApplication. Correctness comes from storage contracts, not from which replica handled the last request.
Progress Model
history.sequenceis the ordered audit trail.runs.revisionfences concurrent decisions.- commands are pending, claimed, completed, failed, or cancelled.
operationKeyidentifies a logical await across replay.claimGenerationfences stale workers after lease reassignment.
blocked is healthy. It means the run is waiting for durable external work.
Definition Digest
A run stores code, version, and digest. Workers reject a digest mismatch instead of replaying history against changed logic. Changing behavior requires a new version.
Visualization
Arbitrary Dart cannot be converted into a complete graph. Attach an optional WorkflowDocument when you need a pre-run inspector map. Without it, the inspector builds an observed operation map from history as the run executes.