# Changelog All notable changes to this project are documented here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project follows [Semantic Versioning](https://semver.org/). ## [Unreleased] ## [1.2.2] - 2026-08-22 ### Added - Added audited single-job and bulk recovery controls for jobs that are no longer running on their agents but remain stuck server-side. Agents now acknowledge unknown cancellation targets so orphaned jobs become terminal, while host ownership checks prevent cross-host updates. ([#56]) ### Fixed - Source-group JSON create and update requests now accept encrypted pre- and post-hooks, preserve hooks when their fields are omitted, allow explicit clearing, and expose only boolean presence indicators. ([#54]) - Generic backup-job requests without paths are rejected before a broken job is created. Configured run-now backups use the source-group endpoint. ([#55]) ## [1.2.1] - 2026-08-22 ### Fixed - Made the Agent updates host-selection screen stable and responsive: removed the redundant typed-count confirmation, corrected name/version/eligibility filtering, and stopped replacing idle or terminal controls through polling. Progress polling now runs only while a rollout is actively running. ([#50]) ## [1.2.0] - 2026-08-22 ### Added - Fleet-wide agent updates are now discoverable from Settings and the dashboard, with arbitrary host subsets, name/tag/version/eligibility filtering, explicit exclusion reasons, server-side membership validation, and a canary-first pause after the first verified reconnect. Halted rolls expose retry and resume actions. ([#43]) - Running jobs with no recent persisted activity are detected server-side and surfaced through deduplicated alerts. Kind-aware thresholds protect normal long-running work, terminal jobs self-resolve, and Prometheus exports stuck job count and oldest inactivity age. ([#41]) - Snapshot projections now retain host-level refresh timestamps—including authoritative empty reports—expose a derived stale flag, refresh after backup, forget, and prune, and support an explicit operator reconciliation endpoint. ([#40]) ### Fixed - Raised the bounded WebSocket read limit on both peers so ordinary large snapshot reports and restic events no longer disconnect otherwise healthy agents. Regression coverage exercises payloads beyond the library's former 32 KiB default in both directions. ([#44]) - Fleet-update timeout verification now performs a final authoritative read of the agent version delivered by the reconnect `hello`, avoiding a poll/deadline race and reporting the last observed version when verification fails. ([#43]) ### Changed - CI runner images and release images use the anonymous-pull `public` namespace at `docker.dcglab.co.uk`; registry authentication remains required only for publishing. ## [1.1.1] - 2026-08-22 ### Fixed - Prevented agents from panicking when a WebSocket connection ends. The WebSocket library transfers ownership of a successful upgrade stream to the connection and leaves the HTTP response body nil; attempting to close that body caused agents to restart and left forget jobs permanently stuck in `running`. ([#37]) - Manual forget jobs now receive the same per-source-group retention policies as scheduled forget jobs. The API also supports a validated `--dry-run` option through the complete server-to-agent-to-restic path, and rejects hosts without configured retention before creating a job. ([#36]) - Corrected the admin-credentials help text to reflect that forget uses normal append-only credentials and blank admin credentials do not provide a fallback for prune. ([#34]) ## [1.1.0] - 2026-06-15 ### Added - **Always-On vs intermittent host mode.** A host can now be marked as not always-on — for laptops/workstations that legitimately sleep, travel, or shut down outside hours. An intermittent host no longer raises "agent offline" alerts when it disappears; instead it shows a calm "asleep" state in the UI ("asleep · last seen … · will catch up on return") and is covered by a longer-horizon staleness alert (raised only when it has an enabled schedule and no successful backup in 7 days). When such a host reconnects, the server waits a short settle window and then automatically dispatches any scheduled backup whose window elapsed while it was asleep. Toggle per host from the host detail page (operator-band, audited as `host.mode_updated`). New and existing hosts default to always-on, so current fleets are unaffected. ### Changed - Host-detail header redesign: tags and presence are grouped into labelled, boxed pills with click-to-edit; presence shows a `24x7` / `Free` chip; the agent "out of date" indicator is simplified (the full version detail remains in the Agent-update panel and on hover). - Relative timestamps ("2h ago") now tick client-side, so a tab left open no longer shows a stale value as wall-clock time moves on. - Release and CI container images are now published to and pulled from the zot OCI registry (`docker.dcglab.co.uk`). ## [1.0.1] - 2026-05-09 ### Fixed - Build version is now single-sourced from `internal/version`, and the server Dockerfile's ldflags were corrected so docker-built binaries report their real version. Previously `internal/version.Version` stayed at its "dev" default in docker images, which made every host look permanently out-of-date to the update logic. ## [1.0.0] - 2026-05-09 First tagged release. Six development phases brought the project from empty repo to a self-hostable, multi-tenant restic backup orchestrator with a web UI, JSON API, and self-updating agent fleet. ### Phase 1 — MVP: enrolment, visibility, on-demand backup - HTTP server, SQLite store with migrations, AEAD-encrypted credentials at rest, Argon2id password hashing, session cookies. - WebSocket transport between server and agents (heartbeat, hello, schedule fan-out, job log streaming). - Agent install path for Linux (systemd unit + `install.sh`); one-time enrolment tokens with embedded repo credentials. - Run-now backup execution end-to-end, snapshot listing. - Server-side encrypted repo creds pushed to the agent on hello. ### Phase 2 — Scheduling, retention, repo operations - Source groups (paths + excludes + pre/post hooks + bandwidth caps) decoupled from schedules; a schedule fires a source group. - Cron-style schedules with retention policies, server-driven reconciliation push and ack. - `restic forget`, `prune`, `check`, `unlock` automation; periodic maintenance ticker with per-host stagger. - Pending-runs queue with backpressure (`max_concurrent_jobs` per host). - Repo stats panel on the host detail page (size, last-check, last- prune, stale-lock banner). - Auto-init of repos on first onboard with credential-failure surface on the host detail page. - Announce-and-approve enrolment path for hosts that don't have a pre-minted token (Ed25519 fingerprint, operator approves). - Windows agent: SCM service integration + `install.ps1` installer. - Cross-platform alt-enrolment (announce flow on Windows). ### Phase 3 — Restore, alerts, audit - Restore wizard: pick a snapshot, pick paths, pick a target (in-place / new directory), live progress. - Snapshot diff against parent. - Alert engine: per-source-group dedup, severity tiers, ack / resolve. - Live-refresh alerts table with severity cues. - Audit log UI with filters, sort, CSV export, payload-detail modal. ### Phase 4 — RBAC, OIDC, host tags - Role-based access control: viewer / operator / admin. - User management UI (invite, role change, disable, password reset). - Generic OIDC SSO with JIT user provisioning + role mapping. - Per-host tags with chip-row filter on the dashboard. ### Phase 5 — OSS readiness - mdBook-rendered docs site at `docs/book/`. - Contributor onboarding (CONTRIBUTING.md, security policy, license). - Docker-only release pipeline + reference deployment compose file. - Playwright e2e harness covering the smoke runbook. ### Phase 6 — Update delivery + observability - Agent self-update: server-side channel pin per host, signed binary fetch via the WS transport, atomic swap with rollback on failure. - Fleet-wide update orchestration with per-host stagger and an admin pause switch. - Prometheus `/metrics` endpoint + Grafana dashboard JSON. - Repo size trend per host (90-day rolling) on the host detail page. ### Cross-cutting - Live dashboard with column sort, filters, free-text host search, background-tab-aware live refresh (5s cadence). - Pure-Go binary with embedded UI, no Node/CGO at runtime. - Reproducible `-trimpath -ldflags="-s -w"` builds for linux/amd64, linux/arm64, windows/amd64. - Sharded CI (server-http / store / rest), pre-commit hooks (gofumpt, go vet, golangci-lint). - Threat model published (`docs/threat-model.md`). [Unreleased]: https://gitea.dcglab.co.uk/steve/restic-manager/compare/v1.2.2...HEAD [1.2.2]: https://gitea.dcglab.co.uk/steve/restic-manager/compare/v1.2.1...v1.2.2 [1.2.1]: https://gitea.dcglab.co.uk/steve/restic-manager/compare/v1.2.0...v1.2.1 [1.2.0]: https://gitea.dcglab.co.uk/steve/restic-manager/compare/v1.1.1...v1.2.0 [1.1.1]: https://gitea.dcglab.co.uk/steve/restic-manager/compare/v1.1.0...v1.1.1 [1.1.0]: https://gitea.dcglab.co.uk/steve/restic-manager/releases/tag/v1.1.0 [1.0.0]: https://gitea.dcglab.co.uk/steve/restic-manager/releases/tag/v1.0.0 [#37]: https://gitea.dcglab.co.uk/steve/restic-manager/issues/37 [#36]: https://gitea.dcglab.co.uk/steve/restic-manager/issues/36 [#34]: https://gitea.dcglab.co.uk/steve/restic-manager/issues/34 [#40]: https://gitea.dcglab.co.uk/steve/restic-manager/issues/40 [#41]: https://gitea.dcglab.co.uk/steve/restic-manager/issues/41 [#43]: https://gitea.dcglab.co.uk/steve/restic-manager/issues/43 [#44]: https://gitea.dcglab.co.uk/steve/restic-manager/issues/44 [#50]: https://gitea.dcglab.co.uk/steve/restic-manager/issues/50 [#54]: https://gitea.dcglab.co.uk/steve/restic-manager/issues/54 [#55]: https://gitea.dcglab.co.uk/steve/restic-manager/issues/55 [#56]: https://gitea.dcglab.co.uk/steve/restic-manager/issues/56