mirror of
https://github.com/Joulenap/joulenap.git
synced 2026-08-11 13:21:43 +02:00
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.
518 lines
32 KiB
Markdown
518 lines
32 KiB
Markdown
# Changelog
|
|
|
|
All notable changes to Joulenap are documented here.
|
|
|
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project
|
|
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
|
## [1.0.0]
|
|
|
|
Joulenap is no longer built around one Proxmox host backing up to one backup server. It now models
|
|
**devices** — any number of PVEs and any number of PBSs — and **routes** between them. Existing
|
|
configurations are converted automatically on the first start; see Changed below for the one
|
|
conversion that is lossy, and for the two breaking changes outside the interface.
|
|
|
|
### Added
|
|
|
|
- **Routes.** A route is one scheduled flow of backup data between devices: sources, a target, its
|
|
own time and weekdays, its own retention, its own options. Four kinds, inferred from the devices
|
|
you pick: **backup** (one or more Proxmox hosts into a backup server, including a fan-in from
|
|
several at once), **sync** (one backup server into another, pull or push, for a real off-site
|
|
second copy), **external** (Joulenap starts nothing and only watches the jobs PVE and PBS run on
|
|
their own schedules), and **verify**. Guests are selected per source, because vmids collide
|
|
between hosts.
|
|
- **Multiple Proxmox hosts and multiple backup servers.** Each is a device with its own address,
|
|
scoped token, TLS fingerprint and — for a backup server — its own wake-up and power-off settings.
|
|
A backup server you keep powered on all the time is supported: turn `managed_power` off and
|
|
Joulenap treats it as always available instead of trying to wake it.
|
|
- **A run queue and a per-server power lease.** One run is ever in flight; the rest wait their turn
|
|
instead of being dropped. Each backup server a run needs is leased: the first holder wakes it, the
|
|
last release powers it off — and only if nothing still queued needs it, the run succeeded, and you
|
|
did not ask to keep it on. So two routes an hour apart on the same box wake it once, and a sync
|
|
route wakes both boxes and releases them independently. The power-off step in the run timeline
|
|
says which of those happened.
|
|
- **A rebuilt interface.** The homepage is now an operations view: a live topology of your hosts and
|
|
backup servers with the routes drawn between them, the route strip where routes are created,
|
|
edited, paused and run by hand, what is coming up next, and a run history whose rows expand into a
|
|
per-step timeline with the PVE/PBS task output streaming underneath. Settings became five tabs
|
|
(Devices, Account, Notifications, Integrations, Advanced) with a device card and edit modal for
|
|
every box, and a removal guard that names the routes still using one.
|
|
- **Two guided wizards, replacing the single linear setup.** *Add a Proxmox VE* connects and then
|
|
reads that host's storage configuration to discover the backup servers behind it, linking the ones
|
|
you already registered and offering to configure a new one inline. *Add a Proxmox Backup Server*
|
|
walks connection, wake-up (with a Test button that sends a real magic packet before you find out
|
|
at 04:00 that Wake-on-LAN was never armed) and power-off. Both work from pasted API tokens, or
|
|
provision everything themselves from a root login used once and never stored.
|
|
- **Ad-hoc maintenance per backup server.** Run a garbage collection or a verification on one box
|
|
from the homepage, without a route. It queues and reports like any other run; only the route
|
|
column is empty.
|
|
- **A route can be stopped and a `config.yaml` can be exported.** Stopping a run also stops the
|
|
PVE/PBS task behind it and asks whether to power the server down.
|
|
|
|
### Changed
|
|
|
|
- **`GET /api/dashboard` and `/metrics` changed shape, and this breaks existing widgets and
|
|
alerts.** With several routes and several backup servers there is no single "next run" or "the
|
|
datastore" left to report. The dashboard payload is now `{state, routes[], pbss[]}`, so a widget
|
|
picks a list entry (`routes.0.next_run`) instead of a flat field. Prometheus series are labelled:
|
|
`joulenap_next_run_timestamp_seconds` became
|
|
`joulenap_route_next_run_timestamp_seconds{route="..."}`, the `joulenap_last_run_*` family became
|
|
`joulenap_route_last_run_*{route="..."}`, every PBS and datastore series carries `pbs=`, and
|
|
per-guest freshness is now labelled `{vmid, pve, pbs}` because a vmid alone stopped being unique.
|
|
The field-by-field mapping is at the top of `docs/INTEGRATIONS.md`, and Settings → Integrations
|
|
always shows a snippet generated for the version you are running.
|
|
- **Your `config.yaml` is migrated automatically, with a parachute.** The `pve:`, `pbs:` and
|
|
`backup:` sections become `pves[]`, `pbss[]` and `routes[]` on the first start after the upgrade:
|
|
the backup job becomes a route named Backup, a scheduled verification becomes one named Verify,
|
|
and schedules, guest selections and retention come across with them. The original file is copied
|
|
to `config.yaml.pre-overhaul.bak` first, and if the converted config fails validation the original
|
|
is kept, the app starts on it, and the reason appears as a banner rather than the app looking like
|
|
a fresh install.
|
|
- **The `exclude` guest mode is gone, and a migrated route widens to "all guests".** Inverting an
|
|
exclusion list needs a live guest list that is not available while the config is being read, so
|
|
such a route is converted to "all" and a warning is logged. It will back up *more* than before,
|
|
never less — but it is worth checking after the upgrade.
|
|
- **Garbage collection and verification are per-route options**, set in the route editor's Advanced
|
|
section, rather than global maintenance settings. `maintenance:` now holds only how long run
|
|
history is kept.
|
|
- **Guest selection and retention moved out of Settings** and into the route that uses them. So did
|
|
backup mode, the bandwidth cap and the minimum-free-space check. Wake timeout, Wake-on-LAN retries
|
|
and the external-watch timeouts belong to a backup server and live on its device card.
|
|
- **`GET /api/guests` now requires a `?pve=` parameter** and reports, per guest, which backup servers
|
|
hold a snapshot of it. Collapsing newest-per-vmid across every host would have shown the wrong
|
|
host's backup date once a second one existed.
|
|
- **Notifications name the route** and no longer describe every missed run as a missed backup. A run
|
|
that fails reports its error translated, in the interface as well as in the notification.
|
|
|
|
### Removed
|
|
|
|
- **The single `pve:` / `pbs:` / `backup:` config sections**, along with `pve.node` (cluster nodes
|
|
are discovered at runtime, which is also how a cluster is detected) and `pve.storage_id` (a host
|
|
now maps each backup server to the storage it uses for it).
|
|
- **External schedules as a global mode.** It is a route kind now, so one backup server can be
|
|
watched while another is driven by Joulenap — which the global switch made impossible.
|
|
- **The endpoints the single-job model needed**: `POST /api/backup/run`, `POST /api/gc/run`,
|
|
`POST /api/jobs/cancel`, `POST /api/power/on`, `POST /api/power/off`, `POST /api/wol/test` and
|
|
`POST /api/wizard/reset`. Their replacements are `POST /api/routes/{id}/run`,
|
|
`POST /api/devices/pbss/{id}/gc` and `/verify`, `POST /api/runs/{id}/stop`,
|
|
`POST /api/devices/pbss/{id}/power` and `POST /api/wizard/wol/test`.
|
|
|
|
### Fixed
|
|
|
|
- **A sync route worked once and then never again.** Proxmox Backup Server refuses to delete a
|
|
remote that a sync job still references, so the second run of any sync route failed. The job is
|
|
now removed before the remote is touched. Two related failures went with it: the run and delete
|
|
calls reject the `sync-direction` parameter the create call requires, and listing sync jobs with
|
|
the server's default hid push jobs, so an existing one was never cleaned up and the create that
|
|
followed failed with "job already exists".
|
|
- **A wizard run could break the backup server you added first.** Generating the SSH key overwrote
|
|
the one shared file every server's configuration points at, leaving the first box with an
|
|
`authorized_keys` line no private key matched — and nothing in the interface said so. The key is
|
|
now created only when there is none, and the wizard says it is reusing the existing one.
|
|
- **A token provisioned by the wizard could not create a remote or a sync job at all**, because
|
|
nothing was granted at `/remote`. Provisioning now grants both `RemoteAdmin` and
|
|
`RemoteSyncPushOperator` while it still holds the root ticket. A server set up before this — or
|
|
one whose token you pasted by hand — needs the grant applied by hand on the box; the command is in
|
|
`docs/CONFIG-WIZARD.md`.
|
|
- **A sync task ending in warnings surfaced as a bare task id.** It now names the direction, both
|
|
servers, the exit status and the first warning or error line from the task log.
|
|
- **Two forms on the same Settings tab discarded each other's unsaved changes.** The unsaved-changes
|
|
guard tracked only one form at a time, so the second to appear silently replaced the first — which
|
|
was already happening in 0.9's Advanced tab.
|
|
- **An interface translated into Italian had English gaps in it**, including a backup-mode dropdown
|
|
under a translated label, a schedule that lost its preposition, and six counts that spelled their
|
|
plural in English ("1 events").
|
|
|
|
### Security
|
|
|
|
- **Every backup server is pinned and verified independently** — its own TLS certificate fingerprint
|
|
for API calls, its own SSH host key confirmed during setup and stored in `data/known_hosts`.
|
|
- **The pre-migration `config.yaml.pre-overhaul.bak` is written with 0600 permissions.** It holds
|
|
every token, password hash and secret in the old config, and a plain file copy does not carry
|
|
permission bits across.
|
|
- **Redacted secrets are matched to devices by id** when a configuration is saved, not by their
|
|
position in a list. Reordering or shortening the device lists can no longer map a redaction
|
|
placeholder onto a different device's stored secret.
|
|
|
|
## [0.9.0]
|
|
|
|
### Added
|
|
|
|
- **External schedules mode.** For setups whose backup, prune, GC and sync jobs are already
|
|
scheduled natively on PVE/PBS: Joulenap can now act purely as the power manager — at the
|
|
scheduled time it wakes the PBS, watches the tasks the servers start on their own, and
|
|
powers it off once they have been quiet for a configurable window. Selected with a new
|
|
switch at the top of the Schedule card ("Scheduled by Joulenap" / "External schedules");
|
|
in external mode Joulenap starts no backup or GC of its own, and the run history records
|
|
the watch as its own run kind with the number of tasks observed. A wake where no job ever
|
|
appears still powers the PBS back off and says so in the notification, so a misfiring
|
|
PVE/PBS schedule is noticed instead of silently missed. (#27)
|
|
- **Live demo build.** `npm run build:demo` emits a self-contained copy of the UI that answers
|
|
its own API calls from fixtures, so it can be hosted as static files (joulenap.com/demo).
|
|
It opens on the dashboard with no login, carries an orange banner making clear the data is
|
|
fake, and replays a scripted backup cycle — wake, vzdump, prune, GC, power off — when you
|
|
press Run backup now, with the task log streaming and a new row landing in the run history.
|
|
The regular `npm run build` that the container image uses never includes any of it.
|
|
|
|
## [0.8.0]
|
|
|
|
### Added
|
|
|
|
- **Notifications say a lot more.** Every run notification now opens with what started the run
|
|
(scheduled or manual), breaks the duration down by phase (`12m 34s (backup 7m 10s · GC 1m 6s)`),
|
|
reports guests as a fraction with the names of the ones that failed
|
|
(`Guests: 12/14 (failed: web01, db02)`), and closes with the next scheduled run and the run
|
|
number. The alert for a run a restart interrupted also states how long the PBS has been awake.
|
|
All of it is translated in both languages.
|
|
- **Run history shows the run number.** A new first column, so the `Run #128` a notification
|
|
quotes can actually be looked up in the interface.
|
|
- **A failed backup names the guest that broke.** Proxmox runs one vzdump task for all selected
|
|
guests, so a single guest failing used to fail the run with no indication of which one; the
|
|
outcome is now read off the task log as it streams, so the notification can name it.
|
|
|
|
### Fixed
|
|
|
|
- **Notification bodies keep their line breaks.** Channels that deliver in HTML (email, Telegram)
|
|
collapsed the whole body onto a single line because Apprise was never told the text was plain
|
|
text.
|
|
- **Notification timestamps all use the configured timezone.** In the missed-backup alert the
|
|
"Last backup run" line was rendered in UTC while the two lines around it used `app.timezone`,
|
|
so the same message could disagree with itself by hours.
|
|
|
|
## [0.7.0]
|
|
|
|
### Added
|
|
|
|
- **Light theme.** The interface now ships the light theme that `app.theme` always promised: a
|
|
header toggle (moon/sun, sitting between the Settings and Logout buttons) switches the whole
|
|
interface — dashboard, settings, dialogs and the config.yaml editor included — with a short
|
|
cross-fade, and remembers the choice in `config.yaml` so it survives restarts and follows you to
|
|
other browsers. The login screen picks up the last theme used on that device. Dark remains the
|
|
default, and existing installations that never touch the toggle look exactly as before. Users who
|
|
have asked their system to reduce motion get an instant switch instead of the fade.
|
|
|
|
### Fixed
|
|
|
|
- **The `app.theme` config value is honoured.** It was accepted and stored since 0.1.0 but never
|
|
read; setting it to `light` now actually applies the light theme at startup.
|
|
- **Header buttons render at the same height.** The Logout button was a few pixels shorter than
|
|
its neighbours.
|
|
|
|
## [0.6.0]
|
|
|
|
### Added
|
|
|
|
- **Run history in the interface** — the activity card now has two tabs. Alongside the familiar
|
|
activity log there is a Run history table listing every run with its job type, what triggered it,
|
|
the result, how long it took and how many guests it covered. Clicking a run expands it in place to
|
|
show each step (wake, wait, backup, garbage collection, verify, power-off) with its own duration
|
|
and outcome, plus that run's log lines. Failures show their error without expanding. The history
|
|
is kept for as long as `maintenance.history.retention_days`, which the panel states.
|
|
- **Stop a running job** — the Run backup and Run GC buttons turn into a Stop button while a job is
|
|
in progress, with a confirmation dialog that can also power the PBS off once the job has stopped.
|
|
Stopping also cancels the underlying task on the Proxmox side, so a cancelled backup does not keep
|
|
running on the server after Joulenap has stopped watching it. A scheduled verify can be stopped
|
|
the same way. Previously a stuck backup or an unreachable PBS blocked every later job — and manual
|
|
power-off — until the container was restarted.
|
|
- **Prometheus metrics for Grafana** — a new `/metrics` endpoint, protected by the same read-only
|
|
API key as the dashboard integration, exposing PBS power state, scheduler state, the last run's
|
|
result and duration, datastore usage, run counts, and the last backup time of every individual
|
|
guest. Scraping never wakes the PBS, and cached values keep reporting while it sleeps. This makes
|
|
it possible to alert on a guest quietly dropping out of your backup set; `docs/INTEGRATIONS.md`
|
|
has the scrape configuration, the full metric list, example queries and ready-made alert rules.
|
|
|
|
### Changed
|
|
|
|
- **Notifications name the job that ran.** A scheduled verification or a garbage-collection run that
|
|
failed used to notify "backup failed"; each job type now reports its own outcome, in English and
|
|
Italian.
|
|
- **Removed the `backup.guests.auto_include_new` setting.** It never had any effect, while its name
|
|
and default implied newly created guests were picked up automatically. Existing configuration
|
|
files keep working — the key is ignored and dropped on the next save. The behaviour it seemed to
|
|
promise is what "all" and "exclude" mode already do; "include" mode is, and always was, an
|
|
explicit list. The documentation now says so.
|
|
- **Documentation accuracy pass.** Corrected the guest-selection and garbage-collection
|
|
descriptions, the Proxmox VE token privilege list (which omitted `Datastore.Audit` and
|
|
`Datastore.Allocate`, so a manually created token would fail at prune time), the Proxmox Backup
|
|
Server token privileges, the supported-versions table, and the API reference, which was missing
|
|
several endpoints. Added a walkthrough of the Settings tabs to the install guide.
|
|
|
|
### Fixed
|
|
|
|
- Toggle switches are now announced correctly by screen readers, and can no longer submit a
|
|
surrounding form by accident.
|
|
- Repaired three changelog comparison links that pointed at version tags which were never published.
|
|
|
|
## [0.5.0]
|
|
|
|
### Added
|
|
|
|
- **Update check (opt-in, off by default)** — Joulenap can ask GitHub once a day whether a newer
|
|
release exists and show a badge in the footer linking to the release notes. It is disabled
|
|
unless you turn it on in Settings -> Integrations: with it off the app makes no outbound
|
|
internet request at all. The check never runs as part of the container healthcheck.
|
|
- **Advanced settings tab** — the settings that previously existed only in `config.yaml` now have a
|
|
home in the interface: backup mode (snapshot / suspend / stop), bandwidth limit, the keep-last and
|
|
keep-yearly retention buckets, how long run history is kept, and the server's port, session
|
|
lifetime and HTTPS-only cookie flag.
|
|
- **Edit config.yaml from the browser** — the same tab embeds a YAML editor with syntax
|
|
highlighting for the whole configuration, so anything the forms don't cover is still reachable
|
|
without shelling into the container. Secrets are shown as `***REDACTED***` and are never sent to
|
|
the browser; leaving them untouched keeps the stored value. The document is validated before
|
|
anything is written, a key you delete keeps its current value, and a Copy button gives you a
|
|
secret-free copy of your configuration to attach to a bug report.
|
|
|
|
## [0.4.4]
|
|
|
|
### Changed
|
|
|
|
- **Accessible confirmation dialog** — the dialog shown before every backup, GC, power-off, and
|
|
reset is now fully keyboard- and screen-reader-accessible: it identifies itself as a dialog,
|
|
keeps focus inside while open, closes on Escape, and returns focus to the button that opened it.
|
|
- **Self-hosted fonts** — the interface fonts (IBM Plex) are now bundled with the app instead of
|
|
being fetched from Google Fonts, so the UI makes no third-party request on load and renders
|
|
correctly fully offline or air-gapped.
|
|
- **Sign-in screens** — the login and first-account screens are now proper forms with correct
|
|
autocomplete hints, so password managers fill and save credentials reliably; the button shows
|
|
progress while signing in.
|
|
|
|
### Fixed
|
|
|
|
- **Header status label** — the header now reads "GC running" or "Verify running" during those
|
|
jobs, instead of always saying "Backup running".
|
|
- **Selective backup with no guests** — choosing Selective mode with no guests selected is now
|
|
blocked with an explanation, instead of silently saving a schedule that wakes the PBS and backs
|
|
up nothing.
|
|
- **Setup wizard error visibility** — an error on a lower wizard step now scrolls into view (and is
|
|
announced to screen readers) instead of appearing off-screen, and "Detect MAC" now tells you when
|
|
auto-detection found nothing instead of doing nothing.
|
|
- **Empty guest list** — the guest panel now shows a "No guests found" message when a node has no
|
|
guests, instead of a blank area.
|
|
|
|
## [0.4.3]
|
|
|
|
### Added
|
|
|
|
- **Unsaved-changes guard** — editing a settings tab (Localization, Notifications, Backup safety)
|
|
or the scheduler and then navigating away now asks before discarding the edits, instead of
|
|
losing them silently. Also warns on a browser tab close or refresh while there are unsaved
|
|
changes.
|
|
- **Request timeout** — the UI now shows a clear "timed out" message instead of hanging
|
|
indefinitely if the backend stops responding.
|
|
|
|
### Fixed
|
|
|
|
- **Setup wizard validation** — a step no longer completes, and Save no longer unlocks, when a
|
|
check fails: an unreachable PBS, a missing PBS API token, or an empty Wake-on-LAN MAC now
|
|
block completion instead of saving a broken configuration.
|
|
- **Setup wizard re-save** — no longer reverts a hand-configured Proxmox VE port or TLS setting.
|
|
- **Manual actions** — Run backup, Run GC, and Power on/off now show the error when they fail to
|
|
start, instead of appearing to do nothing.
|
|
- **Scheduler toggle** — the Enabled switch now explains why it reverted when the change fails,
|
|
instead of silently flipping back.
|
|
- **Live task log** — no longer occasionally shows duplicated lines.
|
|
- **Guest list** — keeps the last-known guests (with an error note) when a refresh fails, rather
|
|
than blanking to an empty panel. What gets backed up is unaffected: the guest set is resolved
|
|
live at backup time.
|
|
- **Localization tab** — no longer shows a "Saved" note before anything was saved, and its
|
|
fields resync if the configuration changes underneath.
|
|
- **Integrations copy** — corrected contradictory text about regenerating the API key.
|
|
Regenerating replaces the key and the old one stops working immediately.
|
|
|
|
## [0.4.2]
|
|
|
|
### Added
|
|
|
|
- **Missed-backup alert** — if a scheduled backup was due while Joulenap was down (for example
|
|
the container was stopped over the backup window), it is detected at the next startup and a
|
|
notification is sent. The backup itself is not run automatically — use "Run backup" if you
|
|
want it immediately.
|
|
- **Interrupted-run alert** — a run left unfinished by a restart is reported at startup, warning
|
|
you when the PBS was left powered on so you can check on it.
|
|
- **Setup prompt on the dashboard** — when Proxmox VE and PBS aren't configured yet (a fresh
|
|
install), the dashboard shows a banner that links straight to the setup wizard.
|
|
|
|
### Changed
|
|
|
|
- **Backup notifications now warn when the PBS was left powered on for failed and aborted runs**,
|
|
not only for successful ones — so an energy-costing "still awake" box is never silent.
|
|
- **The Scheduler "Apply changes" action now shows saving / saved / error feedback** and can't be
|
|
double-submitted, matching the settings tabs; a failed save surfaces the reason instead of
|
|
doing nothing.
|
|
|
|
### Fixed
|
|
|
|
- **Session expiry no longer leaves the UI showing stale data.** When the session expires (or the
|
|
backend restarts), the app returns to the login screen with a notice instead of rendering a
|
|
frozen last-known status indefinitely; a "can't reach Joulenap" banner appears while the backend
|
|
is unreachable and clears on recovery.
|
|
- **An invalid Wake-on-LAN MAC address is now rejected when you save the configuration** (with a
|
|
clear error) instead of being accepted and only failing later at backup time.
|
|
|
|
## [0.4.1]
|
|
|
|
### Fixed
|
|
|
|
- **SQLite concurrency** — the database is opened in WAL mode with a busy timeout, so a
|
|
running backup cycle's frequent commits no longer risk "database is locked" errors against
|
|
the dashboard's polling; foreign-key enforcement is also enabled.
|
|
- **Manual power-off race** — powering the PBS off manually now holds the single-run lock
|
|
across the operation, so a scheduled cycle can't start in the gap and get its PBS shut down
|
|
mid-backup.
|
|
- **Job-lock leak** — if a worker thread fails to start (e.g. resource exhaustion), the run is
|
|
marked failed and the single-run lock is released, instead of being held forever and
|
|
blocking every later run until restart.
|
|
- **History-prune timezone** — a timezone change applied at runtime now moves the daily prune
|
|
job into the new zone, instead of leaving it in the boot-time zone until restart.
|
|
|
|
### Security
|
|
|
|
- **`config.yaml` written owner-only (0600)** — the config file holds API tokens, the session
|
|
key, and notification secrets, so it is now created with owner-only permissions (matching the
|
|
SSH key) instead of the default world-readable mode.
|
|
|
|
## [0.4.0]
|
|
|
|
### Added
|
|
|
|
- **"Keep PBS on" after a manual job** — the Run backup / Run GC confirmation now offers a
|
|
toggle to leave the PBS powered on after the job instead of powering it back off. It defaults
|
|
to the PBS's current state: a box that is already awake (for example, woken for a restore)
|
|
stays on, while one that was asleep goes back to sleep afterwards. `POST /api/backup/run` and
|
|
`POST /api/gc/run` accept an optional `{"keep_on": true}` body. Scheduled runs always power
|
|
off, unchanged.
|
|
- **Manual GC now wakes the PBS** — "Run GC" runs as a full wake to GC to power-off cycle, so it
|
|
works against a normally-off PBS instead of failing when the box is asleep.
|
|
|
|
### Changed
|
|
|
|
- Manual **Run backup / Run GC** are now available while the PBS is asleep — they wake it
|
|
themselves, so they only require that no other run is already in progress.
|
|
- Changing the admin account now requires confirming the current password (`PUT /api/account`),
|
|
so a stolen session alone can no longer rotate the credentials.
|
|
|
|
### Fixed
|
|
|
|
- **Setup wizard no longer wipes the PVE token secret on re-save.** Re-saving a completed wizard
|
|
sent an empty secret, which the backend read as "clear it" — silently breaking every
|
|
subsequent backup. The wizard now preserves the stored secret unless a new one is entered.
|
|
- **`exclude` guest mode is no longer inverted.** The dashboard showed an `exclude` list as a
|
|
selective (include) set and, on Apply, rewrote it as `include` — flipping the backup set to
|
|
exactly the guests meant to be skipped. Exclude mode is now shown read-only (edit `config.yaml`
|
|
to change it) and preserved on save.
|
|
- **An invalid backup cron no longer bricks startup.** An unparseable `backup.schedule` is now
|
|
rejected on save (`422`) and, if already present on disk, is skipped with a warning instead of
|
|
crashing the scheduler on every restart.
|
|
|
|
## [0.3.1]
|
|
|
|
### Changed
|
|
|
|
- **Responsive layout** — the dashboard, header, and settings screen now adapt to narrow
|
|
screens under a single `900px` breakpoint. The settings sidebar collapses into a 2-column
|
|
grid of buttons on a phone. Desktop rendering is unchanged.
|
|
|
|
### Added
|
|
|
|
- A dev-only API stub (`frontend/src/devStub.ts`, `npm run dev -- --mode stub`) so
|
|
contributors can work on the UI — including the full setup wizard — against fixture data,
|
|
without a backend or a real Proxmox. See [`CONTRIBUTING.md`](CONTRIBUTING.md).
|
|
|
|
## [0.3.0]
|
|
|
|
### Added
|
|
|
|
- **Per-channel notification report** — the "Send test" button now shows one row per channel with
|
|
its own result, instead of a single "Test failed" that could not say which channel broke or why.
|
|
A failing ntfy no longer makes a working Telegram look broken, and the reason reported by the
|
|
delivery engine (unreachable host, `401 Unauthorized`, and so on) is shown next to the channel
|
|
that produced it. Secrets are stripped from the reason before it leaves the backend.
|
|
- Failed notifications during a scheduled backup are now logged with the channel name and the
|
|
reason. Previously a channel that quietly stopped working left no trace anywhere.
|
|
|
|
### Changed
|
|
|
|
- `POST /api/notify/test` always answers `200` and returns the per-channel report as
|
|
`{"channels": [{"channel", "ok", "error"}, ...]}`. It no longer returns `400` when no channel is
|
|
configured (the report is simply empty) nor `502` when delivery fails — a delivery failure is a
|
|
result, not a transport error. Anything scripting this endpoint and treating a `502` as "the test
|
|
failed" must now read `ok` per channel instead.
|
|
- Frontend dependencies moved to React 19, Vite 8, i18next 26 and TypeScript 6.
|
|
|
|
### Fixed
|
|
|
|
- A notification sent by the scheduler and a manual test running at the same time could attribute
|
|
one channel's failure reason to another. Each send now captures only its own thread's records.
|
|
- An exception raised while parsing a channel's Apprise URL could reach the container logs with the
|
|
URL, and therefore its credentials, unredacted.
|
|
- The Docker image builds the web UI on Node 24, matching CI.
|
|
- On a transport error the test button no longer reports "couldn't save changes" for an action that
|
|
saved nothing.
|
|
|
|
## [0.2.0]
|
|
|
|
### Added
|
|
|
|
- **Dashboard integration** — a read-only, API-key-protected `GET /api/dashboard` endpoint plus a
|
|
Settings → Integrations panel (generate/rotate/disable the key and copy a ready-made config
|
|
snippet) so Joulenap's status — PBS power state, next/last run, datastore usage — shows on
|
|
homelab dashboards like Homepage, Homarr, Dashy, and Glance. See
|
|
[`docs/INTEGRATIONS.md`](docs/INTEGRATIONS.md).
|
|
- **Persistent datastore usage** — disk used/total is cached whenever the PBS is awake and shown in
|
|
the web UI and the dashboard endpoint even while the PBS is powered off.
|
|
|
|
### Fixed
|
|
|
|
- Copy buttons now work over plain HTTP (a non-secure browser context) via a clipboard fallback, so
|
|
the API key and config snippets copy correctly when Joulenap is reached at a LAN `http://` address.
|
|
|
|
## [0.1.0] — first public release
|
|
|
|
The first release of Joulenap: schedule energy-saving Proxmox backups to a normally-off Proxmox
|
|
Backup Server, all from a web UI.
|
|
|
|
### Added
|
|
|
|
- **Backup cycle** — an in-process scheduler runs the full wake → wait → backup → maintenance →
|
|
power-off cycle; nothing on the Proxmox host is modified.
|
|
- **Wake-on-LAN** of the PBS with a readiness wait and configurable timeout/retries.
|
|
- **vzdump backups** via the PVE API, with per-guest selection (all / include / exclude, plus
|
|
auto-include-new) and snapshot/suspend/stop modes.
|
|
- **Retention** (keep last/daily/weekly/monthly/yearly) and **Garbage Collection** after backups.
|
|
- **Verify** — optional quick verify after each backup and a scheduled full-verify cycle.
|
|
- **SSH power-off** of the PBS (the one action with no API), with a guard that waits for running
|
|
PBS tasks to finish first.
|
|
- **Notifications** via Apprise — Telegram, ntfy, email/SMTP, Discord, and custom Apprise/webhook
|
|
URLs — on success and/or failure, localized server-side.
|
|
- **Setup wizard** — connect to PVE, derive PBS from the storage config, detect the PBS MAC, and
|
|
optionally auto-provision scoped tokens and the poweroff SSH key. Defaults to no-root token mode;
|
|
root credentials, if given, are used transiently and never stored.
|
|
- **Live task-log panel** streaming the real PVE/PBS task output (backup/GC/verify) as it runs.
|
|
- **Per-guest last-backup** caching so the dashboard shows dates while the PBS sleeps.
|
|
- **Web UI** — dashboard, settings, and login/auth; **i18n** (English + Italian) and a dark/light
|
|
theme; a footer showing the app version.
|
|
- **Configurable timezone** (`app.timezone` / `TZ`) so schedules run in your local time, not UTC.
|
|
- **Run history + activity log** in SQLite with daily auto-pruning; interrupted runs are cleaned up
|
|
on startup.
|
|
- **Packaging** — a multi-stage Docker image (`catubba/joulenap`) with a healthcheck, a
|
|
docker-compose example, and Proxmox LXC support.
|
|
- Config-driven via `config.yaml` (pydantic-validated); secrets stay in `config.yaml` and are
|
|
redacted from API responses.
|
|
|
|
[Unreleased]: https://github.com/Joulenap/joulenap/compare/v1.0.0...HEAD
|
|
[1.0.0]: https://github.com/Joulenap/joulenap/compare/v0.9.0...v1.0.0
|
|
[0.9.0]: https://github.com/Joulenap/joulenap/compare/v0.8.0...v0.9.0
|
|
[0.8.0]: https://github.com/Joulenap/joulenap/compare/v0.7.0...v0.8.0
|
|
[0.7.0]: https://github.com/Joulenap/joulenap/compare/v0.6.0...v0.7.0
|
|
[0.6.0]: https://github.com/Joulenap/joulenap/compare/v0.5.0...v0.6.0
|
|
[0.5.0]: https://github.com/Joulenap/joulenap/compare/v0.4.4...v0.5.0
|
|
[0.4.4]: https://github.com/Joulenap/joulenap/compare/v0.4.3...v0.4.4
|
|
[0.4.3]: https://github.com/Joulenap/joulenap/compare/v0.4.2...v0.4.3
|
|
[0.4.2]: https://github.com/Joulenap/joulenap/compare/3f94413...v0.4.2
|
|
[0.4.1]: https://github.com/Joulenap/joulenap/compare/340646b...3f94413
|
|
[0.4.0]: https://github.com/Joulenap/joulenap/compare/v0.3.1...340646b
|
|
[0.3.1]: https://github.com/Joulenap/joulenap/compare/v0.3.0...v0.3.1
|
|
[0.3.0]: https://github.com/Joulenap/joulenap/compare/v0.2.0...v0.3.0
|
|
[0.2.0]: https://github.com/Joulenap/joulenap/compare/v0.1.1...v0.2.0
|
|
[0.1.0]: https://github.com/Joulenap/joulenap/releases/tag/v0.1.0
|