Upgrading

Migrations run automatically when the app starts (Docker Compose) or as the pre-deploy step (Railway). They only ever add or change structure; they never delete your data. Still, back up first: a migration can't be rolled back by itself.

Docker Compose

# 1. Back up the database (and make sure you still have ENCRYPTION_KEYS)
docker compose exec -T db pg_dump -U jobtracker jobtracker | gzip > backup-$(date +%F).sql.gz

# 2. Get the new version
git pull

# 3. Rebuild and restart (migrations run before the server starts)
docker compose --profile app up -d --build

# 4. Check it
docker compose logs app | tail -20
curl -s https://your.domain/api/health

If the app doesn't come up, the log shows the failing migration. Restore the backup into the database and run the previous version (git checkout <previous tag>), then open an issue with the log.

Railway

Push or merge to the deployed branch. The pre-deploy command runs migrations; if they fail, the old version keeps running and the deploy is marked failed. Railway's daily Postgres backups are under the Postgres service → Backups.

Release notes

Each GitHub release lists new environment variables, migrations and anything that needs your action. New variables always have safe defaults, so an upgrade works without editing .env; new features stay off until you configure them.

Encryption key rotation

Add a new key and switch the active one; old data stays readable with the old key:

ENCRYPTION_KEYS=k1:<old>,k2:<new>
ENCRYPTION_ACTIVE_KEY_ID=k2

Keep k1 in the list as long as any data was written with it.