The health check used curl which is not installed on the prod server.
Replace with a dual approach:
1. Primary: check Docker's own container health status (already running
via docker-compose.prod.yml healthcheck with wget inside container)
2. Secondary: wget from host as fallback signal
Also add diagnostic logging (container status + recent backend logs)
before triggering rollback on health check failure.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The APPLIED_MIGRATIONS associative array triggered "unbound variable"
under set -u when empty (first run / seed-existing). Fix by initializing
with =() and using a safe helper function with ${:-} default syntax.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add automated production deployment pipeline:
- scripts/deploy-prod.sh: Full deployment script with pre/post DB backups,
migration tracking via shared.schema_migrations table, health checks,
and automatic rollback on failure (restores DB, reverts code, rebuilds)
- .gitea/workflows/deploy.yml: Manual-trigger Gitea Actions workflow for
intentional production deployments with optional --seed-existing flag
- scripts/db-backup.sh: Add --yes/-y flag to skip interactive confirmation
prompts, enabling automated restore during rollback
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>