# Backups and restores

## Running a backup

Three ways to trigger one:

1. **Scheduled** — the agent's local cron fires at the time set
   on the schedule.
2. **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.
3. **API** — `POST /api/hosts/{id}/jobs` with 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`:

1. **Pick a snapshot.** Search by id or by date; the page is
   pre-populated when you launched the wizard from a snapshot row.
2. **Browse the snapshot tree.** Lazy-loaded children via the
   `MsgTreeList` synchronous WS RPC; results are cached
   per-wizard-session for 30 minutes. Pick the absolute paths
   you want.
3. **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).
4. **Review and submit.** Server mints a job, dispatches
   `command.run` with a `RestorePayload`, and `HX-Redirect`s 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 for `jq`.

Downloads work whether the job is running or finished —
the source is the DB, not the live socket.
