feat: route health monitoring with visual path builder

Add complete route health monitoring feature that tracks whether packets
traverse expected multi-hop paths through the mesh network.

Models & migration:
- 5 new models: PacketPathHop, Route, RouteNode, RouteObserver, RouteResult
- Alembic migration with keyset-paginated backfill of existing packets

Collector:
- store_raw_packet refactored to persist path hops via bulk insert
- Matching engine (collector/routes.py) with subsequence matching, quality
  bands (clear/marginal/failing/no_coverage), and collision detection
- Background route evaluator (60s loop) wired into subscriber lifespan
- Route seed loader in CLI (resolves by public_key, matching YAML format)

API:
- 6 CRUD endpoints + preview endpoint under /api/v1/routes
- Schemas accept node_public_keys (64-char hex) instead of internal UUIDs
- 5 Prometheus gauges for route health metrics
- Packet groups endpoint reads from hop table

Web UI:
- Full SPA routes page with summary strip, grouped cards, expandable detail
- Routes nav entry in both desktop (spa.html) and mobile (app.js) navbars
- Home page nav card with feature gate
- API proxy access mapping for v1/routes endpoints
- Visual node-search path builder with autocomplete dropdown, ordered chips
  with reorder/remove controls, and paste-64-char-key support
- Observer picker with same search UX (unordered chips)
- i18n strings in en.json and nl.json

Config:
- feature_routes flag (default: true)
- route_evaluator_interval_seconds (default: 60)
- routes_file seed path
- example/seed/routes.yaml
This commit is contained in:
Louis King
2026-07-12 22:26:44 +01:00
parent d60e2e8b1d
commit 14fbc45387
36 changed files with 4787 additions and 412 deletions
+25
View File
@@ -0,0 +1,25 @@
# Routes seed file — route health monitoring definitions
#
# Loaded by `meshcore-hub seed` (and the compose `seed` profile).
# Keyed by route name; each entry holds the route's knobs plus an ordered
# `path` of node public_keys (>= 2, distinct) and optionally an `observers`
# list of public_keys.
#
# Path nodes must already exist in the database (create them via
# node_tags.yaml or let the collector discover them). Observer nodes that
# don't exist yet are skipped with a warning (not an error).
Ipswich ↔ Norwich:
description: A140 corridor route
visibility: community
match_width: 1
window_hours: 24
packet_count_threshold: 3
# degraded_threshold: 10 # optional; omit/null = 2x threshold
# max_hop_span: 8 # optional; omit/null = unlimited
enabled: true
path:
- a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2
- 9a8b7c6d5e4f9a8b7c6d5e4f9a8b7c6d5e4f9a8b7c6d5e4f9a8b7c6d5e4f9a8b
# observers: # optional; omit/empty = all observers
# - 0102030405060102030405060102030405060102030405060102030405060102