Backup and Restore - jegr78/ctc-manager GitHub Wiki

Backup & Restore

Available since v1.10. Accessible at /admin/backup.

Overview

CTC Manager v1.10 ships a full database backup/restore feature for admins. A backup captures all 24 operative entity tables (seasons, matchdays, races, results, drivers, teams, etc.) and the uploads/ tree (team logos, race attachments) into a single ZIP. An import replaces the live database atomically — schema-version-gated to prevent catastrophic data loss across major versions.

The feature lives at /admin/backup. Every import is preceded by an automatic backup-before-import ZIP stored at <import-backups-dir>/<timestamp>/ for 24-hour manual recovery. The directory name is the import time plus the first eight characters of the audit id, so two imports in the same second keep separate archives.

Export

Backup page

  1. Sign in to the admin area and click Backup in the sidebar — you land on /admin/backup.
  2. Click Export Backup. A ZIP file (ctc-backup-<ISO-instant>.zip) is streamed to your browser immediately — no full-dataset buffering, so very large leagues download progressively.
  3. Store the ZIP in a safe location. The ZIP layout is:
    • manifest.json (first entry) — schema version + per-table row counts + export timestamp.
    • data/<entity>.json files — one per entity, JSON-serialized via the dedicated backupObjectMapper.
    • uploads/ — mirror of files actually referenced by entities (logos, attachments).

Import

Preview screen

  1. On /admin/backup, choose your backup ZIP via Import Backup and submit.
  2. Review the preview screen: per-table row counts (current vs. backup), the schema-version match indicator, and the upload-file count. The database is NOT touched until you confirm.
  3. Check the I understand confirmation and click Execute Import. The entire database is wiped and replaced inside a single transaction. The previous uploads/ tree is preserved at <import-backups-dir>/<timestamp>/uploads-old/ for 24-hour manual recovery.

While an import is in flight, every admin page shows a yellow read-only banner; any write attempt on another admin page is rejected with HTTP 503 until the import completes.

A save that started before the import finishes first: the import waits up to 30 seconds (app.backup.writer-drain-timeout) for such requests. If one is still running after that, the import aborts before the auto-backup and before any table or upload changes, and asks you to try again.

Read-only banner during import

Schema Version

The backup format carries a schema_version integer (currently 3). The import accepts versions 1, 2 and 3 and rejects any other version BEFORE any database write.

Every data file must hold exactly the rows the manifest announces for its table. A missing data file, a manifest-only archive or a changed row count rejects the backup at preview and again before the import wipes any table. The only permitted gaps are tables an older version did not export: a version 1 backup has neither the Discord tables nor site_slugs, a version 2 backup has no site_slugs. The error names every table that does not match. An archive with two entries of the same name is rejected as unsafe.

The schema version is bumped manually when the on-disk wire shape changes incompatibly (added / removed / renamed entity fields, FK changes).

Recovery

If an import fails or you need to revert to the pre-import state:

  1. The pre-import automatic backup is at <import-backups-dir>/<timestamp>/auto-backup-before-import.zip.
  2. The previous uploads/ tree is at <import-backups-dir>/<timestamp>/uploads-old/.
  3. <import-backups-dir> is data/<profile>/import-backups/ on a host JVM and /app/data/import-backups/ (volume ctc-data) in a container.
  4. Both are retained for 24 hours. Step-by-step recovery is documented in the operator runbook:

docs/operations/import-runbook.md

The runbook covers: re-importing the pre-import auto-backup, manually restoring the uploads-old/ tree, and verifying integrity via the data_import_audit table.

Screenshots

All screenshots are stored in the main repository under .screenshots/77/ and embedded here via stable raw.githubusercontent.com/jegr78/ctc-manager/master/ URLs:

The wiki repo does NOT carry binary screenshot copies — the URLs point at the main repo's master branch, so when screenshots are re-captured in a future phase, this wiki page auto-updates without any wiki-side change.

⚠️ **GitHub.com Fallback** ⚠️