Files
Gebos/docs/adr/0001-manual-supabase-cli-migrations.md
Lars Nolden 2ce68cb098
deploy / deploy (push) Successful in 5m57s
check / flake-check (push) Failing after 35m52s
Wire schema v1 into a manual Supabase migration and vendor the real stack
- Move db/schema.sql to supabase/migrations/ as the first supabase CLI
  migration (manual `db push` only, no automated runner); re-add the
  gebos_ingest role + grants there since init.sql never re-runs
- Add gebos-postgres-passwords oneshot on db-host: syncs role passwords
  from sops (LoadCredential, journal-safe), makes supabase_admin
  SUPERUSER and hands the auth schema to supabase_auth_admin to match
  the upstream supabase/postgres image; add pg_hba rule for 10.0.0.0/8
- Vendor the official docker-compose (studio/kong/auth/rest/meta only,
  external Postgres, loopback Studio with no Kong dashboard route) plus
  kong.yml (trimmed) and kong-entrypoint.sh (verbatim); tested: compose
  config, Kong config parse, migration applied on TimescaleDB pg17
- Document decisions as ADRs 0001-0004 (migrations, passwords, vendored
  stack, JWT API keys incl. verify/mint procedure)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 22:33:50 +02:00

52 lines
2.3 KiB
Markdown

# ADR-0001: Database schema changes are manual Supabase CLI migrations
Date: 2026-07-08
Status: Accepted
## Context
Schema v1 (`db/schema.sql`, ~600 lines) was committed but wired to nothing.
The only SQL that ran automatically was `nix/supabase/init.sql` via
`services.postgresql.initialScript` — which executes **only at first initdb**,
so on the already-initialized db-host cluster neither it nor any schema change
would ever apply again. A delivery mechanism was needed.
Options considered:
1. **Automated runner** — a systemd oneshot on db-host applying migrations on
every deploy (dbmate/atlas or plain psql with a tracking table).
2. **Manual Supabase CLI migrations** — plain-SQL files in
`supabase/migrations/`, applied by a human with `supabase db push`.
3. **Extending initialScript** — rejected outright: never re-runs on an
existing cluster.
## Decision
Option 2. Schema changes are rare, deliberate, admin-level operations; a
human applies them on purpose, and no automation exists to break or to apply
a half-reviewed migration as a side effect of a deploy.
* Migrations live in `supabase/migrations/<timestamp>_<name>.sql`; schema v1
moved there as the first one. `supabase/config.toml` is the minimal CLI
project marker.
* Applied via SSH tunnel to db-host as the `postgres` superuser
(see `supabase/README.md` for the exact commands). The CLI records applied
files in `supabase_migrations.schema_migrations`, so pushes are incremental
and re-running is safe. Individual migrations need **not** be idempotent.
* Layering rule: `nix/supabase/init.sql` holds only cluster bootstrap
(Supabase schemas, admin/API roles, extensions needing
`shared_preload_libraries`); everything else — including the `gebos_ingest`
role and its grants, which are coupled to application tables and must reach
existing clusters — lives in migrations. Passwords live in neither
(see ADR-0002).
## Consequences
* Deploys (`deploy-rs`) never touch the schema; a deploy and a migration are
two separate, independently reversible acts.
* A human must remember to push after merging a migration. Accepted for a
pilot with one operator.
* The local `nix run .#dev` Postgres has no TimescaleDB yet, so the v1
migration's `create_hypertable` fails there until the dev stack gains the
extension.