PostgreSQL Database¶
PostgreSQL is the durable source of truth for Relayna Gateway. It stores projects, virtual keys, access policy, registered service routes, provider configuration, route toggles, guardrail configuration, operator tokens, portal memberships, managed-identity bindings, and usage records.
Scope¶
- Relayna Gateway requires PostgreSQL 14 or newer.
- Tables are created in the default
publicschema. - Migrations enable the
pgcryptoextension so UUID primary keys can usegen_random_uuid(). PostgresStore::connectruns the bundled SQLx migrations fromcrates/gateway-store/migrationson startup.- SQLx also maintains its migration bookkeeping table,
_sqlx_migrations.
Do not treat this page as a replacement for migrations. The current schema is defined by the migration files, and this page explains the operational meaning of that schema.
Entity Overview¶
| Area | Tables | Purpose |
|---|---|---|
| Projects | projects |
Groups project-owned virtual keys and service access. |
| Virtual keys | api_keys, key_policies, key_guardrail_policies, policy_layers |
Stores key identity, inherited request policy, limits, budgets, lifecycle metadata, and guardrail policy. |
| Services | service_registrations, project_service_links, key_service_links |
Registers /services/<service-name>/* routes and grants project or individual-key access. |
| Providers and routes | provider_configs, litellm_credential_mappings, litellm_passthrough_settings, openai_route_settings, anthropic_route_settings, route_policies |
Stores upstream provider settings, LiteLLM credential mapping, wildcard passthrough settings, and global OpenAI-compatible and Anthropic-compatible route toggles/modes. |
| Guardrails | guardrail_definitions, guardrail_execution_events |
Stores guardrail catalog entries and execution audit records. |
| Studio settings | studio_connection_settings |
Stores the optional Relayna Studio import connection. |
| Operators | operator_tokens |
Stores hashed tokens for /admin-ui/admin/* and /admin-ui access. |
| Portal access | portal_members, service_memberships, managed_identity_bindings, oidc_login_transactions, portal_sessions |
Stores Entra member state, exact service assignments, workload bindings, one-time browser login state, and opaque sessions. |
| Audit | audit_events |
Stores append-only operator mutation records with redacted snapshots. |
| Provider intelligence | provider_health_states, request_debug_bundles, service_registry_snapshots |
Stores health/circuit state, sanitized request debug bundles, and import version history. |
| Usage | usage_events |
Stores request accounting for admin usage views, exports, budget rehydration, Relayna Studio consumption, and trace-aware analytics. |
Required Operational Data¶
- At least one active
operator_tokensrow is required for authenticated/admin-ui/admin/*access after bootstrap. Startup creates one bootstrap token when no active token exists. IfGATEWAY_ADMIN_TOKENis set, a fresh database is seeded from that token. Otherwise startup generates and prints a raw token once. After an active token exists, env changes are ignored and token changes must go through Admin portal rotation. - Entra browser users require a
portal_membersrow. First sign-in creates a pending member; administrator access requires an active Admin role, while owner monitoring requires an active exactservice_membershipsrow. - Managed-identity monitoring requires an enabled
managed_identity_bindingsrow matching tenant, client ID, optional object ID, application role, and service. Tenant-wide token validity alone grants no service access. - Project-owned keys require a
projectsrow and anapi_keys.project_idvalue that references it. Individual keys must haveproject_idset toNULL. - A usable virtual key needs an
api_keysrow. If nokey_policiesrow exists, runtime code uses default policy values; admin-created keys normally upsert an explicit policy row. - Service routing requires an enabled
service_registrationsrow with complete runtime fields. Project-owned keys useproject_service_links; individual keys usekey_service_links. - OpenAI-compatible route availability is controlled by seeded
openai_route_settingsrows for/v1/chat/completionsand/v1/responses. - Guardrail use depends on
guardrail_definitionsplus per-keykey_guardrail_policies. Migrations seed the built-inpii-redactdefinition as enabled but not default-on. usage_eventsandguardrail_execution_eventsare append-only operational records used by admin usage, exports, budget rehydration, observability, and audit workflows.- Provider health state, request debug bundles, service registry snapshots,
operator scopes, audit events, policy layers, and usage trace indexes are
v0.1.0additions. See Current Feature Highlights for the operator-facing feature summary.
Table Reference¶
projects¶
Projects group shared service access and project-owned keys.
| Key | Details |
|---|---|
| Primary key | id uuid generated with gen_random_uuid(). |
| Unique keys | name is unique. |
| Checks | name must be non-empty after trimming and at most 120 characters. |
| Referenced by | api_keys.project_id, service_registrations.project_id, project_service_links.project_id, and guardrail_execution_events.project_id. |
| Required data | Create a project before creating project-owned virtual keys or project-scoped service links. |
api_keys¶
api_keys stores Relayna virtual key identity and lifecycle state. Raw virtual
keys are never stored.
| Key | Details |
|---|---|
| Primary key | id uuid generated with gen_random_uuid(). |
| Unique keys | key_prefix is unique and is used for lookup before hash verification. |
| Foreign keys | project_id references projects(id) with ON DELETE RESTRICT when owner_type = 'project'. |
| Checks | owner_type must be project or individual; project keys require project_id, individual keys require project_id IS NULL. |
| Lifecycle fields | disabled, revoked_at, and expires_at determine whether a key can authenticate. rotation_due_at helps operators plan rotation, and last_used_at records the last observed key use when populated by runtime paths. |
| Secret fields | key_hash stores an Argon2 hash of the raw rk_live_... key. |
| Referenced by | key_policies, key_guardrail_policies, key_service_links, usage_events, guardrail_execution_events, and legacy route_policies. |
key_policies¶
key_policies stores route, model, provider, service, rate-limit, budget, and
feature permissions for a virtual key.
| Key | Details |
|---|---|
| Primary key | key_id, also a foreign key to api_keys(id) with ON DELETE CASCADE. |
| Defaults | Routes default to /v1/chat/completions and /v1/responses; providers default to litellm; models and services default to empty arrays. |
| Limits | rpm_limit, tpm_limit, daily_budget_usd, monthly_budget_usd, daily request/token caps, per-request cost/token caps, UTC-hour allowlists, stale-key auto-disable days, request/response byte caps, stream duration, SSE event, tool call, and tool schema caps are nullable unless otherwise noted. NULL means no database-configured limit for that field. |
| Feature flags | allow_streaming and allow_tools default to false. |
| Versioning | policy_version increments when key policy is updated and is surfaced for simulation and debugging. |
| Indexes | idx_key_policies_limits supports lookups for keys with configured limits or budgets. |
| Required data | Admin key creation upserts this row. If it is missing, runtime defaults are used. |
policy_layers¶
policy_layers stores optional inherited policy layers for deterministic
effective-policy resolution.
| Key | Details |
|---|---|
| Primary key | id uuid. |
| Unique keys | (layer_kind, scope_id) is unique. |
| Layer kinds | global, project, team, key, route, and model. |
| Payloads | policy jsonb stores additive KeyPolicy fields; guardrail_policy jsonb stores the guardrail layer. |
| Versioning | policy_version identifies the layer version used in simulator and runtime debugging. |
| Required data | Optional. Existing per-key policy behavior is preserved when this table has no matching rows. Layer JSON uses neutral defaults so empty layers do not narrow routes, providers, streaming, or tools. |
key_guardrail_policies¶
key_guardrail_policies stores guardrail selection and per-key runtime config
overrides.
| Key | Details |
|---|---|
| Primary key | key_id, also a foreign key to api_keys(id) with ON DELETE CASCADE. |
| Policy arrays | mandatory_guardrails, optional_guardrails, and forbidden_guardrails default to empty arrays. |
| Overrides | guardrail_config_overrides jsonb defaults to {} and stores shallow per-key overrides for selected guardrails. |
| Required data | Only required when a key opts into mandatory, optional, forbidden, or overridden guardrail behavior. |
project_service_links¶
project_service_links grants project-owned keys access to registered
services.
| Key | Details |
|---|---|
| Primary key | Composite key on (project_id, service_name). |
| Foreign keys | project_id references projects(id) with ON DELETE CASCADE; service_name references service_registrations(name) with ON DELETE CASCADE. |
| Indexes | project_service_links_service_name_idx supports reverse lookup by service. |
| Required data | Required for project-owned keys to call registered service routes. |
key_service_links¶
key_service_links grants individual keys access to registered services.
| Key | Details |
|---|---|
| Primary key | Composite key on (key_id, service_name). |
| Foreign keys | key_id references api_keys(id) with ON DELETE CASCADE; service_name references service_registrations(name) with ON DELETE CASCADE. |
| Indexes | key_service_links_service_name_idx supports reverse lookup by service. |
| Required data | Required for individual keys to call registered service routes. |
service_registrations¶
service_registrations defines registered service routes under
/services/<service-name>/*.
| Key | Details |
|---|---|
| Primary key | name text. |
| Unique keys | studio_service_id is unique when present. |
| Foreign keys | project_id references projects(id) with ON DELETE RESTRICT when present. |
| Checks | name must be lowercase DNS-label style; source is gateway or studio; sync_status is local, synced, incomplete, stale, or failed; cost_mode is fixed, passthrough, or none; health_check_method is GET or HEAD; timeout_ms and max_body_bytes must be positive. |
| Runtime fields | route_pattern, upstream_base_url, health_check_path, health_check_method, enabled, allowed_methods, timeout_ms, max_body_bytes, cost_mode, estimated_cost_usd, pricing_rules, credential_secret, and fallback_services. |
| OpenAPI fields | openapi_source_path, openapi_schema_hash, and openapi_synced_at record the reviewed source; openapi_endpoints stores the compact discovered method/path catalog; endpoint_pricing_rules stores per-operation none, fixed, or passthrough billing. These JSONB fields default safely for registrations created before 0.1.21. |
| Indexes | service_registrations_studio_service_id_idx, service_registrations_source_status_idx, and service_registrations_project_id_idx. |
| Required data | A service must be enabled and have complete runtime fields before the proxy can forward matching service traffic. |
OpenAPI is fetched only during authenticated preview/sync actions and is not a runtime dependency for proxy traffic. See OpenAPI Service Import and Endpoint Pricing for the sync contract and cost precedence.
provider_configs¶
provider_configs stores operator-managed upstream provider settings.
| Key | Details |
|---|---|
| Primary key | id uuid generated with gen_random_uuid(). |
| Unique keys | (provider, name) is unique. Only one enabled litellm config is allowed. |
| Checks | provider must be litellm or internal-service; name must be non-empty and at most 120 characters; base_url must start with http:// or https://; LiteLLM credential header mode is authorization_bearer or custom_header; custom header value format is raw or bearer. |
| Header fields | credential_header_mode, credential_header_name, and credential_header_value_format control whether LiteLLM receives Authorization: Bearer <key>, a raw custom credential header such as x-litellm-api-key: <key>, or a bearer-prefixed custom header such as x-litellm-key: Bearer <key>. |
| Secret fields | credential_secret stores the internal upstream credential and is treated as write-only by API responses. |
| Required data | Needed when operators configure runtime provider settings through the admin API or portal instead of environment fallback. |
litellm_credential_mappings¶
litellm_credential_mappings stores write-only LiteLLM virtual keys scoped to
a Relayna key or project.
| Key | Details |
|---|---|
| Primary key | id uuid generated with gen_random_uuid(). |
| Scope fields | scope is key or project; key_id or project_id stores the selected target. Exactly one target must be present. |
| Unique keys | Partial unique indexes allow one mapping per key and one mapping per project. |
| Secret fields | credential_secret stores the LiteLLM virtual key and is treated as write-only by API responses and audit snapshots. |
| Lifecycle fields | enabled, created_at, and updated_at. Disabled mappings are skipped during credential resolution. |
| Runtime precedence | Gateway resolves LiteLLM credentials by key mapping, then project mapping, then active provider default credential, then the LITELLM_SERVICE_KEY startup fallback when no active provider config overrides it. |
litellm_passthrough_settings¶
litellm_passthrough_settings stores the singleton configuration for LiteLLM
wildcard passthrough.
| Key | Details |
|---|---|
| Primary key | id boolean, constrained to true, so only one settings row can exist. |
| Enablement | enabled controls whether unmatched LiteLLM-bound traffic can fall through to wildcard passthrough after Relayna routes and canonical OpenAI routes have had precedence. |
| Allowlists | allowed_paths and allowed_methods are non-empty arrays. A path ending in * matches by prefix. The safe default when enabled is /v1/* with GET and POST. |
| Sensitive exposure | ui_exposure and admin_api_exposure are disabled, operator_only, or explicitly_exposed by default. trusted_ingress is also supported by ui_exposure only. disabled blocks matching sensitive paths even when they are listed in allowed_paths; operator_only requires Gateway Entra or trusted Apigee identity plus Relayna virtual-key auth; explicitly_exposed allows authenticated Relayna virtual-key clients when path and method allowlists match; trusted_ingress allows browser-safe LiteLLM UI access for trusted ingress flows when /ui and support paths match. |
| Runtime limits | timeout_ms, max_request_body_bytes, and max_response_body_bytes default to 120000, 1048576, and 1048576. Operators can raise these up to 600000 ms and 104857600 bytes for long-context direct passthrough traffic. |
| Auditability | Admin API updates write audit events with before/after settings. No LiteLLM credential secret is stored in this table. |
| Runtime role | Wildcard passthrough preserves the original path and query, strips client credentials, injects the resolved LiteLLM credential, and records reduced status-only usage for non-canonical paths. |
openai_route_settings¶
openai_route_settings stores global enablement and mode selection for
OpenAI-compatible proxy routes.
| Key | Details |
|---|---|
| Primary key | route_id text. |
| Unique keys | route is unique. |
| Checks | route_id is limited to chat-completions, responses, and embeddings; route is limited to /v1/chat/completions, /v1/responses, and /v1/embeddings. |
| Mode | mode is managed_by_gateway or direct_litellm_passthrough. managed_by_gateway is the default. |
| Runtime limits | timeout_ms, max_request_body_bytes, and max_response_body_bytes default to 120000, 1048576, and 1048576. These route-level limits apply before virtual-key policy limits; configured key or policy-layer limits can still be stricter. |
| Seed data | Migrations insert supported routes as enabled and managed by Gateway. |
| Required data | These rows must exist for operators to toggle global OpenAI-compatible route availability and direct LiteLLM passthrough mode. |
| Runtime role | Both modes preserve Relayna auth, global route enablement, policy, provider/model allowlists, rate limits, and budgets. Direct LiteLLM passthrough skips Gateway guardrail rewriting and token accounting, then forwards directly to LiteLLM with credential translation. |
anthropic_route_settings¶
anthropic_route_settings stores global enablement and mode selection for
Anthropic-compatible Claude proxy routes.
| Key | Details |
|---|---|
| Primary key | route_id text. |
| Unique keys | route is unique. |
| Checks | route_id is limited to messages, messages-count-tokens, message-batches, message-batch, message-batch-results, message-batch-cancel, and models; route is limited to the matching /v1/messages... and /v1/models patterns. |
| Mode | mode is managed_by_gateway or direct_litellm_passthrough. managed_by_gateway is the default. |
| Runtime limits | timeout_ms, max_request_body_bytes, and max_response_body_bytes default to 120000, 1048576, and 1048576. These route-level limits apply before virtual-key policy limits; configured key or policy-layer limits can still be stricter. |
| Seed data | Migrations insert supported Anthropic routes as enabled and managed by Gateway. |
| Required data | These rows must exist for operators to toggle Anthropic-compatible route availability and direct LiteLLM passthrough mode. |
| Runtime role | Both modes preserve Relayna auth, global route enablement, policy, provider/model allowlists, rate limits, and budgets. Direct LiteLLM passthrough skips Gateway guardrail rewriting and token accounting, then forwards directly to LiteLLM with credential translation. |
studio_connection_settings¶
studio_connection_settings stores the optional Relayna Studio import
connection configured through Admin portal Settings.
| Key | Details |
|---|---|
| Primary key | singleton boolean, constrained to true. |
| Checks | base_url must be NULL or an HTTP/HTTPS URL. |
| Secret fields | bearer_token_secret stores the Studio bearer token and is write-only in API responses. |
| Required data | Optional. When no row or no base URL exists, Gateway can fall back to RELAYNA_STUDIO_BASE_URL and RELAYNA_STUDIO_TOKEN. |
operator_tokens¶
operator_tokens stores admin authentication tokens. Raw operator tokens are
never stored.
| Key | Details |
|---|---|
| Primary key | id uuid generated with gen_random_uuid(). |
| Unique keys | token_prefix is unique. A partial unique index allows only one active token where disabled = false and revoked_at IS NULL. |
| Governance fields | roles and scopes bind the token to operator capabilities. Bootstrap and rotated owner tokens default to role owner and wildcard scope *. |
| Lifecycle fields | disabled, revoked_at, and last_used_at. |
| Secret fields | token_hash stores an Argon2 hash of the raw operator token. |
| Indexes | operator_tokens_active_idx and operator_tokens_one_active_idx. |
| Required data | At least one active row is needed for admin access after bootstrap. GATEWAY_ADMIN_TOKEN seeds only a fresh database; existing active rows ignore env changes. |
audit_events¶
audit_events is the append-only admin audit trail. It records admin mutations
and is queryable through the scoped admin audit API.
| Key | Details |
|---|---|
| Primary key | id uuid generated with gen_random_uuid(). |
| Actor | actor_token_id references the operator token that authorized the action. |
| Action fields | action, target_type, and optional target_id describe the mutation. |
| Change fields | before_json and after_json store redacted structured snapshots when available. Raw virtual keys, operator tokens, provider credentials, and internal service tokens must not be written. |
| Request fields | request_id, optional ip, optional user_agent, and created_at. |
| Indexes | audit_events_created_at_idx, audit_events_actor_created_at_idx, and audit_events_target_created_at_idx. |
usage_events¶
usage_events records gateway request outcomes for usage summaries and
operator visibility.
| Key | Details |
|---|---|
| Primary key | id uuid generated with gen_random_uuid(). |
| Foreign keys | key_id references api_keys(id) with ON DELETE RESTRICT. project_id is nullable after project-first key support and is not currently constrained by a foreign key. |
| Request fields | request_id, trace_id, route, model, provider, service_name, nullable validated service_version, nullable http_method, nullable query-free endpoint_path, nullable endpoint_template, task_id, run_id, and fallback_count. |
| Accounting fields | status, status_code, latency_ms, input_tokens, output_tokens, total_tokens, and estimated_cost. |
| Indexes | Lookup indexes cover key, project, request ID, trace ID, provider, service, model, task, run, status, and expensive-request time-series queries. A partial service-endpoint index combines service, method, a bounded MD5 digest of COALESCE(endpoint_template, endpoint_path), status code, and time; exact queries also compare the full effective endpoint. |
| Required data | Written for successful and failed request paths. Preserve this table for billing, diagnostics, budget counter rehydration, usage exports, and Relayna Studio usage views. |
Admin usage and analytics endpoints read this table with the same filters used by the usage dashboard: time range, project, key, route, provider, service, method, effective endpoint, numeric status code, task ID, run ID, model, status, trace ID, and minimum cost. Endpoint breakdowns exclude non-service and historical rows without endpoint metadata. JSON exports include summary totals plus row details. Summary and time-series queries derive P95 latency directly from the matching event set. CSV exports append the service version and method/path/template fields and neutralize spreadsheet formula prefixes before sending the response.
guardrail_definitions¶
guardrail_definitions stores the global guardrail catalog.
| Key | Details |
|---|---|
| Primary key | name text. |
| Runtime fields | description, modes, default_on, failure_policy, config_schema, config, and enabled. |
| Seed data | Migrations upsert pii-redact with pre_call, post_call, and during_call modes, fail_closed, and restore_output: true. |
| Required data | A guardrail must exist here before a key policy can reference it. |
guardrail_execution_events¶
guardrail_execution_events stores audit and observability records for
guardrail execution.
| Key | Details |
|---|---|
| Primary key | id uuid generated with gen_random_uuid(). |
| Foreign keys | key_id references api_keys(id) with ON DELETE SET NULL; project_id references projects(id) with ON DELETE SET NULL. |
| Event fields | request_id, route, model, provider, guardrail_name, mode, action, failure_policy, latency_ms, reason, and metadata. |
| Indexes | Lookup indexes cover request ID, key, project, guardrail, and mode/action time-series queries. |
| Required data | Written when guardrails run. Preserve it for guardrail audit trails and admin summaries. |
route_policies¶
route_policies is a legacy per-route policy table from the initial migration.
Current runtime and admin paths use key_policies.allowed_routes instead.
| Key | Details |
|---|---|
| Primary key | id uuid generated with gen_random_uuid(). |
| Unique keys | (key_id, route) is unique. |
| Foreign keys | key_id references api_keys(id) with ON DELETE CASCADE. |
| Current role | Retained by migration history. Do not build new behavior on this table unless the runtime is intentionally changed to use it again. |
Secret Handling¶
- Raw virtual keys and raw operator tokens are shown only at creation/bootstrap time. PostgreSQL stores only lookup prefixes and Argon2 hashes.
provider_configs.credential_secret,service_registrations.credential_secret, andstudio_connection_settings.bearer_token_secretare internal secrets and should be treated as write-only from API and UI responses.- Back up PostgreSQL as sensitive data because hashes, provider credentials, Studio credentials, service credentials, policies, and usage records are all operationally sensitive.
- Prefer the admin API or Admin portal for changes. Manual SQL updates should be reserved for recovery operations with a reviewed rollback plan.