# Backend migrations Goose (`pressly/goose/v3`) migrations embedded into the backend binary by `embed.go`. Applied at startup before any listener opens — see `internal/postgres`. ## Authoring conventions - Each schema change is a new file with a monotonically increasing numeric prefix and a snake-case slug: `0000N_short_description.sql`. Reuse of a prefix is forbidden once the file is merged. - `00001_init.sql` is the historical baseline. Treat it as immutable history; do not edit it to land new schema. Squashing the chain back into a fresh `00001` is reserved for the explicit pre-production cut-over. - Every file MUST contain both an `-- +goose Up` and `-- +goose Down` section, even if Down is a single `DROP …` for the same artefacts. Down migrations are exercised by the schema test and serve as the documented rollback path. - Destructive changes (dropping columns/tables, renaming with data loss) MUST be split into at least two migrations so the chain stays rollable forward and backward without coordinated code+schema windows: 1. add the new shape, dual-write the data, leave the old shape in place; 2. once all readers have switched, drop the old shape in a follow-up migration. - Migrations are applied automatically on backend startup, so a fresh push to `development` plus the `dev-deploy.yaml` workflow brings the long-lived dev database up to head without manual intervention. `make -C tools/dev-deploy clean-data` is only needed when a developer deliberately wants a fresh database. - The integration harness (`backend/internal/postgres/migrations_test.go`) spins up a disposable Postgres per run and asserts the final table set. When a migration adds or removes tables, update the expected list in the same patch. ## Pre-production squash The chain may be squashed back into one clean `00001_init.sql` before the first production deployment. That is a deliberate, one-time operation; until then, additive numbered files are the rule. After the squash this file gets a short note that `00001_init.sql` represents the production baseline and the policy above continues to apply for every later migration.