Automate migration backups and add session rollback on failure
- Replace operator-driven backup requirement with automatic migration engine responsibility - Full DB backup when new migrations are detected, before any step runs - Per-table backup before each migration step affecting that table - Session rollback (or per-table restore) on any migration failure - Update local-first-recovery to reflect automatic backup requirement Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# Contract: Database Patterns (Go / MySQL / MariaDB)
|
||||
|
||||
Version: 1.7
|
||||
Version: 1.8
|
||||
|
||||
## MySQL Transaction Cursor Safety (CRITICAL)
|
||||
|
||||
@@ -104,32 +104,45 @@ items, _ := repo.GetItemsByPricelistIDs(ids) // 1 query with WHERE id IN (...)
|
||||
// then group in Go
|
||||
```
|
||||
|
||||
## Backup Before Any DB Change
|
||||
## Automatic Backup During Migration
|
||||
|
||||
Any operation that changes persisted database state must have a fresh backup taken immediately before execution.
|
||||
|
||||
This applies to:
|
||||
- Go migrations
|
||||
- Manual SQL runbooks
|
||||
- Data backfills and repair scripts
|
||||
- Imports, bulk updates, and bulk deletes
|
||||
- Admin tools or one-off operator commands
|
||||
The migration engine is responsible for all backup steps. The operator must never be required to take a backup manually.
|
||||
|
||||
Backup naming, storage, archive format, retention, and restore-readiness must follow the `backup-management` contract.
|
||||
|
||||
### Full DB Backup on New Migrations
|
||||
|
||||
When the migration engine detects that new (unapplied) migrations exist, it must take a full database backup before applying any of them.
|
||||
|
||||
Rules:
|
||||
- No schema change or data mutation is allowed on a non-ephemeral database without a current backup.
|
||||
- "Small" or "safe" changes are not exceptions.
|
||||
- The operator must know how to restore from that backup before applying the change.
|
||||
- If a migration or script is intended for production/staging, the rollout instructions must state the backup step explicitly.
|
||||
- The backup taken before a migration must be triggered by the application's own backup mechanism, not by assuming `mysql`, `mysqldump`, or other DB client tools exist on the user's machine.
|
||||
- Before a migration starts, double-check that backup output resolves outside the git worktree and is not tracked or staged in git.
|
||||
- The full backup must complete and be verified before the first migration step runs.
|
||||
- The backup must be triggered by the application's own backup mechanism; do not assume `mysql`, `mysqldump`, `pg_dump`, or any other external DB client tool is present on the operator's machine.
|
||||
- Before creating the backup, verify that the backup output path resolves outside the git worktree and is not tracked or staged in git.
|
||||
|
||||
### Per-Table Backup Before Each Table Migration
|
||||
|
||||
Before applying a migration step that affects a specific table, take a targeted backup of that table.
|
||||
|
||||
Rules:
|
||||
- A per-table backup must be created immediately before the migration step that modifies that table.
|
||||
- If a single migration step touches multiple tables, back up each affected table before the step runs.
|
||||
- Per-table backups are in addition to the full DB backup; they are not a substitute for it.
|
||||
|
||||
### Session Rollback on Failure
|
||||
|
||||
If any migration step fails during a session, the engine must roll back all migrations applied in that session.
|
||||
|
||||
Rules:
|
||||
- "Session" means all migration steps started in a single run of the migration engine.
|
||||
- On failure, roll back every step applied in the current session in reverse order before surfacing the error.
|
||||
- If rollback of a step is not possible (e.g., the operation is not reversible in MySQL without the per-table backup), restore from the per-table backup taken before that step.
|
||||
- After rollback or restore, the database must be in the same state as before the session started.
|
||||
- The engine must emit structured diagnostics that identify which step failed, which steps were rolled back, and the final database state.
|
||||
|
||||
## Migration Policy
|
||||
|
||||
- For local-first desktop applications, startup and migration recovery must follow the `local-first-recovery` contract.
|
||||
- Migrations are numbered sequentially and never modified after merge.
|
||||
- Trigger, take, and verify a fresh backup through the application-owned backup mechanism before applying migrations to any non-ephemeral database.
|
||||
- Each migration must be reversible where possible (document rollback in a comment).
|
||||
- Never rename a column in one migration step — add new, backfill, drop old across separate deploys.
|
||||
- Auto-apply migrations on startup is acceptable for internal tools; document if used.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Contract: Local-First Recovery
|
||||
|
||||
Version: 1.1
|
||||
Version: 1.2
|
||||
|
||||
## Purpose
|
||||
|
||||
@@ -53,7 +53,7 @@ For protected user data, destructive reset is forbidden.
|
||||
|
||||
Rules:
|
||||
- Do not drop, truncate, or recreate protected tables as a recovery shortcut.
|
||||
- Backup-before-change is mandatory and must follow the `backup-management` contract.
|
||||
- Backup-before-change is mandatory, must be performed automatically by the migration engine (never by the operator), and must follow the `backup-management` and `go-database` contracts.
|
||||
- Validate-before-migrate is mandatory.
|
||||
- Migration logic must use fail-safe semantics: stop before applying a risky destructive step when invariants are broken or input is invalid.
|
||||
- The application must emit explicit diagnostics that identify the blocked table, migration step, and reason.
|
||||
|
||||
Reference in New Issue
Block a user