# 🖥️ Dashy SOC Board > [!NOTE] > The homelab's "one pane of glass" — a single dashboard page backed by one large custom function, aggregating roughly a dozen distinct data sources that used to be scattered across separate pages into one glanceable board. ## Fourteen data sources, one board ```mermaid flowchart TD subgraph Sources["Data sources"] direction LR Wazuh["SOC indexer
+ compliance API"] Loki["Log aggregator
24h error counts"] Prom["Metrics
CPU/RAM/disk"] Slack["Alert channels
per app + per host"] Orch["Orchestration APIs
execution health"] Audit["Fleet config-drift
audit feed"] Hyper["Hypervisor API
VM/LXC tree"] Vault["Secrets platform
seal state, lease counts"] SSO["SSO provider
login/failure stats"] DNS["DNS server
query stats, blocklist"] Backup["Backup server
job age/status"] FW["Edge firewall
state table, top rules"] end Sources --> Function["One aggregation function"] Function --> Board["SOC Board
client-rendered"] ``` ## Layout A top row shows a 6-tier infrastructure dependency ladder alongside fleet-wide 24-hour KPIs. Below that, an "Active Issues" strip surfaces the worst findings fleet-wide, followed by a grid of per-host tiles — worst-severity badge, error sparkline, sorted consistently. Clicking a tile expands a full detail panel: compliance and resource gauges, that host's folded-in specialty widget where relevant, and findings grouped by category. > [!TIP] > **Deliberately scoped**: security/error/warning signal only. Per-app uptime is handled separately by the dashboard's own native status checks on individual tiles — the only up/down signal inside this board is *infrastructure-tier* reachability, not per-app availability. Keeping the scope narrow is what keeps the board actually scannable. ## Acknowledge mechanism: client-side, no backend ```mermaid flowchart LR Finding["Finding
stable content-derived key"] --> Ack["User acknowledges"] Ack --> Storage["Browser localStorage
flat map, per-browser"] Storage --> Recompute["Live re-derive:
badges, issue strip, gauges"] Recompute -.never touches.-> Upstream["Wazuh / Slack / any
upstream source"] ``` > [!IMPORTANT] > Acknowledging a finding is a **display filter only** — it never writes back to any upstream source, is scoped per-browser rather than fleet-wide, and a full data set for every host is always kept in memory so the recompute has everything it needs regardless of which panel happens to be open. A reload in a different browser shows the finding again — a deliberate tradeoff favoring simplicity (no backend state to manage) over persistence. ## Real integration gotchas hit building this > [!WARNING] > A few non-obvious lessons from actually building this, in case they save someone else the debugging time: > - Embedding via `fetch` + `innerHTML` means injected `