TEXT. Schema is managed by versioned SQL migrations (currently through the 000089_* series) that run automatically on startup.
Core Tables
Workflow Tables
Core Engine Tables
Key Columns
Relationships
- Jobs & Runs: A
jobhas manyjob_runs. Each run is linked to a specificjob_version. - Workflows: A
workflowhas manyworkflow_versions, and each version has manyworkflow_version_stepsused to materializeworkflow_step_runsat trigger time. - Workflow Governance:
workflow_policiesis one row per project and is enforced at workflow create/update/trigger boundaries. - Workflow Explainability:
workflow_step_decisionsstores progression decisions per run and powers/v1/workflow-runs/{id}/explain. - Environments:
jobsandjob_secretsare linked toenvironmentsfor configuration isolation.
Event Trigger Tables
event_triggers
Key Indexes
idx_event_triggers_status_expires:(status, expires_at) WHERE status = 'waiting'— Reaper timeout lookupidx_event_triggers_project_status:(project_id, status)— List queriesidx_event_triggers_event_key_prefix:(event_key text_pattern_ops)— Prefix matching for batch resolutionidx_event_triggers_step_run:(workflow_step_run_id) WHERE workflow_step_run_id IS NOT NULL— Step-to-trigger lookup
Performance Indexes
idx_workflow_runs_status_expires:(status, expires_at) WHERE expires_at IS NOT NULL— Reaper timeout lookupidx_workflow_runs_status_finished:(status, finished_at) WHERE finished_at IS NOT NULL— Retention deletionidx_step_runs_workflow_run_status:(workflow_run_id, status)— Step run queries by run and statusidx_step_decisions_step_run_id:(step_run_id)— CASCADE deletes on decisionsidx_job_runs_active_by_job:(job_id) WHERE status IN ('queued', 'dequeued', 'executing')— Active run counting
webhook_deliveries Extensions
Thewebhook_deliveries table (migration 000009, extended in 000061 and 000062) is shared between job run webhooks and event trigger webhooks:
idx_webhook_deliveries_pending:(next_retry_at ASC) WHERE status = 'pending'— Delivery worker queueidx_webhook_deliveries_run_seq:(run_id, sequence) WHERE run_id IS NOT NULL— Ordered delivery per runidx_webhook_deliveries_event_trigger:(event_trigger_id) WHERE event_trigger_id IS NOT NULLidx_webhook_deliveries_status_created:(status, created_at)
endpoint_circuit_state
The circuit breaker state table (migration 000022) tracks per-endpoint failure state:endpoint_health_scores
The endpoint health scoring table (migration 000120) tracks continuous health metrics per endpoint using EWMA:job_slos and job_slo_evaluations
SLO definitions and evaluation history (migration 000122):job_runs Key Indexes
idx_runs_queue_covering:(created_at ASC) INCLUDE (job_id, priority, scheduled_at, next_retry_at) WHERE status = 'queued'— Covering index for dequeueidx_runs_status_project_covering:(project_id, status, created_at DESC) INCLUDE (job_id, priority, scheduled_at, next_retry_at)— Covering index for list queriesidx_runs_heartbeat:(heartbeat_at) WHERE status = 'executing'— Stale run detectionidx_runs_expires:(expires_at) WHERE expires_at IS NOT NULL AND status IN ('delayed', 'queued')— Expiration reaperidx_job_runs_parent_run_id:(parent_run_id) WHERE parent_run_id IS NOT NULL— Parent-child lookupidx_runs_metadata: GIN index onmetadata(migration 000016) — JSONB filteringidx_jobs_tags: GIN index ontags(migration 000054) — Tag-based filtering
FK Constraints on job_runs
Important for partitioning considerations:job_runs.parent_run_id— Self-referential FK dropped in migration 000066 to support range partitioning. Integrity is enforced at the application layer.run_events.run_id— No ON DELETE clauserun_checkpoints.run_id— ON DELETE CASCADErun_usage.run_id— ON DELETE CASCADErun_tool_calls.run_id— ON DELETE CASCADErun_outputs.run_id— ON DELETE CASCADE
Miscellaneous Indexes
idx_idempotency_expires:(expires_at) WHERE expires_at IS NOT NULLonjob_run_idempotencyidx_audit_events_resource_lookup:(resource_type, resource_id)onaudit_eventsidx_webhook_subscriptions_project_active:(project_id, created_at DESC) WHERE active = TRUEonwebhook_subscriptions
Migrations
We usegolang-migrate for schema evolution.
Numbering Convention
Migrations follow a sequential 6-digit numbering scheme:000001_*.up.sql through the latest migration in the repository.
Recent Migrations
Adding New Migrations
- Create a new pair of SQL files in the
apps/strait/migrations/directory using the next sequence number:000090_your_feature.up.sql000090_your_feature.down.sql
- Ensure the migration is idempotent.
- The application will automatically detect and apply the new migration on the next startup.