2026-05-17 04:08:20 +00:00
|
|
|
# Migration policy
|
|
|
|
|
|
2026-05-17 17:39:38 +00:00
|
|
|
## Migrations are the sole source of truth
|
|
|
|
|
|
|
|
|
|
The `sql/migrations/` directory contains all schema definitions. There is
|
|
|
|
|
no separate schema.sql file; use `pg_dump -s central` to generate a
|
|
|
|
|
human-readable snapshot of the current schema when needed.
|
|
|
|
|
|
2026-05-17 04:08:20 +00:00
|
|
|
## Migrations must be idempotent
|
|
|
|
|
|
|
|
|
|
New migration files (007+) must use guards so they can be safely
|
|
|
|
|
re-run without error:
|
|
|
|
|
|
|
|
|
|
- `CREATE TABLE IF NOT EXISTS ...`
|
|
|
|
|
- `CREATE INDEX IF NOT EXISTS ...`
|
|
|
|
|
- `INSERT ... ON CONFLICT DO NOTHING` (or `ON CONFLICT ... DO UPDATE`
|
|
|
|
|
where the intent is upsert)
|
|
|
|
|
- `ALTER TABLE ... ADD COLUMN IF NOT EXISTS ...`
|
|
|
|
|
|
|
|
|
|
Migrations 003-006 predate this policy and are grandfathered. Do not
|
|
|
|
|
rewrite them.
|
|
|
|
|
|
|
|
|
|
## All schema changes go through migrate.py
|
|
|
|
|
|
|
|
|
|
Direct `psql` execution bypasses the `schema_migrations` tracker and
|
|
|
|
|
was the cause of the v0.2.0 reconcile. If a migration needs to be
|
|
|
|
|
applied on the live system, run:
|
|
|
|
|
|
2026-05-17 18:26:48 +00:00
|
|
|
sudo -u central /opt/central/.venv/bin/python -m central.migrate
|
2026-05-17 04:08:20 +00:00
|
|
|
|
|
|
|
|
Never apply migration SQL directly via `psql`, even as a superuser,
|
|
|
|
|
even "just to test." If migrate.py has a bug that's blocking you, fix
|
|
|
|
|
migrate.py.
|
2026-05-17 18:26:48 +00:00
|
|
|
|
|
|
|
|
## Extensions are not in migrations
|
|
|
|
|
|
|
|
|
|
PostgreSQL extensions like PostGIS require superuser privileges to
|
|
|
|
|
install. The production `central` role is intentionally not a superuser.
|
|
|
|
|
Therefore, extensions live outside the migration system:
|
|
|
|
|
|
|
|
|
|
- **Production bootstrap:** A DBA runs `CREATE EXTENSION postgis` once
|
|
|
|
|
before the first `migrate.py` run.
|
|
|
|
|
- **Test database:** The `central_test` role is a superuser, allowing
|
|
|
|
|
test fixtures to self-bootstrap extensions.
|
|
|
|
|
|
|
|
|
|
This is documented in [docs/test-database.md](test-database.md).
|
|
|
|
|
|
|
|
|
|
Do not add `CREATE EXTENSION` statements to migrations — they will fail
|
|
|
|
|
in production where migrations run as the non-superuser `central` role.
|