Storage

Schema & migrations

The canonical Postel database schema, the forward-only migrations, and the boot-time version handshake.

Every SQL-backed adapter targets the same canonical schema. It's defined once, in Postgres dialect with SQLite variants noted inline, under specs/db-schema/ — that directory is the source of truth, and each adapter transcribes it to its dialect.

Tables

TableHolds
_postel_metaSchema version (read at boot for the compatibility handshake).
tenantsOptional tenant rows (NULL tenant = single-tenant mode).
endpointsOne row per registered receiver URL, plus its delivery config.
endpoint_secretsPriority-ordered signing secrets per endpoint (rotation overlap).
messagesThe outbox: one row per send(). Workers reserve rows here.
attemptsPer-endpoint, per-message delivery attempts (the audit trail).
endpoint_state_transitionsAudit log of endpoint state changes.

Plus a dead_letter view over attempts whose final disposition is exhausted.

Forward-only migrations

Migrations are numbered (0001_init.sql, 0002_*, …) and forward-only: no destructive change, every step idempotent (IF NOT EXISTS / version-gated). Standalone and client adapters run them through your connection; ORM adapters ship a schema fragment in the host's DSL that you merge and migrate with your ORM's own tooling.

Version handshake

_postel_meta records the schema version the database is at. An adapter reads it at boot and refuses to run against an incompatible schema, so a library upgrade that needs a newer schema fails fast with a clear "run the migration" error rather than misbehaving against old columns. Run the adapter's migrations (or postel migrate) to bring the database forward.

On this page