Repository navigation
Data Model
Yash Aryan edited this page Oct 9, 2026
·
3 revisions
Run status map: Job run status lifecycle · Definition sync: Job definition and log data flow · ADR-004 — Immutable job versions
PostgreSQL. IDs are ULIDs stored as text (sortable, agent-generatable). Timestamps are timestamptz. JSON is jsonb. Spec: docs/data-model.md. Schema evolves via numbered files in migrations/.
Multi-tenancy is deferred. One deployment is one tenant; org_id can be added later.
| Entity | Role |
|---|---|
| user | Person who logs in (email, password hash or SSO-only, role) |
| server | Target machine, 1:1 with an agent (pending / online / offline, cert fingerprint, labels, last seen) |
| enrollment_token | One-time secret (hash only) to bind an agent to a server |
| job | Schedule + options + target (server or labels) + pointer to current version |
| job_version | Immutable snapshot of script and non-secret env. Edits insert a new row |
| secret | Encrypted value (value_enc), scoped global / server / job |
| run | One execution: trigger, status, timing, exit code. ID may be agent-generated |
| run_log | Chunked stdout/stderr, capped per run |
| api_token | Programmatic access (hash only) |
| audit_log | Who did what |
| notification_target | Webhook / Slack / email, optional label and status filters |
| job_template | Built-in or user-saved starting points for the wizard |
| connector / connector_operation / snapshots | Portal management of nginx, systemd, Docker, pm2 |
-
Job versions are immutable. Editing a script never mutates a row. A run always points at the exact
job_version_idit executed. -
Run IDs can be agent-generated. Offline agents upload later; the control plane upserts by
id. -
Logs live in Postgres up to
RUN_LOG_MAX_BYTES, then a truncation marker. Object storage is not built. - Secrets store ciphertext only. Decrypt at sync time over mTLS. See Security.
-
Label targeting.
jobs.server_idmay be null;target_kind = 'labels'plus jsonb selector, resolved at sync and run-now time. Deleting a server SET NULL rather than cascading those jobs.
pending | running | succeeded | failed | timed_out | canceled | skipped
Triggers: schedule | manual | api.
| File | What it added |
|---|---|
0001_init.sql |
Phase 1 schema |
0002_agent_token.sql |
Legacy bearer column (mTLS uses fingerprint) |
0003_notifications.sql |
Webhook targets |
0004_labels_and_limits.sql |
Label targeting, CPU/memory columns |
0005_connectors.sql |
Connector registry |
0006_connector_ops.sql |
Connector operations |
0007_notify_channels.sql |
Slack / email channels |
0008_job_templates.sql |
Templates + six built-ins |
0009_job_limits.sql |
Extra job resource limits |
0010_retention_indexes.sql |
Indexes for the retention pruner |
Apply with the bundled migrate tool before rolling the control plane. No automatic down-migration — restore from pg_dump.