chore: reset alembic migration history with a single initial baseline#572
chore: reset alembic migration history with a single initial baseline#572
Conversation
Drop SQLModel.metadata.create_all() from init_db — the startup path used to create missing tables directly from models, which let the DB drift from the alembic-tracked schema. Alembic now owns all DDL; init_db only seeds the superadmin organization/user and the default bucket. Document the one-time alembic_version reset required for databases migrated under the pre-2026-04 history, so existing volumes do not fail 'alembic upgrade head' after pulling the new baseline.
…green Downgrade() previously dropped the tables but left the userrole and annotationtype enum types behind, so a subsequent alembic upgrade head would fail on CREATE TYPE ... already exists. Explicitly drop both types after the table drops. Verified via upgrade -> downgrade -> upgrade round-trip on an empty postgres. Also remove the 2026-04-specific restamp section from the migrations README. It was scoped to a single rollout and has no long-term value in-repo; the restamp procedure for existing deployments is communicated via the PR description instead.
The dev compose backend command relied on SQLModel.metadata.create_all
in init_db to materialize tables at startup. Now that init_db no longer
creates schema, init_db's SELECTs fail against an empty DB and the
backend healthcheck fails — which is what broke the 'tests' workflow
('container pyronear-backend-1 is unhealthy' at docker compose up
--wait). Match production compose by running alembic first.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #572 +/- ##
==========================================
+ Coverage 88.34% 88.57% +0.23%
==========================================
Files 51 51
Lines 2162 2180 +18
==========================================
+ Hits 1910 1931 +21
+ Misses 252 249 -3
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
Hi @MateoLostanlen ! Thank you for the PR ! I have a few questions :
|
Acruve15
left a comment
There was a problem hiding this comment.
I don't have much to say on this. My concerns are mostly operational rather than about the migration itself. If I understand correctly, existing environments will crash on the next deployment. Both docker-compose.yml and docker-compose.dev.yml now run alembic upgrade head at startup, and every existing DB has alembic_version pointing at one of the deleted revisions
💡 Can we either land it as a one-off script (e.g. scripts/restamp_alembic.sh?) or add a checklist of enviornements (prod, staging, any dev VMs?) that we tick off before merging?
Another suggestion:
- CI does not exercise the migration end-to-end. The pytest fixture in
src/tests/conftest.py:243builds the schema withSQLModel.metadata.create_all, so the only path that runs alembic is the compose--waitintests.yml. Adding a tiny job that runsalembic upgrade head && alembic downgrade base && alembic upgrade headwould catch the "CREATE TYPE already exists" class of bug you just fixed.
|
Hi @fe51 , I ran the local test — here's the breakdown so you can see exactly what Phase 1 — Switch envdev API to clean_alembic without losing data
Phase 2 — Apply PR #564's migration on top of the baseline
Result The envdev DB went from "no alembic at all" to stamped at 9700bbccb2f1 One side note unrelated to this work: GET /api/v1/cameras/ returns 500 For the real deploy, the same recipe applies: build the new image, |
Replace sqlmodel.sql.sqltypes.AutoString with sa.String in the baseline migration so it no longer depends on sqlmodel at load time. Add a render_item hook in env.py narrowed to AutoString instances so future autogenerated migrations also emit sa.String(...). Remove import sqlmodel from script.py.mako so newly generated migration files don't reintroduce the dependency.
|
Thanks @Acruve15 , all your remarks taken into account. On the AutoString point, pushed in cf345bb:
On the operational side:
|
Add a thin Make wrapper around alembic revision --autogenerate and alembic upgrade head so contributors do not have to remember the docker compose exec invocation. Update the migrations README to reflect that alembic now owns the schema (init_db only seeds the superadmin), list the cases that --autogenerate misses, and document stamp/current/history for adopting existing schemas onto the new baseline. Also add a .PHONY declaration covering every target so the Makefile stays well-behaved if a file named after a target ever appears in the repo.
fe51
left a comment
There was a problem hiding this comment.
Hi @MateoLostanlenn thanks a lot for this fresh new start and process to run migration !
Summary
migrations).
the previous startup path could create missing tables directly from models, which is what let the
drift happen.
(otherwise a re-upgrade fails with CREATE TYPE ... already exists).
How the baseline was generated
Autogenerated against an empty Postgres, so the new migration captures the full current schema as
defined by src/app/models.py. Includes all 10 tables (organizations, webhooks, alerts, cameras,
users, poses, occlusion_masks, sequences, alerts_sequences, detections), their FKs, the
ix_users_login unique index, and the userrole / annotationtype enums. Verified with an upgrade →
downgrade → upgrade round-trip on an empty Postgres.
Deployment — required on every existing environment
The alembic_version table still points to a now-deleted revision, so every existing DB must be
re-stamped before deploying this branch. Run on the VM:
Strip the +asyncpg driver suffix — that form is for SQLAlchemy, not libpq
psql "${POSTGRES_URL/+asyncpg/}" -c "DELETE FROM alembic_version;"
alembic stamp head
No DDL runs — this only updates the version marker. Fresh DBs will get the full schema via the normal
alembic upgrade head path.