67 docs indexed

Postgres Schema

All Postgres tables used by obleth, their columns, and the migration file that introduced each.

The base schema lives in schema/postgres/0001_init.sql. Incremental migrations are applied in order:

FileWhat it adds
0001_init.sqlFull initial schema (all tables and indexes)
0002_tracing_flag.sqltracing_enabled on tenants and api_keys
0003_guardrails_policy.sqlguardrails_policy on tenants
0004_saved_recipes.sqlsaved_recipes table (superseded by 0006)
0005_managed_launcher_spec.sqllauncher_spec on managed_models
0006_recipes.sqlrecipes table; drops saved_recipes
0007_replica_port_and_min_replicas.sqlport_base on model_replicas, min_replicas on managed_models
0008_managed_provision_error.sqllast_provision_error and last_provision_error_at on managed_models
0009_replica_cancel_requested.sqlcancel_requested on model_replicas
0010_drop_replica_model_cascade.sqlDrops the model_replicasmodels foreign key so replica rows outlive their model and the provisioner can still cancel their Slurm jobs
0011_endpoint_selection_session_hash.sqlWidens the endpoint_selection_mode check to accept session_hash
0012_model_debug_diagnostics.sqldebug_diagnostics on models
0013_compression_policy.sqlcompression_policy on tenants
0014_model_energy_slots.sqlenergy_slots_per_node on models
0015_tenant_synthetic.sqlsynthetic on tenants

Every statement is idempotent (create … if not exists / add column if not exists) and is applied automatically when the gateway boots, so all files are safe to re-run against an existing database.

Tables

tenants

Stores all tenants.

ColumnTypeNotes
idUUID PRIMARY KEY
nameTEXT NOT NULL UNIQUEHuman-readable name
weightBIGINT NOT NULL DEFAULT 100Fairshare weight (>= 1)
tokens_per_minuteBIGINT NOT NULL DEFAULT 0TPM token-bucket refill rate (>= 0); 0 means unlimited
max_in_flightBIGINTOptional per-tenant concurrency cap; null = only the global limit applies
fairshare_groupTEXT NOT NULL DEFAULT 'default'FK → fairshare_groups.name
descriptionTEXT NOT NULL DEFAULT ''Operator note
organizationTEXT NOT NULL DEFAULT ''Optional org metadata
contact_emailTEXT NOT NULL DEFAULT ''Optional contact metadata
statusTEXT NOT NULL DEFAULT 'active'active, suspended, or archived — only active admits traffic
tracing_enabledBOOLEAN NOT NULL DEFAULT falseWhen true, every request from any key in this tenant is span-traced to the ClickHouse spans table (added by 0002_tracing_flag.sql)
timezoneTEXT NOT NULL DEFAULT 'UTC'IANA timezone for access windows
active_fromTIMESTAMPTZOptional activation start; null = no bound
active_untilTIMESTAMPTZOptional expiry cutoff; null = no bound
weekly_windowsJSONBRecurring windows [{day:0-6, start_min, end_min}]; null/empty = any time
budget_tokensBIGINTOptional cumulative token cap for the term
budget_cost_usdDOUBLE PRECISIONOptional cumulative USD cap for the term
budget_periodTEXTlifetime, monthly, or term
budget_started_atTIMESTAMPTZWhen the current term began
allowed_modelsJSONBOptional model-name allowlist; null/empty = all models permitted
guardrails_policyJSONBPer-tenant guardrails content policy (scanners + action); null = none (added by 0003_guardrails_policy.sql)
compression_policyJSONBPer-tenant compression policy; null = follow the global default (added by 0013_compression_policy.sql)
syntheticBOOLEAN NOT NULL DEFAULT falseMarks a benchmark/test tenant. Its requests are recorded with request_type = 'benchmark' and excluded from usage and cost stats by default (added by 0015_tenant_synthetic.sql)
created_atTIMESTAMPTZAuto-set
updated_atTIMESTAMPTZAuto-updated

Indexed by fairshare_group and by status (partial, where status <> 'active').

api_keys

Stores API key hashes. The raw key is never stored.

ColumnTypeNotes
idUUID PRIMARY KEY
tenant_idUUID NOT NULLFK → tenants.id (ON DELETE CASCADE)
nameTEXT NOT NULLDisplay name
descriptionTEXT NOT NULL DEFAULT ''Operator note
key_prefixTEXT NOT NULLFirst 18 chars (safe to display)
key_hashTEXT NOT NULL UNIQUESHA-256 of the full secret
budget_tokensBIGINTOptional cumulative token cap for this key alone
budget_cost_usdDOUBLE PRECISIONOptional cumulative USD cap for this key alone
budget_periodTEXTlifetime, monthly, or term
budget_started_atTIMESTAMPTZWhen this key's current budget term began
disabledBOOLEAN NOT NULL DEFAULT false
tracing_enabledBOOLEAN NOT NULL DEFAULT falseWhen true, requests using this key are span-traced to the ClickHouse spans table; overrides the tenant default when set per-key (added by 0002_tracing_flag.sql)
created_atTIMESTAMPTZ
updated_atTIMESTAMPTZ

Indexed by tenant_id (api_keys_tenant_id_idx).

models

Model registry: client-facing names mapped to upstream OpenAI-compatible endpoints.

ColumnTypeNotes
idUUID PRIMARY KEY
model_nameTEXT NOT NULL UNIQUEName used in client requests
descriptionTEXT NOT NULL DEFAULT ''Operator-facing model description
model_typeTEXT NOT NULL DEFAULT 'chat'Modality: chat, embedding, audio_transcription, audio_speech, or image
upstream_modelTEXT NOT NULLModel name sent to upstream
api_baseTEXT NOT NULLPer-model upstream override (provider base ending in /v1)
api_keyTEXTInjected upstream credential (encrypted at rest)
input_cost_per_tokenFLOAT8 NOT NULL DEFAULT 0For billing (chat, embedding)
output_cost_per_tokenFLOAT8 NOT NULL DEFAULT 0For billing (chat)
cost_per_imageFLOAT8 NOT NULL DEFAULT 0Per-image billing (image, × n)
cost_per_audio_secondFLOAT8 NOT NULL DEFAULT 0Per-audio-second billing (audio_transcription; reserved)
cost_per_characterFLOAT8 NOT NULL DEFAULT 0Per-character billing (audio_speech)
context_windowBIGINT NOT NULL DEFAULT 8192
admission_weightBIGINT NOT NULL DEFAULT 100Scales the tenant's fairshare weight for this model (>= 1); 100 is neutral
max_in_flightBIGINTOptional per-model in-flight cap; null = no cap
capacity_modeTEXT NOT NULL DEFAULT 'static'static or tuned — how max_in_flight was chosen
capacity_tuned_atTIMESTAMPTZWhen auto-tune last applied a slot count; null until tuned
supports_function_callingBOOLEAN NOT NULL DEFAULT false
supports_system_messagesBOOLEAN NOT NULL DEFAULT true
supports_response_schemaBOOLEAN NOT NULL DEFAULT falseRequired for JSON-schema requests in auto routing
supports_tool_choiceBOOLEAN NOT NULL DEFAULT falseRequired for tool_choice requests in auto routing
supports_visionBOOLEAN NOT NULL DEFAULT falseNative image input. When false, the vision boon can relay images to a describer model instead
tagsJSONB NOT NULL DEFAULT '[]'Auto-router tags (fixed vocabulary)
boonsJSONB NOT NULL DEFAULT '[]'Per-model gateway boons opted into (fixed vocabulary: vision, structured_output, compression)
tool_serversJSONB NOT NULL DEFAULT '[]'Registered MCP servers whose tools this model may use (gateway tool loop; operator-defined names)
enabledBOOLEAN NOT NULL DEFAULT true
cache_enabledBOOLEAN NOT NULL DEFAULT falseResponse cache toggle
cache_ttl_secsBIGINT NOT NULL DEFAULT 300Cache TTL in seconds
request_timeout_secsBIGINTPer-request upstream timeout; null = use OBLETH_UPSTREAM_TIMEOUT_SECS
max_retriesBIGINT NOT NULL DEFAULT 0Extra attempts per endpoint on retryable failures
retry_backoff_msBIGINT NOT NULL DEFAULT 200Base retry backoff (exponential, capped)
endpoint_selection_modeTEXT NOT NULL DEFAULT 'failover'failover, load_balance, or session_hash across endpoints. session_hash was rejected by the original check constraint until 0011_endpoint_selection_session_hash.sql widened it
debug_diagnosticsBOOLEAN NOT NULL DEFAULT falseWhen on, a terminal 502/504 triggers a read-only DNS-resolve and TCP-connect probe recorded as a trace span (added by 0012_model_debug_diagnostics.sql)
energy_slots_per_nodeBIGINT NOT NULL DEFAULT 0Concurrent requests that saturate one node (energy accounting); 0 = opted out
health_checks_enabledBOOLEAN DEFAULT trueScheduled model health checks
health_alerts_enabledBOOLEAN DEFAULT trueSlack alerts for this model
health_check_interval_secsBIGINT DEFAULT 900Per-model check interval
health_failure_thresholdBIGINT DEFAULT 2Consecutive failures before alerting
health_maintenance_untilTIMESTAMPTZSuppress alerts while active
health_maintenance_noteTEXTOperator note for maintenance
health_statusTEXT DEFAULT unknownLatest status
health_consecutive_failuresBIGINT DEFAULT 0Current failure streak
health_alert_stateTEXT DEFAULT okAlert state (ok or firing)
health_next_check_atTIMESTAMPTZNext scheduled check time
health_last_checked_atTIMESTAMPTZLatest check timestamp
health_last_latency_msBIGINTLatest check latency
health_last_http_statusBIGINTLatest upstream/proxy status
health_last_messageTEXTSanitized latest check summary
created_atTIMESTAMPTZ
updated_atTIMESTAMPTZ

Indexed by enabled (partial, where enabled = true) and by health_next_check_at (partial, where the model is enabled and health checks are on) so the health worker can find due models without a full scan.

model_health_checks

Append-only history of model health probes.

ColumnTypeNotes
idBIGSERIAL PRIMARY KEY
model_idUUID NOT NULLFK → models.id (ON DELETE CASCADE)
checked_atTIMESTAMPTZProbe timestamp
triggerTEXTscheduled, manual, or bulk
statusTEXThealthy, degraded, unhealthy, or skipped
latency_msBIGINTEnd-to-end proxy latency
http_statusBIGINTHTTP status from the proxy/upstream
messageTEXTSanitized summary
response_excerptTEXTSanitized body excerpt for failures

model_endpoints

One row per upstream cluster that a model can be routed to. A model with no rows here uses its own api_base/api_key (legacy single-upstream path); with rows, the data plane routes across the enabled, healthy ones using the model's endpoint_selection_mode. See Reliability & Failover.

ColumnTypeNotes
idUUID PRIMARY KEY
model_idUUID NOT NULLFK → models.id (ON DELETE CASCADE)
nameTEXT NOT NULLUnique per model (UNIQUE (model_id, name))
api_baseTEXT NOT NULLUpstream base ending in /v1
api_keyTEXTInjected upstream credential (encrypted at rest); inherits the model key when null
priorityBIGINT NOT NULL DEFAULT 100Lower is tried first in failover mode
weightBIGINT NOT NULL DEFAULT 100Traffic share in load_balance mode
enabledBOOLEAN NOT NULL DEFAULT trueDisabled endpoints are removed from rotation
health_statusTEXT NOT NULL DEFAULT 'unknown'Latest per-endpoint probe status
consecutive_failuresBIGINT NOT NULL DEFAULT 0Current failure streak
alert_stateTEXT NOT NULL DEFAULT 'ok'Alert state
last_checked_atTIMESTAMPTZLatest probe timestamp
last_latency_msBIGINTLatest probe latency
last_http_statusBIGINTLatest probe HTTP status
last_messageTEXTSanitized latest probe summary
created_atTIMESTAMPTZ
updated_atTIMESTAMPTZ

Indexed by model_id (model_endpoints_model_idx).

managed_models

Optional Slurm provisioning spec, one row per model obleth hosts on a cluster. Absent rows mean the model uses static endpoints and the data plane behaves exactly as it would without the provisioner. See Slurm Provisioning.

ColumnTypeNotes
model_idUUID PRIMARY KEYFK → models.id (ON DELETE CASCADE)
enabledBOOLEAN NOT NULL DEFAULT trueMaster switch; false drains replicas to zero and keeps the spec
partitionTEXT NOT NULLSlurm partition
gresTEXT NOT NULL DEFAULT ''Generic resource, e.g. gpu:h100:2
nodesBIGINT NOT NULL DEFAULT 1Nodes per replica (>= 1)
constraintsTEXTSlurm --constraint
excludeTEXTNodes or features to avoid
accountTEXTSlurm account
qosTEXTQuality-of-service class
time_limitTEXTSlurm --time, e.g. 12:00:00
cpus_per_taskBIGINTSlurm --cpus-per-task; null = partition default
memTEXTSlurm --mem, e.g. 560G; null = partition default
imageTEXT NOT NULLApptainer image reference
preambleTEXT NOT NULL DEFAULT ''Shell lines injected before apptainer exec
log_output_dirTEXT NOT NULL DEFAULT ''Directory for Slurm stdout/stderr; empty = Slurm default
launch_commandTEXT NOT NULLCommand run inside the container
script_bodyTEXT NOT NULL DEFAULT ''Fully rendered job script; when set, submitted verbatim and overrides image/preamble/launch_command
serving_portBIGINT NOT NULLBase port the inference server binds (1–65535)
health_pathTEXT NOT NULL DEFAULT '/health'Health probe path
target_replicasBIGINT NOT NULL DEFAULT 2Replica count the reconciler submits toward (>= 1)
min_replicasBIGINT NOT NULL DEFAULT 1Health floor: the model is healthy at or above this many healthy replicas (added by 0007_replica_port_and_min_replicas.sql)
max_job_failuresBIGINT NOT NULL DEFAULT 0Stop resubmitting after this many consecutive lost replicas; 0 = unlimited
launcher_specJSONBMetadata recorded by recipe-sourced deploys so the edit view can identify them; the provisioner ignores it (added by 0005_managed_launcher_spec.sql)
last_provision_errorTEXTThe provisioner's last submit failure, surfaced in the dashboard and cleared on a successful submit (added by 0008_managed_provision_error.sql)
last_provision_error_atTIMESTAMPTZWhen that failure occurred
created_atTIMESTAMPTZ
updated_atTIMESTAMPTZ

model_replicas

One row per known Slurm-backed replica of a managed model. The provisioner owns these rows.

ColumnTypeNotes
idUUID PRIMARY KEY
model_idUUID NOT NULLThe model this replica serves. Not a foreign key: 0010_drop_replica_model_cascade.sql dropped it so replica rows outlive a deleted model and the provisioner's drain pass can still cancel their Slurm jobs
slurm_job_idTEXT NOT NULLUnique per model (model_replicas_job_uniq), which makes replica creation idempotent
nodesTEXTAllocated hostnames (comma-separated)
endpoint_idUUIDFK → model_endpoints.id (ON DELETE SET NULL); the routing entry created once the replica is healthy
stateTEXT NOT NULL DEFAULT 'pending'pending, starting, healthy, draining, or lost
port_baseBIGINTBase of the disjoint port window assigned to this replica; the job binds the first free port in [port_base, port_base + OBLETH_PORT_SPAN) (added by 0007_replica_port_and_min_replicas.sql)
cancel_requestedBOOLEAN NOT NULL DEFAULT falseOperator-requested restart: the provisioner cancels this replica's job regardless of target, and the resubmit launches a fresh one (added by 0009_replica_cancel_requested.sql)
last_messageTEXTLatest provisioner status detail
created_atTIMESTAMPTZ
updated_atTIMESTAMPTZ

Indexed by model_id and by state.

recipes

Admin-authored recipe templates for the Slurm model launcher, created and edited from the dashboard. body is the raw recipe document (YAML header plus sbatch script) — the same shape as a .recipe file on disk, stored in the database so it is editable at runtime without redeploying the control plane. Added by 0006_recipes.sql, which also drops the superseded saved_recipes table from 0004.

ColumnTypeNotes
idUUID PRIMARY KEY
nameTEXT NOT NULLDisplay name
bodyTEXT NOT NULL DEFAULT ''Raw recipe document
authorTEXT NOT NULL DEFAULT ''Display label of who saved it
created_atTIMESTAMPTZ
updated_atTIMESTAMPTZ

Indexed by updated_at desc (recipes_updated_idx).

fairshare_groups

Scheduler groups for hierarchical mode. A default group (weight 100) is seeded on first boot.

ColumnTypeNotes
nameTEXT PRIMARY KEYGroup name
weightBIGINT NOT NULL DEFAULT 100Group-level weight (>= 1)
created_atTIMESTAMPTZ
updated_atTIMESTAMPTZ

mcp_servers

MCP server registry. obleth reverse-proxies these through its auth + audit layer.

ColumnTypeNotes
idUUID PRIMARY KEY
nameTEXT NOT NULL UNIQUEReached at /mcp/{name}
upstream_urlTEXT NOT NULLSSRF-validated upstream base
auth_headerTEXTInjected auth header value (encrypted at rest)
enabledBOOLEAN DEFAULT true
created_atTIMESTAMPTZ
updated_atTIMESTAMPTZ

audit_log

Append-only record of all Management API mutations.

ColumnTypeNotes
idBIGSERIAL PRIMARY KEY
tsTIMESTAMPTZ NOT NULL DEFAULT now()When the action occurred
actorTEXT NOT NULLWho performed it (e.g. admin)
actionTEXT NOT NULLe.g. create_tenant, delete_key
entity_typeTEXT NOT NULLe.g. tenant, api_key
entity_idTEXT NOT NULLID of the affected entity
detailJSONB NOT NULL DEFAULT '{}'Structured detail payload

Indexed by ts desc (audit_log_ts_idx), by actor, ts desc (audit_log_actor_idx), and by entity_type, entity_id, ts desc (audit_log_entity_idx) so filtering the trail by who acted or which entity was touched stays fast as the log grows.

app_settings

Key-value store for runtime-reloadable gateway settings. Holds the alerting configuration (Slack webhook + SMTP email) under key alerts, the auto_router classifier settings, the usage-retention window, the model-boon settings (boons), the Slurm provisioner connection (slurm), the energy accounting configuration (energy), and the Charo assistant settings (charo_settings). New fields are stored as JSON so they need no schema change.

ColumnTypeNotes
keyTEXT PRIMARY KEYSetting name (e.g. alerts, auto_router)
valueJSONB NOT NULLSetting payload
updated_atTIMESTAMPTZ NOT NULL DEFAULT now()Auto-updated

Applying the schema

The gateway applies all schema files under schema/postgres/ in lexicographic order on boot — there is no per-version migration table to query. All statements are idempotent, so re-running against an existing database is safe. To inspect the live schema, read it from Postgres directly:

-- List obleth's tables
\dt

-- Describe a table
\d+ tenants