New integration, following the existing pattern: config in-app (URL +
API key, credentials encrypted at rest), its own Uptime Kuma page, an
Integrations list entry, a Dashboard widget, and diagnostic-log/
integration-down-alert coverage for free via the shared withDiagLogging
wrapper. Read-only -- no start/stop equivalent exists for a monitor.
Uptime Kuma has no conventional REST API (the dashboard talks to it over
Socket.IO); researched before writing any code, since guessing wrong here
would have cost real time. The one machine-readable, authenticated
endpoint that lists every monitor is its Prometheus exporter at
GET /metrics, gated by HTTP Basic auth -- an API key as the password with
the username left blank on current installs, or the real dashboard
login on installs from before the API-key feature existed. This adapter
authenticates the same way and parses that endpoint's text-exposition
format itself (metrics: monitor_status, monitor_response_time,
monitor_cert_days_remaining, monitor_uptime_ratio; labels: monitor_id,
monitor_name, monitor_type, monitor_url, monitor_hostname, monitor_port),
verified against the documented metric/label set and the actual upstream
source (server/prometheus.js). A malformed line is skipped rather than
failing the whole scrape.
"What server is being monitored for what": each monitor's target (an IP
for TCP checks, or the hostname out of the URL for HTTP/keyword checks)
is matched against your servers' own IPs and hostnames -- reusing the
same kind of match already used in the consistency report -- and linked
to that server's page. Monitors with no single network target (groups,
push monitors, DNS/keyword checks with a complex URL) are left unmatched
rather than guessed at. Uptime Kuma's tags aren't read, since the
Prometheus endpoint doesn't reliably distinguish a tag label from any
other label it might add later.
The username field is the first genuinely optional integration config
field this app has had; IntegrationField gained an `optional` flag
(server validation and both the add/edit web forms honor it) rather than
special-casing Uptime Kuma.
Verified with 48 backend checks (Prometheus text parsing including
escaped quotes, decimals, negative numbers, and malformed lines; TCP vs.
HTTP target/port extraction; every documented status code; server
matching by IP, hostname, and short name, including no-match cases; the
route's real HTTP round trip against a fake Uptime Kuma server, wrong
credentials, upstream failures, roles, wrong/disabled/missing
integration, diagnostic-log entries; the optional-field validation rule)
and by driving the real page and the real Dashboard widget in a browser
against the real routers, including CSV export and column sorting. Real
dev database mtime untouched.
Not verified: a real Uptime Kuma instance. Everything here was checked
against Uptime Kuma's documented metric format, its actual upstream
source, and a fake server built to match both -- not against a live
installation. If your instance's /metrics output differs from what's
documented (older version, unusual monitor types), the parser should
degrade to an empty or partial monitor list rather than error, but that
degradation itself hasn't been observed against the real thing.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Proxmox already runs vzdump backups, but nothing in the app said
whether they were actually succeeding — a silent backup failure is
one of the more dangerous blind spots a homelab admin can have. Adds
a "Backups" card to the Proxmox page: configured backup job
schedules (storage target, which guests, enabled/disabled) from
GET /cluster/backup, and recent vzdump task history per node from
GET /nodes/{node}/tasks?typefilter=vzdump, with a banner at the top
if the most recent run didn't succeed.
New "Proxmox backup failed" notification toggle under Settings ->
Notifications, on the same daily schedule as the other checks. The
scheduler checks each node's own most-recent vzdump run independently
(not just the single most recent task overall) so one node's healthy
backup can't mask another node's failing one in a multi-node cluster.
Known limitation, documented in the adapter's own header comment:
Proxmox's task list doesn't reliably expose which specific guest
failed within an "all guests" job — only the task's own log text has
that — so this surfaces job- and task-level status rather than
guessing at per-guest outcomes.
Verified against a fake Proxmox server (real self-signed HTTPS, since
the adapter's node:https usage can't be monkey-patched under ESM)
reproducing the documented /cluster/backup and task-list response
shapes: job parsing (all-guests+exclude vs specific-vmids+disabled)
correct, task OK/failure parsing correct, and the critical multi-node
scenario confirmed — one node's failing latest run flagged, the
other's healthy latest run correctly left alone, with exactly one
notification of the right content. This reproduces Proxmox's
documented API shape rather than a live-verified one; flag if the
real cluster's response differs in some way this didn't anticipate.
Confirmed the real dev database's mtime was untouched throughout.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Each adapter performs write actions, not just reads (start/stop a
guest, edit a DNS record, rerun a CI job, etc.), so a read-only
credential silently works for the dashboard views but fails the
moment you use an action. Lists the exact endpoints/permissions
needed per target system, drawn from each adapter's own auth code and
header comments (e.g. Proxmox's Sys.Audit/Datastore.Audit split,
Azure's DNS Zone Contributor role, Loopia/Pi-hole/cPanel having no
scoped-credential option at all).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>