Skip to content

Database schema

Ampora uses Entity Framework Core with PostgreSQL. The migrations in src/Ampora.Persistence/Migrations are the source of truth. This page is a high-level orientation — names, purposes, relationships — to help you read the schema, not a substitute for the migration code.

Conventions

  • All timestamps are timestamptz and stored in UTC.
  • Primary keys are UUID v4 unless otherwise noted.
  • Multi-tenant tables carry tenant_id (UUID, indexed).
  • Soft-deletable tables carry deleted_at_utc (nullable).
  • Optimistic-concurrency tables carry row_version (bytea).
  • Encrypted-at-rest fields end in _encrypted, _nonce, _tag, _scheme — the AES-GCM envelope.

Domain tables

Tenants and users

Table Purpose
tenants One row per tenant; theme, branding, defaults
tenant_identity_mappings OIDC claim → role mapping per tenant
users Cached profile of OIDC subjects we have seen

Agents and identities

Table Purpose
agent_identities Issued client certs; bound or unbound to an agent
agents Connected (or formerly connected) agents
agent_descriptions Latest AgentDescription per agent (JSONB labels)
agent_status_history Append-only event timeline
agent_session_ownership Which Ampora instance owns each WebSocket session (with fencing token)
agent_package_statuses Per-package state per agent (when ReportsPackageStatuses)

Configurations

Table Purpose
configurations Containers; one per logical config
configuration_versions Versions per container; immutable when published
configuration_lints Lint findings per version

Groups

Table Purpose
groups Static or Dynamic; soft-deletable
group_memberships Static membership; single-group invariant enforced via partial unique index
group_dynamic_selectors DSL expression and compiled AST per dynamic group

Rollouts

Table Purpose
rollouts One row per rollout
rollout_batches Per-batch state
rollout_targets Per-agent state in a batch
rollout_gate_decisions Audit of gate evaluations

Audit

Table Purpose
audit_events Hot table
audit_event_archive Same shape, fewer indexes

PKI

Table Purpose
ca_signing_keys Draft / Active / Trusted / Retired keys (private material AES-GCM-wrapped or HSM handle)
crl_publications Latest signed CRL blob per active key
ocsp_signers Per-active-key OCSP signer cert + key

Tokens

Table Purpose
bootstrap_tokens Single-use bootstrap tokens (hashed)
token_pools Token-issuance pools
pat_tokens Personal Access Tokens for API automation

Governance

Table Purpose
policies Built-in and custom policies
policy_versions Approval-flow versions of custom policies
lint_rules Tenant-scoped lint rules

GitOps

Table Purpose
git_config_sources Registered repos with wrapped credentials
git_sync_runs Sweep history (30-day retention)

Federation

Table Purpose
federation_peers Inbound + outbound auth material per peer
federation_handover_tokens Cross-cluster handover tokens
federated_rollouts Coordination rows for cross-peer rollouts

Infrastructure

Table Purpose
leader_leases Named leader leases for background services
dispatch_envelopes Cross-instance dispatch payloads
live_update_events Optional persistence for the live-update bus (Redis backplane uses pub/sub instead)

Indexes

Beyond the obvious primary-key and foreign-key indexes, the performance-critical ones are:

  • agents(tenant_id, last_seen_utc DESC), (tenant_id, deleted_at_utc).
  • agent_descriptions — JSONB GIN with jsonb_path_ops (used by dynamic group selectors).
  • audit_events(tenant_id, timestamp_utc DESC), (entity_type, entity_id, timestamp_utc DESC).
  • rollout_targets(rollout_id, batch_index, status) for the per-batch progress query.
  • agent_session_ownership(agent_id, fencing_token DESC).

Row-Level Security

When MultiTenant:Mode = HardIsolation, RLS policies restrict every multi-tenant table to rows where tenant_id = current_setting('app.tenant_id')::uuid. Ampora sets SET LOCAL app.tenant_id = '<uuid>' per request.

Migrations

ls src/Ampora.Persistence/Migrations

Each migration has a Up method only. Forward-only — see Operator → Database & migrations.

Reading the live schema

psql -h db.acme.io -U ampora -d ampora -c '\d agent_descriptions'

The \d command lists the live shape. For an EF-perspective view, the __EFMigrationsHistory table records which migrations have been applied.