mirror of
https://github.com/Joulenap/joulenap.git
synced 2026-08-11 13:21:43 +02:00
docs: correct what a pre-release audit found across the shipped markdown
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.
This commit is contained in:
@@ -13,7 +13,8 @@
|
||||
|
||||
- **Web UI** (frontend): single-page app. Talks to the backend over the REST API below.
|
||||
- **Backend / API**: serves the UI, exposes the REST API, holds the scheduler, runs the route cycles, manages config.
|
||||
- **Scheduler**: in-process (APScheduler). **One cron trigger per enabled route**, plus a daily history-prune job (armed independently, so history is trimmed even while every route is paused). Re-armed whenever config changes. GC and verify have no triggers of their own — they are options of a route, or a manual action on a box.
|
||||
- **Scheduler**: in-process (APScheduler). **One cron trigger per enabled route**, plus a daily history-prune job and a one-minute liveness heartbeat (both armed independently, so history is trimmed and liveness recorded even while every route is paused). Re-armed whenever config changes. GC and verify have no triggers of their own — they are options of a route, or a manual action on a box.
|
||||
- **Startup catch-up**: the jobstore is in memory, so a fire due while the container was stopped is simply lost. At startup each armed route is checked for a slot that came due *while the process was not running*, and one is reported as a missed run (logged, and notified under `on_failure` — never auto-run: a restart must not kick off a heavy PBS-waking backup). "Not running" is a fact, not an inference: the heartbeat touches `data/.heartbeat` every minute and its mtime bounds the window, so a schedule edited to earlier in the day — or a route disabled and re-enabled, or the kill-switch — cannot be mistaken for downtime. No heartbeat on record (first boot, unwritable data dir) reports nothing.
|
||||
- **Run queue + power lease**: one run is ever in flight; the rest wait in a FIFO queue. Each PBS a run needs is held under a refcounted lease that wakes it on first acquire and powers it off on last release. See below.
|
||||
- **Connectors**:
|
||||
- `pve` — PVE API client (list guests, trigger `vzdump`, read task status).
|
||||
@@ -72,7 +73,7 @@ Only the last of those is worth a warning; the other three are the correct outco
|
||||
|
||||
`managed_power: false` describes an always-on PBS. The lease is the single place that knows: acquiring degrades to a reachability check and releasing does nothing.
|
||||
|
||||
**The lease is keyed per device, not per machine.** A backup server serving two datastores is two devices, so each holds its own lease and neither knows about the other: a run that finishes with the first can power the machine off while a queued run on the second still wants it, and that run then wakes it again. Runs are serialised by the single-run lock, so this costs one extra sleep/wake cycle rather than correctness — but on one physical box, prefer a single datastore, or expect the extra cycle.
|
||||
Because the key is the machine, a run holding one datastore of a box reports every device on that box as busy — which is what disables the ⏻ button on its siblings, since an SSH power-off would take the running server down with them.
|
||||
|
||||
|
||||
## What each kind does
|
||||
|
||||
@@ -40,7 +40,7 @@ For each field: **auto** = discovered/derived, **manual** = entered.
|
||||
| PBS host/IP, port | auto | read from the PVE storage config (manual in flow B) |
|
||||
| PBS datastore | auto | from the storage config |
|
||||
| PBS fingerprint | auto | from the storage config, or read from the PBS certificate on connect |
|
||||
| WoL broadcast interface | auto | the NIC with the route to the PBS subnet; override allowed |
|
||||
| WoL broadcast interface | auto | the NIC with the route to the PBS subnet; a dropdown lists the host's own NICs if you want to pin one |
|
||||
| PBS MAC | auto | connect + read ARP, with the PBS powered on ("Detect MAC") |
|
||||
| PBS API token | manual, or auto in root mode | see the privileges below |
|
||||
| PBS SSH host key | auto | scanned, shown, saved to `data/known_hosts` on your confirmation |
|
||||
|
||||
@@ -39,9 +39,10 @@ Integrations**; enabling the integration enables both.
|
||||
|
||||
1. Open Joulenap → **Settings → Integrations**.
|
||||
2. Click **Generate API key**. The key is shown once — copy it somewhere
|
||||
safe (a password manager, your dashboard's secret store, etc.). Joulenap
|
||||
only stores a copy needed to verify requests; it won't show you the key
|
||||
again.
|
||||
safe (a password manager, your dashboard's secret store, etc.). The
|
||||
interface will not show it again: like every other secret it lives in
|
||||
`config.yaml` and is redacted from every API response, so recovering it
|
||||
means reading that file on the host — or generating a new one.
|
||||
3. Pick your dashboard in the picker on that page to get a ready-to-paste
|
||||
config snippet with the key and endpoint URL already filled in.
|
||||
4. Disabling the integration (the **Disable** button) clears the key, and
|
||||
|
||||
+4
-4
@@ -1,13 +1,12 @@
|
||||
# Joulenap frontend
|
||||
|
||||
React + TypeScript + Vite SPA for Joulenap, recreated from the prototypes in
|
||||
`design/joulenap-remix/` and wired to the backend REST API.
|
||||
React + TypeScript + Vite SPA for Joulenap, wired to the backend REST API.
|
||||
|
||||
## Develop
|
||||
|
||||
```bash
|
||||
cd frontend
|
||||
npm install
|
||||
npm ci
|
||||
npm run dev # Vite dev server on :5173, proxies /api -> http://localhost:8080
|
||||
```
|
||||
|
||||
@@ -27,7 +26,8 @@ needs the built output present. `dist/` is git-ignored.
|
||||
|
||||
- `src/api/` — typed client + response types for `/api/*`
|
||||
- `src/auth/`, `src/config/` — auth + config React contexts
|
||||
- `src/pages/` — `Login`, `Dashboard` (+ `dashboard/` panels), `Settings` (+ `settings/` panels incl. the setup wizard)
|
||||
- `src/pages/` — `Login`, `Dashboard` (+ `dashboard/` panels), `Settings` (+ `settings/` panels, incl. the device editor)
|
||||
- `src/wizard/` — the two device wizards (add a PVE, add a PBS) and the PBS steps they share
|
||||
- `src/shell/` — header + authenticated app shell
|
||||
- `src/components/`, `src/hooks/`, `src/utils/` — shared widgets/helpers
|
||||
- `src/i18n/` — `react-i18next` setup; `en.json` is the base language, `it.json` the translation
|
||||
|
||||
Reference in New Issue
Block a user