# Migrations

SQLx-managed Postgres migrations. Each `NNN_topic.up.sql` has a matching
`NNN_topic.down.sql`. Run by `sqlx::migrate!()` at app start.

## Rules

1. **Never edit a shipped migration.** If a column needs to change or a fix needs to
   land, write a new migration. Production has already applied the old one and SQLx
   tracks each by checksum — editing in place will fail to apply on existing databases.
2. **Always pair `.up.sql` with a `.down.sql`.** Reverts may not be perfect (data
   loss is sometimes unavoidable) but the file must exist and do the best it can.
3. **Prefer additive changes.** New columns, new tables, new keys in `config`. Drop /
   rename only when there is no alternative.
4. **No business logic in migrations.** Schema + seeds only. Anything that needs Rust
   code goes in a one-off binary, not a migration file.
5. **One concern per migration.** Easier to revert. Easier to read in `git log`.

## Numbering

Zero-padded three digits, monotonically increasing. The next free number lives at the
bottom of the directory listing — pick that.

## Seed-only migrations

When you only need to add `config` keys (feature flags, defaults), use
`INSERT … ON CONFLICT DO NOTHING` so existing operator overrides survive. See
`009_feature_toggles.up.sql` for the canonical shape.
