Backup export: make ORDER BY drift-resistant (auto-discover stable columns, drop hardcoded names) #140
Reference in New Issue
Block a user
No description provided.
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Why
On 2026-05-26 the backup generator failed with:
Root cause:
internal/services/export_service.go:1566hardcodedORDER BY appointment_id, calendar_binding_idagainst a table whose real join column isbinding_id(mig 101). One-character bug.The immediate fix landed on main (commit on branch
mai/paliadin/fix-backup-binding-column). But the broader issue: every sheet inorgSheetQueries()hardcodes the ORDER BY columns. Same risk lurks on every other table — the next time someone renames a column, the backup silently breaks until someone tries to run it.m flagged it: "This needs to work and be flexible, too!"
Scope — make the exporter drift-resistant
Three levels, pick one:
idif the table has anidcolumn (auto-detect viainformation_schema.columns); otherwise fall back to no ORDER BY (deterministic-but-pg-order) with a WARN log. Keeps the deterministic-output contract for tables withid; gives up on the others. Smallest change, no manual maintenance.id(or nothing) when all named columns are gone.information_schema.columnsfor the table; ORDER BY all not-null FK / pk columns in declared order. Most clever, most surface to test, most likely to surprise.Recommended: (1) for the bulk, with explicit
OrderBy []stringper sheet where the natural order matters (e.g.caldav_sync_logkeyed byoccurred_at, id). Smallest blast radius.Worker scope
orgSheetQueries()to return(sheetName, table, orderBy?)triples instead of free SQL strings. Build the SQL at runtime via a query-builder helper that:information_schema.columnsquery at the start of each backup run).ORDER BY id; the few with multi-column orders (caldav_sync_log, project_teams, my_pinned_projects, ref__countries, ref__holidays, appointment_caldav_targets, backups) declare their lists.Acceptance
/admin/backups→ "Generate" succeeds against the live DB. Every sheet renders rows.DROP COLUMN xmigration in a test DB → next backup still succeeds, log shows a WARN about the dropped column.go test ./internal/services/...green incl. the new fixture test.Anti-patterns
DropColumns), secret-redaction, sheet-grouping logic untouched.deadline_ruleswrites or any other audit-triggered table; this is a read-only exporter refactor.