Skip to content

Safe update + rollback UX (master) #140

Description

@frahlg

Goal

Build trust in a high-cadence auto-update flow. Operators should be able to:

  1. See what's changing before they click Update (feat(selfupdate): render changelog inline in update modal #139 ✓ — changelog inline).
  2. Have a safety net if they regret it (snapshot + rollback).
  3. Detect regressions quickly (post-update health check).
  4. Audit past updates (history).

High update cadence means every interaction matters — one bad update erodes months of accumulated trust.

Work breakdown

Phase 1 — Safe rollback bundle

  • Snapshot before update — sidecar dumps `state.db` (via `sqlite3 .backup`) + copies `config.yaml` into `snapshots/-pre--to-/` before `compose pull`. Retain last 5. Covered by a follow-up test suite.
  • Rollback-by-tag — API passes `target` through to the sidecar (sidecar already supports it). New endpoint `GET /api/version/releases` lists recent tags from GitHub so the UI can offer a picker.
  • Rollback UI — collapsible section in the update modal. Radio: "Keep current data" / "Restore snapshot from before the target version". Yellow warning for any backward step; red warning + explicit checkbox for > 1 minor version jump.

Phase 2 — Post-update health check

  • Frontend waits 30 s after sidecar reports `done`, pings `/api/status`, banner if any drivers offline or watchdog tripped.
  • Banner offers: Investigate | Roll back to previous snapshot.
  • No auto-rollback — too risky without human context.

Phase 3 — Update history

  • `GET /api/version/history` returns last 10 updates (ts, from→to, snapshot id, outcome).
  • UI "History…" button in modal renders the table.

Phase 4 — Breaking-change highlight

  • Detect `BREAKING CHANGE:` markers in release body (semantic-release emits them).
  • Render with red flag in the modal. Requires extra confirmation click before Update.

Out of scope (for now)

  • Canary/beta channel — premature; reconsider after ~20 deploys.
  • Schema versioning in `state.db` — use snapshot/restore instead of forward/backward migrations; revisit when we're actually burned.
  • Auto-rollback on health-check failure — dangerous without operator context.

Design notes

What to snapshot: only `state.db` + `config.yaml`. Parquet rolloffs are append-only (safe to keep). Lua drivers are checked-in or volume-mounted (not part of state).

Retention: last 5 snapshots. ~10-50 MB each on a warm system.

Rollback flavours:

  • Soft: switch image tag, keep current state. Works when forward-compat holds.
  • Hard: switch image tag + restore snapshot. For when state schema broke.

UI picks via a radio, defaults to soft.

PR sequence

  1. `feat(selfupdate): snapshot before update + rollback by tag` (Phase 1)
  2. `feat(selfupdate): post-update health check banner` (Phase 2)
  3. `feat(selfupdate): update history view` (Phase 3)
  4. `feat(selfupdate): highlight breaking changes in modal` (Phase 4)

Each PR links back here.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions