deploy(prod): pre-deploy DB backup + paired code/DB rollback skill

Every `just deploy` now takes a pg_dumpall to
/opt/colectivo/backups/predeploy-<ts>-<sha>.sql.gz BEFORE rebuilding the
app or applying migrations, aborts the deploy if the dump is < 1 KiB,
and (on success) appends `<iso-ts> \t <sha> \t <backup-file>` to
/opt/colectivo/.deploys.log on ambrosio. Keeps the newest 10 backups
(prunes older predeploy-* files).

New `infra/scripts/rollback-erosi.sh` reads .deploys.log and pairs a
code rollback with a DB restore atomically:

  just rollback-list          # show recent deploys
  just rollback               # roll back to N-1
  just rollback-to <sha>      # roll back to a specific deploy
  just rollback-code          # roll back code only, keep current DB

Rollback safety:
- 5-second abort window.
- Verifies the target SHA exists locally + the backup is still on prod
  (warns if it's been pruned past the 10-deploy window).
- Uses a temporary git worktree so the user's working tree isn't
  disturbed.
- Stops app/auth/rest/realtime/storage before the gunzip|psql restore.
- Rebuilds the app image at the rolled-back SHA with the same GIT_SHA
  build-arg path the deploy uses (so __APP_COMMIT__ in the bundle
  matches the running code).
- Does NOT write a new .deploys.log entry — rollback is intentionally
  not a deploy event; the next `just deploy` is from current HEAD.
- Storage volume (/var/lib/storage user uploads) is NOT rolled back.

Justfile `deploy` recipe repointed from the stale `deploy.sh` (which
referenced GHCR pull) to `deploy-erosi.sh` (the active prod path).

New project-scoped skill: `.claude/skills/deploy/SKILL.md` documents the
flow + safety boundaries for Claude-assisted invocations. `.gitignore`
keeps `.claude/settings.local.json` ignored but tracks `.claude/skills/`.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-18 14:57:25 +02:00
parent c0e5b5ed7f
commit ae4fd45b99
6 changed files with 363 additions and 4 deletions

View File

@@ -45,6 +45,28 @@ ssh ambrosio 'cd /opt/colectivo && docker compose --env-file .env -f infra/docke
```
`KEYCLOAK_CLIENT_SECRET` is runtime-only (GoTrue reads it) — for that one a `docker compose restart auth` is enough.
### Rollback (code + DB)
Every `just deploy` pairs a code-rsync with a `pg_dumpall` taken just before the build, and logs the pair to `/opt/colectivo/.deploys.log` on ambrosio. Rollback uses that log to restore both atomically.
```sh
just rollback-list # show recent deploys (timestamp / sha / backup)
just rollback # roll back code + DB to N-1
just rollback-to <git-sha> # roll back to a specific deploy
just rollback-code # roll back code only, leave DB at current state
```
Safety:
- 5-second abort window before anything destructive runs.
- Verifies the target SHA exists in the local git repo (fetch first if you're rolling back to an old commit).
- Verifies the matching backup is still on ambrosio (older than 10 deploys = pruned).
- Stops `app` / `auth` / `rest` / `realtime` / `storage` before the `gunzip | psql` restore so they don't observe inconsistent state.
- Materialises the target commit into a temp `git worktree`; your working tree is untouched.
- Does **not** write to `.deploys.log` — rollback is intentionally not a deploy event. The next `just deploy` will be from your current HEAD.
- The storage volume (user uploads at `/var/lib/storage`) is **not** rolled back. Treated as append-only.
When to use `--code-only`: regression is UI/JS only and the DB schema is forward-compatible. Skips the destructive restore but still rebuilds + redeploys the older app image.
### Wipe all app + auth data (keep schema, keep migrations)
When switching Keycloak realms or starting fresh:
```sql