SlpModularCms is the product; slpsoftware.nl is the customer running it - the first one, and a fine stand-in for what a real deployment looks like. Renamed the directories, systemd units, and backup paths accordingly. Left the backup script's own filename alone since the already-committed deploy-scp.yaml calls it by that exact name.
3.2 KiB
Rollback Plan
Mechanism (D-26, infrastructure-design.md § 3–4): two releases are always retained —
current plus exactly one previous. Pruning only ever runs after a passing health check, so a
failed deploy never leaves fewer than two releases on disk.
When to Roll Back
- The deploy workflow's health check failed (job already shows red;
currentwas left pointing at the new, unhealthy release — no automatic rollback, perinfrastructure-design.md§ 4) - The deploy succeeded and passed its health check, but a defect surfaces afterward that only shows up under real traffic
Fast Rollback (Previous Release Still on Disk) — the Common Case
No rebuild needed. Over SSH, on the Pi:
cd ~/apps/slpsoftware/<env>/releases
ls -1t # confirm which directory is the previous, working release
ln -sfn ~/apps/slpsoftware/<env>/releases/<previous-timestamp> ~/apps/slpsoftware/<env>/current
systemctl --user restart slpsoftware-<env>.service
curl -f https://<env-domain>/health # confirm the rollback itself is healthy
This is the same atomic-switch primitive the deploy workflow itself uses — pointing it backward
instead of forward. wwwroot/web/ is untouched either way, since it was never part of the switched
directory to begin with (FR-08).
Rebuild-and-Redeploy Rollback (Older Than One Release Back)
If the defect predates the retained previous release, redeploy an earlier commit through the normal pipeline:
git revertor check out the last-known-good commit on a branch- Push to
master(test) or runworkflow_dispatchwithdeploy_production: true(production) — the same gates and deploy sequence run as any other deploy - This only works because migrations are required to be forward-compatible and non-destructive (D-26) — redeploying an older commit's code against a database that has since had newer migrations applied must not break. If a migration since the target commit was destructive, this path is not safe and the database backup (§ below) is the actual recovery route instead
Database Rollback
A backup is taken before every production deploy (operations/deployment/deployment-instructions.md
§ 4, invoked by deploy-scp.yaml when run_db_backup: true). To restore:
sqlcmd -S <server> -U <user> -P <password> -C -Q \
"RESTORE DATABASE [SlpModularCmsProduction] FROM DISK = N'<path-to-backup>.bak' WITH REPLACE"
Restoring a database backup and rolling back the application release are independent actions — decide based on the actual failure whether one, the other, or both are needed. Rolling back the app without restoring the database is usually sufficient (migrations are non-destructive by design); restoring the database without rolling back the app should be rare and deliberate.
What Is Never Part of a Rollback
wwwroot/web/(the customer's website) — structurally outside every release directory; no rollback action should ever touch it- The Data Protection key ring — lives in the database, not the release directory; rolling back the app release does not affect it
- Gitea Actions variables/secrets — these describe the target, not a specific release; nothing about them changes during a rollback