feat(admin): the nightly backup, made visible

It has run since the beginning and nothing showed it. A backup nobody can see is
a backup nobody knows has been failing, and the failure is quiet: a volume gone
read-only, a disk that filled, a container that has not been up at midnight all
week. The first anybody hears of it is the day they need one.

`ListBackupRuns` was already in the store and exposed nowhere. Now there is a
list, a download, and a button that takes one now — the same work the nightly job
does without its "one a day" check, because waiting until tonight to learn whether
backups work at all is how somebody finds out on the day they need one, and it is
the only way to get a snapshot from *before* something you are about to do.

Restoring is deliberately not a button. Swapping a database under a server that
is writing to it means stopping every writer, replacing the file and reopening,
and a half-done version of that destroys the thing it was restoring. The panel
says what to do instead.

`RunBackupNow` turns out to have been a second copy of the backup logic, written
for a button that did not exist yet, and the two had already drifted: it never
created the backups directory and logged nothing. One implementation now.

Administrators only, and sessions only. A backup is a complete copy of the
database, so this hands out everybody's data in one file.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Kristian Wind
2026-08-18 09:04:43 +02:00
co-authored by Claude Opus 5
parent 04a7ba1024
commit 1da7ea64bf
5 changed files with 471 additions and 37 deletions
+1 -1
View File
@@ -154,7 +154,7 @@ func TestBackupsRotateByCountNotAge(t *testing.T) {
}
}
if err := runner.rotateBackups(); err != nil {
if err := rotateBackups(cfg, runner.log); err != nil {
t.Fatalf("rotate: %v", err)
}