Plan + shared mqtt.config.json for subscribing to the office broker's retained node/description topics: live registry of announced UXVs with standard-identity/liveness, manual rescan, and a bidirectional alias link between a drone node and its video feed. Planning only; no consumer code. |
||
|---|---|---|
| .. | ||
| 01-search-and-filter.md | ||
| 02-holovids-enrichment.md | ||
| 03-alerting-and-escalation.md | ||
| 04-rollups-and-mesh-muting.md | ||
| 05-deep-probes-and-export.md | ||
| 06-native-media-detail-views.md | ||
| 07-live-stream-recording.md | ||
| 08-klv-telemetry.md | ||
| 09-c2-map-cop.md | ||
| 10-reductstore-media-archive.md | ||
| 11-drone-mqtt-discovery.md | ||
| README.md | ||
R2D2 monitoring · feature roadmap
Plans for turning the seeded Kuma instance (118 monitors / 21 groups, see
../seed/README.md) into something an operator can actually run a production
video fleet from. Each file is a review-first implementation plan — read it,
push back, then we build. Nothing here is code you have to trust blind; every
plan says exactly which existing file it touches and how you'd verify it.
The problem these solve
The public status page (../seed/status-page.png) is a 118-row wall grouped by
region. It answers "is the fleet broadly healthy?" It does not answer the
questions you actually ask at 2am:
- "Is
ITA.RADON01up, and what channel/port is it on?" — no search. - "Show me only what's DOWN right now." — no status filter.
- "Which Poland feeds are stalled?" — no facet by region + state.
- "Did anyone get paged when 6 Italy feeds dropped?" — no alerting wired.
- "Is that feed actually streaming video, or just returning HTTP 200?" — HTTP 200 ≠ live stream.
Hard constraint that shapes everything
Uptime Kuma's public status page supports Custom CSS only — no custom JS.
You cannot bolt a search box onto /status/r2d2 itself. So "search" is not a
status-page tweak; it's a small companion read-only app that speaks the same
socket.io API the seed scripts already use (statuspage.mjs is the template).
The admin dashboard has search, but it's admin-only and not the ops surface we
want to hand to a duty operator. This is why Feature 01 is an app, not a CSS
snippet.
Roadmap (priority order)
| # | Feature | Headline value | Touches |
|---|---|---|---|
| 01 | Ops Feed — searchable/filterable companion | The 2am questions above. Instant search, DOWN-only filter, region/tag facets, thumbnails | new ops/ app, reuses socket auth from statuspage.mjs |
| 02 | holovids CSV enrichment | Exact channel/port/codec/bitrate + snapshot thumbnails on every feed. Unblocks search-by-channel | convert.mjs, seed.mjs |
| 03 | Alerting & escalation | Someone actually gets paged, per-region, without alert storms | seed.mjs, notifications |
| 04 | SLO rollups & mesh-aware muting | Meaningful "N/M live" per region; stop false-DOWN from off-mesh probes | convert.mjs, seed.mjs |
| 05 | Deep stream probes & metrics export | Catch stalled-but-200 feeds; Grafana/Prometheus/RSS feed for downstream | probe scripts, Kuma /metrics |
| 06 | Native media detail views & GUI integration | Native imagery + HLS player + metadata + copy-URL/open-in-VLC buttons per feed; type-dispatched "plugin" detail panels integrating projector/restreamer/TrailBase | ops/ app (detail view, hls.js, media proxy) |
| 07 | ⚠ Live-triggered recording to disk | Multi-select feeds → record to tuf8tb while LIVE; fast liveness, cut clip after 30 s dead; auto region/country/feed tree; storage monitoring | ops/ app (recorder.mjs, ffmpeg, disk monitor) |
| 08 | KLV / MISB telemetry | Decode MISB ST 0601 (platform/sensor/frame-centre/footprint) from the real feed's source TS → telemetry HUD; gated on discovering whether Restreamer strips the KLV data PID | ops/ (misb0601.mjs, klv-agent Docker, telemetry SSE) |
| 09 | C2 map & global COP | Per-feed mini-map in the theater + a global common operating picture of every live platform on offline tiles; map ⇄ video pivot | ops/ (app/map.mjs, MapLibre + offline PMTiles) |
| 10 | ReductStore media archive (20 GB FIFO) | Bounded, self-evicting, queryable archive of every snapshot/clip — closes F07's open retention question with a native FIFO-quota object store; battle-tested on real captured media | reduct/store Docker sidecar, ops/reduct-sink.mjs (additive to F07) |
| 11 | Drone MQTT discovery & video ⇄ node association | Listen to the office broker's retained node/description topics → live registry of announced UXVs (callsign/nationality/FRIEND-HOSTILE/present); manual rescan for new assets; alias + bidirectional link between a drone node and its video feed |
ops/ app (mqtt-consumer.mjs, node registry, associations.json, drones Page tab) |
See ../ops/PLAN.md for the umbrella "C2-grade FMV console" arc
tying F06 → F08 → F09 together (tested against the real feed, discovery-first:
does Restreamer strip the KLV data PID?).
How to read a plan
Every feature doc has the same shape:
- Why — the operator question it answers.
- Approach — what we build and why, given the CSS-only constraint.
- Data model / API — the concrete Kuma events and fields involved.
- MVP → later — smallest useful slice first.
- Verify — how you confirm it works before trusting it.
- Open questions — decisions that are yours, not mine.
Suggested sequence
02 first (it's a convert.mjs change that enriches the data everything else
reads), then 01 (the app that surfaces that data), then 03/04 in parallel, then
05 when the fleet is stable enough that "200 but stalled" is your top remaining
blind spot.