Backup and Recovery
Use this page when you need a repeatable backup, restore, and release rollback path for production or evaluator environments.
Scope
This repository treats backup and rollback as three separate concerns:
- database backup and restore
- runtime image rollback
- demo reset workflows
Do not treat migrate:fresh --seed as a production recovery tool.
1. Database backup
For Docker-based environments, use the provided helper:
scripts/ops/mysql-backup.sh build/backups/$(date +%F-%H%M%S)-app.sql docker-compose.production.yml .envArguments:
- output SQL path
- compose file (optional, defaults to
docker-compose.production.yml) - env file (optional, defaults to
.env)
The helper executes mysqldump inside the running MySQL container and writes a plain SQL dump on the host.
2. Database restore
Restore a dump back into the running MySQL service with:
scripts/ops/mysql-restore.sh build/backups/2026-03-10-180000-app.sql docker-compose.production.yml .envUse restore only when you are explicitly recovering data. For evaluator demos, prefer a full reset instead.
3. Release rollback
Code rollback and data rollback are different operations.
Use runtime rollback when:
- the published image is bad
- a migration has not irreversibly changed data
- the problem is application behavior, not corrupted data
Recommended sequence:
- switch the app image tag back to the previous immutable GHCR version
- redeploy the stack
- run
GET /api/health/live - run
GET /api/health/ready - execute
php artisan about --only=environment
If the issue is data corruption or destructive migration behavior, restore the database before reopening traffic.
4. Demo reset
For evaluator or hosted demo environments, do not mix production recovery with demo cleanup.
Use one of these paths instead:
php artisan migrate:fresh --seed --force- restore a known-clean demo SQL snapshot
5. Recommended drill cadence
Run a real recovery drill at least once per release line:
- create a SQL backup
- restore it into a disposable environment
- verify health endpoints
- verify seeded login and one write-safe flow
- rehearse a GHCR image rollback
6. What to verify after restore
Minimum checks:
GET /api/health/liveGET /api/health/readyphp artisan about --only=environment- queue worker starts
- seeded login works
- tenant-scoped list endpoints return expected data
7. Related documents
docs/production-runtime.mddocs/release-artifacts.mddocs/demo-deployment-runbook.mddocs/deletion-lifecycle.md