ServerFlows
Persistence & State
Schema architecture, idempotency, and FlowRepo service for database operations.
Schema Architecture
Flow definitions and runtime state are stored in PostgreSQL via Prisma:
| Model | Purpose |
|---|---|
Flow | Top-level container for a workflow |
FlowVersion | JSON graph (nodes + edges); only ACTIVE version executes |
FlowRun | Single execution instance |
FlowExecutionNode | Detailed logs per node (input/output/errors) |
FlowDeadLetter | Failed executions for debugging/retry |
Schema Relationships
FlowRepo Service
Located in flow-repo.ts, this service is the only component performing raw DB writes for the engine.
Key Operations
// Create a new execution
const run = await flowRepo.createRun({
flowId: "flow_123",
versionId: "version_456",
idempotencyKey: "req_abc",
triggerEvent: { userId: "user_789" },
});
// Update node status
await flowRepo.updateNodeStatus({
nodeId: "node_abc",
status: "SUCCESS",
output: { result: "..." },
});Idempotency
To prevent duplicate executions from network retries:
// Check before creating run
const existing = await flowRepo.findByIdempotencyKey(key, versionId);
if (existing) {
return existing; // Return existing result
}
// Create new run
const run = await flowRepo.createRun({ ... });Transaction Management
// Ensure atomicity of run + first node creation
Effect.withTransaction(tx => {
await flowRepo.createRun(tx, runData);
await flowRepo.createNode(tx, nodeData);
});State Enums
enum FlowStatus {
DRAFT = "DRAFT",
ACTIVE = "ACTIVE",
PAUSED = "PAUSED",
ARCHIVED = "ARCHIVED",
}
enum RunStatus {
PENDING = "PENDING",
RUNNING = "RUNNING",
COMPLETED = "COMPLETED",
FAILED = "FAILED",
DEAD_LETTER = "DEAD_LETTER",
}
enum NodeStatus {
PENDING = "PENDING",
RUNNING = "RUNNING",
SUCCESS = "SUCCESS",
FAILED = "FAILED",
}Storage Optimization
- Node logs: Use JSONB for input/output to save storage
- Version history: Retain last 10 versions for rollback
- Dead letter: Auto-purge after 30 days