P5-01 — Documentation site under docs/book/ rendered with mdBook
(downloaded via Makefile, same static-binary pattern as Tailwind).
Structured chapters: getting started, concepts, operations,
security, reference. `make docs` / `make docs-watch`. Generated
output gitignored.
P5-02 — CONTRIBUTING.md rewritten from placeholder to a full
guide. CODE_OF_CONDUCT.md adapted from Contributor Covenant for a
single-maintainer project. .gitea/issue_template/{bug,feature}.md
and PULL_REQUEST_TEMPLATE.md.
P5-04 — Six README screenshots captured live from a fresh server
bootstrap (login, empty dashboard, add-host, alerts, settings,
audit log). README rewritten to centre the screenshot grid and
link out to the docs site.
P5-05 — SECURITY.md with disclosure policy (3-day ack, 30-day
default window), scope in/out, threat-model summary, operator
hardening checklist. Mirrored as a docs-site chapter.
P5-06 — End-to-end test harness. e2e/compose.e2e.yml brings up
server + sibling Linux agent (alpine + restic) + restic/rest-server.
Agent uses announce-and-approve so Playwright can drive the full
operator flow: bootstrap → login → accept pending → backup →
verify terminal status. Second spec scrapes /metrics to assert
the P6-04 endpoint surface. .gitea/workflows/e2e.yml runs on every
PR; local how-to in docs/e2e.md.
2.8 KiB
Backups and restores
Running a backup
Three ways to trigger one:
- Scheduled — the agent's local cron fires at the time set on the schedule.
- Run-now — operator clicks Run now on the host detail
right rail. Posts to
/hosts/{id}/run-backup(defaults to all source groups) or to a per-group form for finer control. - API —
POST /api/hosts/{id}/jobswith the appropriate payload. Same audit + dispatch path.
In every case the server creates a jobs row, broadcasts a
command.run to the host, and lands the operator on the live
job log page (HTMX HX-Redirect).
Cancelling a job
Any running job — backup, forget, prune, restore, anything —
exposes a Cancel button on its detail page. The server
broadcasts command.cancel, and the agent kills the running
restic subprocess via context cancel: SIGTERM first, SIGKILL
after a 5s grace (cmd.Cancel + cmd.WaitDelay). On Windows the
SIGTERM step is replaced with os.Kill because Windows can't
deliver SIGTERM. Result: a cancelled job lands as cancelled
within a couple of hundred milliseconds.
Restore wizard
Restoring a file or path goes through a four-step wizard at
/hosts/{id}/restore:
- Pick a snapshot. Search by id or by date; the page is pre-populated when you launched the wizard from a snapshot row.
- Browse the snapshot tree. Lazy-loaded children via the
MsgTreeListsynchronous WS RPC; results are cached per-wizard-session for 30 minutes. Pick the absolute paths you want. - Choose a target. Either In place (overwrites the
live filesystem; requires you to type the hostname to
confirm) or New directory (default
$HOME/rm-restore/<job-id>/; agent expands$HOME/${HOME}/~/and creates the directory chain). - Review and submit. Server mints a job, dispatches
command.runwith aRestorePayload, andHX-Redirects to the live job log.
--no-ownership is gated on restic ≥ 0.17 (the flag was added
in that release). Hosts running 0.16 don't get the flag and
restore as the running user instead.
Snapshot diff
Two snapshot ids in the Diff form on the host detail page →
a JobDiff job that runs restic diff <a> <b>. Output streams
to the standard live job log. Useful when investigating a
suspiciously-sized backup.
Job log artefacts
Every job's log is persisted in job_logs (one row per line),
not just streamed in-memory. That gives you:
- A live view at
/jobs/{id}while the job runs. - Two download formats from the same page header dropdown:
- txt — one line per row,
HH:MM:SS.mmm TAG payload. - ndjson — one self-contained JSON object per line
(
{seq, ts, stream, payload}), perfect forjq.
- txt — one line per row,
Downloads work whether the job is running or finished — the source is the DB, not the live socket.