- name
- run-migration
- description
- Authors and validates an Alembic migration for this repo's SQLModel schema — generating it from model changes, reviewing the autogenerated script for dangerous operations, and running the upgrade/downgrade/upgrade validation loop. Use whenever a SQLModel change needs a migration, or when reviewing an already-written migration for safety before it runs against production.
# Migration author
Migrations live in `backend/app/alembic/versions/`, driven by `backend/app/alembic/env.py` and `backend/alembic.ini` (`script_location = app/alembic`). All commands run inside the `backend` container, from `/districtr-backend` (the container's working directory, where `alembic.ini` lives):
```bash
docker-compose exec backend alembic <command>
```
## Procedure
### 1. Change the SQLModel, then generate
Edit the model in `backend/app/models.py` (or `app/comments/models.py`, `app/cms/models.py`, etc.), then:
```bash
docker-compose exec backend alembic revision --autogenerate -m "<description>"
```
`env.py`'s `include_object` hook excludes the `gerrydb` schema from autogenerate diffing entirely (imported layers, owned by the import pipeline) — a model added there will never autogenerate a migration, and that's the guard working, not a bug to route around. It also excludes tables by name: entries in `POST_GIS_ALPINE_RESERVED_TABLES` (`backend/app/alembic/constants.py`), `parentchildedges_*` partitions, and `*_districtr_view` materialized views.
### 2. Review the autogenerated script
Autogenerate proposes a plausible diff, not a safe one — read every operation before keeping it, with the usual eye for drops, table rewrites, and `ACCESS EXCLUSIVE` locks. Repo-specific review points:
- **Anything touching `parentchildedges`** — it is the one remaining `LIST`-partitioned table (partitioned by `districtr_map`). Autogenerate does not understand partitioning: it will not see per-map partitions at all, and a change that looks like it targets the parent table alone can still lock every partition. Constraint/FK changes here need to be written by hand against the partitioned structure, not trusted from autogenerate.
- **For any locking/rewriting operation, note the table's size in the migration docstring or the PR description** so a reviewer can judge whether it's safe to run live.
### 3. Write (or fix) the downgrade
Check the generated `downgrade()` actually reverses the schema, and be explicit in the docstring about what it does *not* restore. A one-way migration should say so in `downgrade()` — `pass # one-way migration` with a comment, not a downgrade that silently does nothing while looking like it works.
### 4. Validate: upgrade → downgrade → upgrade
```bash
docker-compose exec backend alembic upgrade head
docker-compose exec backend alembic downgrade -1
docker-compose exec backend alembic upgrade head
```
On failure, fix and re-run the full three-step loop, not just the failing step. (CI's test suite runs `alembic upgrade head` on a fresh database, but only the upgrade direction — this loop is what exercises downgrade.)
Two repo-specific review facts beyond the checklist above: constraint drops are by literal name, so verify the names against production before merging; and `document.document`'s FK deliberately keeps NO ACTION (maps with saved plans must not be deletable) — don't "fix" it to match the cascading FKs next to it.
Ver en GitHub