Files

Golden backups

One disaster-recovery backup file per release, written by that release's own exporter, and a manifest of what it held. tests/integration/golden-backups.test.ts uploads every file here through the admin upload route, restores it into an empty account through the restore route and job, exports the account again and checks the counts section by section against the manifest. A backup a person downloaded from an older release has to keep restoring after every later change; this is where that is held still.

File What it is
v<release>.json the file exactly as the exporter wrote it (compact JSON, never reformatted)
v<release>.manifest.json release, schema version, owner id, exportedAt, SHA-256, byte size, counts

The account is the shared backup seed (tests/integration/backup-fixture.ts: one row of every two-ended model plus the column shapes), so every section the backup writes holds at least one row. Ciphertext inside the file is sealed under the integration suite's fixed key (ENCRYPTION_KEY in vitest.integration.config.mts), so the file opens on every machine that runs the suite and no real key is involved.

Adding the next release's file

Once per release, on the release branch after the version bump, with Docker running:

GOLDEN_BACKUP_WRITE=1 pnpm vitest run --config vitest.integration.config.mts tests/integration/golden-backups.test.ts
pnpm vitest run --config vitest.integration.config.mts tests/integration/golden-backups.test.ts

The first command writes v<version from package.json>.json and its manifest; the second restores every file here, the new one included. Commit both files.

Never rewrite an existing release's file: the test checks each file against the SHA-256 in its manifest, because a file regenerated by today's exporter would prove only that today's exporter and today's restore agree. When a change means an old file can no longer restore as it was written, that is a breaking change to the backup format, and it is decided in the restore code, not by replacing the fixture.

A count the restore is documented to drop by age (a measurement tombstone past its retention) is listed in AGES_OUT in the test and may only go down.