# 🖥️ 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 `