Homelab monitoring design (docs/specs/2026-10-03-external-monitoring.md):
Beszel agents own the two physical hosts, prometheus-pve-exporter covers
every LXC/VM via the PVE API with no guest agents, and Grafana supplies
graphs. Dash needs zero code changes — JSON-path widgets already carry an
Authorization header and can walk Prometheus/Beszel JSON, embed widgets
iframe Grafana panels, and monitors + notification transports provide
the alerting layer for unmanaged hardware like the CM834 switch.
infra/monitoring/ ships compose.yaml, prometheus.yml, pve.yml.example
(gitignored real file), and Grafana datasource provisioning.
docs/monitoring.md documents deployment and widget recipes.
Authored By: TDvorak <[email protected]>
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Replaces the static HTML page with a Next.js 15 + Tailwind v4 + Motion
app. The hero renders the dashboard itself - live tiles, ticking clock,
wandering metrics, pulsing status dots - instead of screenshots. Adds a
playable four-renderer switcher (bento/cards/index/console) with layout
animations, live monitor/domain/system mocks, and a cycling alert feed.
Vercel project dash is now git-connected with root dir landing/; pushes
deploy automatically. Canonical alias: dash-homelab.vercel.app.
Authored By: TDvorak <[email protected]>
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
The blanket dist/ pattern in .gitignore excluded the
apps/backend/internal/web/dist directory itself, making the earlier
.keep negation unreachable — the file was never committed, and CI's
clean checkout left //go:embed all:dist with no matching files.
Re-include the directory (contents remain ignored) and commit .keep.
Verified: go build ./... succeeds with dist containing only .keep.
Authored By: TDvorak <[email protected]>
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
The dist copy deleted tracked .keep and overwrote tracked index.html —
dirty tree aborted the release. index.html is now untracked (bare clones
serve 404 instead of a stale stub), .keep alone satisfies go:embed, and
the workflow merges into dist/ without rm. fetch-depth: 0 for tag history.
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
One archive can't span builds with different target sets (dash ships 6,
dash-agent 3) — split into two archives keyed by build id. Also: `builds`
is deprecated in goreleaser v2, renamed to `ids`. Snapshot validated
locally: 9 archives, checksums, embedded UI, migrations on boot.
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
fmtBytes used 1<<40 — a 32-bit shift in JS evaluates to 1<<8=256, so every
value >=256 bytes rendered as TB. Also drop undefined-valued props that
exactOptionalPropertyTypes rejects in incident/status-page bodies.
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>