Checked every tracked .md against the code rather than for plausibility. The
API table, the metric names, the dashboard payload, the permissions
cheat-sheet, every config field and SECURITY's numbers all already matched.
Four things did not.
ARCHITECTURE contradicted itself on the power lease: keying it on the host
updated the description a few lines up but left a later paragraph still saying
the lease is per device, complete with the extra sleep/wake cycle that no
longer happens. Replaced with the consequence that is now true -- every device
on a held machine reads busy, which is what disables the power button on its
siblings.
The startup catch-up was documented nowhere despite sending notifications.
ARCHITECTURE's scheduler section now covers it and the heartbeat that decides
what counts as downtime.
frontend/README pointed at design/joulenap-remix/, which .gitignore excludes --
a path no clone has. It also filed the setup wizard under the settings panels,
where it has not lived since it moved to src/wizard/, and said npm install
where the lockfile wants npm ci.
Two wordings tightened: the WoL interface is a dropdown now, not free text with
an override; and "stores a copy needed to verify requests" read as though the
API key were hashed, when it sits in config.yaml like every other secret.
Both files spent most of their length on content any given reader skips. The
three install paths are mutually exclusive and Option A is the recommended one,
yet B and C sat between its last step and First run -- a hundred lines
interrupting the path most people are on. The four dashboard snippets are the
same shape: a reader runs one of Homepage, Glance, Homarr or Dashy and scrolls
past the other three.
INSTALL keeps its Option B and Option C headings and collapses only the bodies,
because the file's own table of contents links to those anchors and a summary
in place of the heading would break them. The dashboard blocks have no
incoming links, so there the summary replaces the heading and names the widget
each one configures.
INTEGRATIONS' 0.9 -> 1.0 field mapping is collapsed too: it is legacy-only and
it was the first thing every reader met, including everyone who never ran 0.9.
Its summary keeps the words README and CHANGELOG use to point at it.
Visible length: INSTALL 339 -> 251 lines, INTEGRATIONS 397 -> 267. Reference
tables were deliberately left open -- find-in-page does not reliably reach
inside a collapsed block, which is the whole reason only alternatives and
legacy content are hidden.
Rewrite demoTimeline.ts around the three-route scenario and rebuild the
scripted replay inside devStub.ts on top of the 1.0 endpoints, then bring
the shipped documentation in line with what actually ships.
Demo:
- demoTimeline.ts keys its online windows by PBS id, so one field covers a
single-box backup and a sync route's two; steps carry the per-device
names the backend really emits, plus their detail.
- The demo auto-plays: it opens mid-backup on Nightly and the queued Lab
route starts by itself when that lands, with the target left awake
between them and the skipped power-off recording why. The queue and the
power lease are visible without a click.
- The clock ticks and the fixture calendar shifts by whole weeks, so
weekdays and times survive and the schedules stay self-consistent. Dev
stub mode keeps its frozen clock; every replay mutation sits behind the
demo flag.
- Restore the "fake data" banner and make logout reload rather than strand
the visitor on a login form.
- build:demo now type-checks first, which it never did.
Fix the expanded run history row refetching its detail only once, so a run
in flight showed a frozen step timeline while its task log kept streaming.
Docs:
- ARCHITECTURE: the route model, the queue and lease, a cycle per kind, the
migration, and REST tables rebuilt from the shipped routers.
- CONFIG-WIZARD: the two device flows, and the /remote grant a sync route
needs on a peer configured before 1.0.
- INTEGRATIONS: the new dashboard payload, snippets matching the ones the
app generates, the labelled metric names, and a 0.9 mapping table.
- README, INSTALL: routes, the five settings tabs, upgrading from 0.9, and
the Node version CI and the image actually build with.
- SECURITY: transport pinning, auth hardening, the two API-key endpoints
outside the session, and what Joulenap deliberately does not do.
- CONTRIBUTING: npm test is a separate CI step, and the demo section now
describes the demo that exists.
- CHANGELOG: the 1.0.0 entry, including the breaking dashboard and metrics
shapes and the exclude guest mode widening to all.
Run history in the UI: the activity card gains a second tab listing every run
with job type, trigger, result, duration and guest count. Rows expand in place
to that run's steps and log lines. Backed by /api/runs, which had existed since
0.1 with no consumer; RunSummary gains guests_ok.
Job cancellation: Run backup / Run GC turn into Stop while a job is in flight,
behind a confirmation that can also power the PBS off afterwards. Cooperative
cancellation checked in the existing poll loops (task wait, PBS wake wait,
between steps), and the underlying PVE/PBS task is stopped, not abandoned, so a
cancelled backup does not keep running on the server. A running verify is
stoppable too. Previously a stuck job blocked every later run and manual
power-off until restart.
Prometheus /metrics for Grafana, protected by the existing dashboard API key.
Sixteen gauges including per-guest last-backup times, so a guest dropping out of
the backup set can be alerted on. Written directly in the text exposition format
rather than adding a dependency; a scrape never wakes the PBS.
Notifications now name the job that ran: a failed verify or GC no longer reports
"backup failed".
Removed the dead backup.guests.auto_include_new key. It was never read, while
its name and default implied new guests were picked up automatically. Existing
configs still load (the key is stripped) and the docs now state the real rule.
Documentation accuracy pass over README, ARCHITECTURE, INSTALL, INTEGRATIONS,
SECURITY and config.example: corrected the PVE and PBS token privilege lists,
the garbage-collection and guest-selection descriptions, the supported-versions
table and the API reference, and added a Settings walkthrough.
Toggle switches are announced as switches by screen readers and can no longer
submit a surrounding form.
secrets.compare_digest() rejects non-ASCII str with TypeError, turning
the unauthenticated /api/dashboard endpoint's 401 path into a 500 when
an attacker sends a non-ASCII ?key= or X-API-Key. Compare as UTF-8
bytes instead, and add a regression test.
Also fix the Homepage integration snippet (UI + docs) referencing the
non-existent /favicon.svg; the app serves its icon at
/assets/joulenap-icon.svg.