Data Model
Tables
applications
The unit of tenancy. Every row doubles as its own policy document.
| Column | Type | Meaning |
|---|---|---|
id | uuid, PK | |
name | text | |
created_at | timestamptz | |
monthly_token_quota | integer, nullable | null = unlimited. Enforced by quota reservation. |
rate_limit_per_minute | integer, nullable | null = unlimited. Enforced by the fixed-window rate limiter. |
allowed_models | text[], nullable | null = unrestricted. Checked against the raw requested model name, before alias resolution. |
routing_strategy | enum('cost','latency','balanced'), nullable | null = use the registry's declared order. |
disabled_at | timestamptz, nullable | Set it, and every one of the application's API keys stops working immediately — no need to revoke them individually. |
api_keys
| Column | Type | Meaning |
|---|---|---|
id | uuid, PK | |
application_id | uuid, FK → applications.id | |
key_hash | text | HMAC-SHA256 of the raw key, never the key itself. See Security. |
key_prefix | text | First 23 characters of the issued key (lattice_sk_ + 12 chars), safe to display in a UI so an admin can recognize a key without ever seeing it in full again. |
revoked_at | timestamptz, nullable | |
last_used_at | timestamptz, nullable | Best-effort touched on every successful auth. |
usage_records
One row per completed request that produced token counts — the raw ledger application_usage_counters is a running aggregate of.
| Column | Type |
|---|---|
id | uuid, PK |
application_id | uuid, FK |
model, provider | text |
prompt_tokens, completion_tokens | integer, nullable |
created_at | timestamptz |
application_usage_counters
A running total per application per calendar month, keyed by (application_id, period_start). Exists so a quota check is a single row read, not a scan over usage_records.
| Column | Type |
|---|---|
application_id | uuid, FK — part of composite PK |
period_start | timestamptz — month start (UTC), part of composite PK |
tokens_used | integer, default 0 |
requests_used | integer, default 0 |
rate_limit_counters
The same "single row read" idea, for the 60-second rate-limit window instead of the monthly quota.
| Column | Type |
|---|---|
application_id | uuid, FK — part of composite PK |
window_start | timestamptz — floored to the current 60s window, part of composite PK |
request_count | integer, default 0 |
request_logs
Append-only observability history, written best-effort so a logging failure never affects the client response — see Request Lifecycle .
| Column | Type | Meaning |
|---|---|---|
id | uuid, PK | |
application_id | uuid, FK | |
request_id | text | Server-generated Bun.randomUUIDv7(), correlates with structured logs. |
model | text | The requested model name, as sent by the client. |
provider | text, nullable | null if the request failed before routing resolved a provider (e.g. bad model name, quota exceeded). |
status | enum('success','error') | |
http_status | integer | |
error_code | text, nullable | A LatticeErrorCode — see Errors. |
attempts | integer | How many providers were tried. |
latency_ms | integer | |
prompt_tokens, completion_tokens, total_tokens | integer, nullable | |
estimated_cost_usd | numeric(12,6), nullable | See cost estimation. |
created_at | timestamptz | Indexed alongside application_id for the management API's paginated request log. |
management_api_keys
Structurally similar to api_keys, but with no foreign key to applications — a management key authorizes the gateway's own admin surface, not any one application's traffic.
| Column | Type |
|---|---|
id | uuid, PK |
name | text |
key_hash, key_prefix | text |
revoked_at, last_used_at | timestamptz, nullable |
provider_circuit_state / provider_latency_state
Not shown on the ERD above (they have no relationship to applications) — these are the Postgres-backed sync points for the in-memory circuit breaker and latency tracker , keyed by provider and model_id respectively.
Migrations
The gateway uses Drizzle Kit against server/database/schema.ts. See Database & Migrations for the day-to-day workflow.