CIS490/training/dashboard/dashboard.caddy
Max Gorog a8157ed177 training/dashboard: live deck at dashboard.wg, fed by receiver
Starlette + WebSocket dashboard run on the Pi as cis490-dashboard.service
(127.0.0.1:8447, Caddy-fronted at dashboard.wg). Tails
/var/lib/cis490/index.jsonl for episode events, snapshots host counts
every 30s, broadcasts to every connected browser. New connections get a
warm snapshot (recent_episodes, total_bytes, host_counts) so reloads
don't see a cold dashboard.

Frontend is a 10-scene scrollytelling deck following the project
outline: intro, collect, hosts, db explorer, baseline, attacks,
chunking, models, knn, perf. Sticky full-bleed canvas with a
right-aligned prose column (matrix-explorable layout). Hotkeys (arrows,
space, j/k, c, Home/End), prev/next chevrons, FAB, and an opt-in
click-to-advance toggle. Demo toggle drives synthetic data for the
five scenes that have no real producer yet (attack envelopes,
chunking, model bars, knn scatter, perf scatter); when off, those
scenes show "awaiting <event_type> events" rather than fake data.

Producers wire in by POSTing typed JSON to 127.0.0.1:8447/publish
(loopback only; Caddy 404s it externally). Event types the widgets
subscribe to: model_metric {model, accuracy}, embedding {x, y, phase},
model_perf {model, latency_us, accuracy}, prediction {episode_id,
window_idx, predicted, actual}, attack_profile {name, shape, curve},
phase {phase}.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 21:26:07 -05:00

23 lines
857 B
Text

# CIS490 live dashboard — blank-slate web display fed by Python over
# a WebSocket. Reachable as https://dashboard.wg from any peer on the
# WG mesh.
#
# Trust boundary: "reached :443 over WG", same as bootstrap.wg —
# iptmonads has already gated WG peers, so no client_auth here.
#
# /publish is the producer ingest endpoint. The dashboard service
# binds 127.0.0.1:8447 and enforces a loopback allow-list at the app
# layer, but everything Caddy proxies arrives at the upstream FROM
# 127.0.0.1 (Caddy itself), so the app-layer check would be bypassed
# for WG callers. We explicitly 404 it here so producers MUST POST
# directly to 127.0.0.1:8447 from the Pi.
#
# Upstream: cis490-dashboard.service on 127.0.0.1:8447.
dashboard.wg {
tls internal
@publish path /publish /publish/*
respond @publish "Not Found" 404
reverse_proxy 127.0.0.1:8447
}