docs: Plan 6 — cache service icons locally (no CDN slug leak)

Server-side icon cache (lib/health/icons.js + GET /api/icons/:slug.png) fetches
each icon once from dashboard-icons into a persistent dir and serves it from the
LAN. Browser never contacts the CDN; slug sanitized; first-letter fallback.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
root
2026-06-02 22:04:04 +10:00
parent f2f1ee4b10
commit 34f5995810

View File

@@ -46,7 +46,7 @@ The two bands are kept visually and structurally separate, by explicit request.
| Real-time | **Per-card polling**, no new SSE. |
| Service registry (LB) | **Config file** now; DB-backed + Proxmox auto-discovery are noted future upgrades. |
| Little Blue fix-it tools | **Deferred** to a later agent phase. |
| Service icons | Auto-pulled from the walkxcode/dashboard-icons CDN, first-letter fallback (parity with v1). |
| Service icons | **Cached locally, server-side.** The server fetches each needed icon once from dashboard-icons into a persistent cache and serves it from the LAN. Browser never hits the CDN; no per-request slug leak. First-letter fallback on miss. |
## 4. Architecture
@@ -151,12 +151,24 @@ services for the user to correct.
### 6.5 Rendering
- `public/views/health_band.js` + `public/components/service_tile.js`.
- Tile: auto-icon (`<img loading="lazy"
src="https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/<slug>.png">`,
slug = `icon` or slugified `name`, first-letter `<div>` fallback on `onerror`),
status dot (ok/warn/down), name, host, hover "open ↗" link → `url`.
- Tile: auto-icon (`<img loading="lazy" src="/api/icons/<slug>.png">` served from
the **local cache** §6.6; slug = `icon` or slugified `name`; first-letter `<div>`
fallback on `onerror`), status dot (ok/warn/down), name, host, hover "open ↗"
link → `url`.
- Grouped sections with header + "X/Y healthy" + divider, refreshed every 60s.
### 6.6 Local icon cache (no CDN leak)
- `lib/health/icons.js` + a persistent cache dir `ICON_CACHE`
(default `/var/lib/void/icons`, like the blob store — survives deploys).
- `GET /api/icons/:slug.png` serves the cached file. On a **cache miss**, the
server fetches `<slug>.png` once from dashboard-icons
(`cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/<slug>.png`), validates it's
a PNG, writes it to the cache, then serves it. Subsequent requests are local.
- Slug is constrained to `[a-z0-9-]` (no path traversal, no arbitrary upstream).
- On upstream 404/error, respond 404 → the tile falls back to the first-letter
badge. Only the **server** ever contacts the CDN, once per distinct icon.
- "As needed": icons are fetched lazily on first reference, not bulk-synced.
## 7. Theme tokens
Add to `public/style.css :root`:
- Reuse `--accent` / `--accent-dim` / `--panel` / `--border` for refined-B chrome.
@@ -172,6 +184,8 @@ Backend (vitest):
- registry loader: parse + group + ordering + icon-slug derivation.
- `dashboard_layout` repo: get/put + owner scoping.
- `/api/health/services` grouping + healthy counts.
- icon cache: miss → fetch-once → cached file served; slug sanitization rejects
traversal/invalid chars; upstream 404 → 404 (browser falls back).
Frontend (pure-logic units):
- card module contract (each exports id/title/size/mount/start/stop).
@@ -200,4 +214,5 @@ Security: confirm the health checker rejects targets outside the registry.
- Little Blue fix-it agent (chat + repair/Proxmox tools).
- DB-backed + Proxmox-auto service registry.
- Multi-host metrics; per-agent theming; final avatar art; agent-output cards.
- Optional self-hosted service-icon set (drop the CDN dependency).
- Optional: pre-seed/vendor the icon cache at deploy (fully offline, no first-use
CDN fetch) and a periodic refresh.