From 4b5b801def92a7906440c4563cd0734928ca5fd6 Mon Sep 17 00:00:00 2001 From: you Date: Fri, 20 Mar 2026 09:37:22 +0000 Subject: [PATCH] =?UTF-8?q?docs:=20v2.1.1=20=E2=80=94=20multi-broker=20MQT?= =?UTF-8?q?T,=20observer=20detail,=20changelog?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Multi-broker MQTT with per-source IATA filtering - Observer detail pages with charts and status - Channel key auto-derivation (SHA256) - Map dark/light tile swap - Server-side My Nodes filter - 12 bug fixes including spark bars, packet ordering, PII cleanup - Docker deploy.sh fixed with config mount --- CHANGELOG.md | 69 +++++++++++++++++++++++++++------------------------- README.md | 31 ++++++++++++++++++++--- 2 files changed, 63 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b4b013d..717fbaf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,42 +1,45 @@ # Changelog -## v2.0.0 (2026-03-20) +## v2.1.1 — Multi-Broker MQTT & Observer Detail (2026-03-20) -85+ commits — analytics, mobile redesign, accessibility, 100+ bug fixes. +### 🆕 New Features -### ✨ New Features -- Per-node analytics page (6 charts, stat cards, peer table, time range selector) -- Global analytics — Nodes tab (network status, role breakdown, claimed nodes, leaderboards) -- Live map VCR playback — rewind/replay/scrub 24h at up to 4× speed, retro LCD clock -- Richer node detail — status badge, avg SNR/hops, observer table, QR codes, recent packets -- Claimed (My Mesh) nodes — star your nodes, always sorted to top, auto-sync favorites -- Packets "My Nodes" toggle — filter to only your mesh traffic -- Bulk health API (`GET /api/nodes/bulk-health`) -- Network status API (`GET /api/nodes/network-status`) -- Live theme toggle — dark/light tiles swap instantly via MutationObserver +- **Multi-Broker MQTT** — Connect to multiple MQTT brokers simultaneously via `mqttSources` config array. Each source gets its own connection, topics, credentials, TLS settings, and optional IATA region filter. Legacy `mqtt` config still works. +- **IATA Region Filtering** — `mqttSources[].iataFilter` restricts accepted regions per source (e.g. only accept SJC/SFO/OAK packets from a shared feed). +- **Observer Detail Pages** — Click any observer row for a full detail page with status, radio info, battery/uptime/noise floor, packet type donut chart, timeline, unique nodes chart, SNR distribution, and recent packets table. +- **Observer Status Topic Parsing** — `meshcore///status` messages populate model, firmware, client_version, radio config, battery, uptime, and noise floor. 7 new columns in the observers table with auto-migration. +- **Channel Key Auto-Derivation** — Hashtag channel keys (`#channel`) are automatically derived as `SHA256("#channelname")` first 16 bytes on startup. Only non-hashtag keys (like `public`) need manual config. +- **Map Dark/Light Mode** — Map page now uses CartoDB dark/light tiles that swap automatically with the theme toggle (same as live page). +- **Shareable URLs** — Copy Link button on packet detail, standalone packet page at `#/packet/ID`, deep links to channels and observer detail pages. +- **Multi-Node Packet Filter** — "My Nodes" toggle in packets view now uses server-side `findPacketsForNode()` to find ALL packet types (messages, acks, traces), not just ADVERTs. -### 📱 Mobile -- Two-row VCR bar layout (controls+LCD / full-width timeline) -- iOS safe area support (home indicator clearance) -- Feed/legend hidden on mobile — just map + VCR + LCD -- JS-driven viewport height for reliable orientation changes -- Touch-friendly targets, horizontal scroll on tables +### 🐛 Bug Fixes -### ♿ Accessibility -- ARIA tab patterns, focus management, keyboard navigation -- Distinct SVG marker shapes per node role -- Color-blind safe palettes, screen reader support +- **Observer name resolution** — MQTT packets now pass `msg.origin` (friendly name) to both packet records and observer upserts. Previously only the status handler used it. +- **Observer analytics ordering** — Fixed `recentPackets` returning oldest instead of newest (wrong slice direction). Sorted observer analytics packets explicitly. +- **Spark bars visible** — Fixed `.data-table td { max-width: 0 }` crushing spark bar cells to zero width with inline style override. +- **My Nodes filter field names** — Fixed `pubkey` → `pubKey`, `to`/`from` → `srcPubKey`/`destPubKey`/`srcHash`/`destHash`. +- **Duplicate pin buttons** — Live page destroy now removes the nav pin button; init guards against duplicates. +- **Packets page crash** — Fixed non-async `renderTableRows` using `await` (syntax error prevented entire page from loading). +- **Node search all packet types** — Search by node name now returns messages, acks, and traces — not just ADVERTs. +- **Node packet count accuracy** — `findPacketsForNode()` is now single source of truth for all node packet lookups. +- **Health endpoint recentPackets** — Changed from `slice(-10).reverse()` to `slice(0, 20)` — 20 newest DESC instead of 10 oldest. +- **RF analytics total packets** — Added `totalAllPackets` field so frontend shows both total and signal-filtered counts. +- **Duplicate `const crypto` crash** — Removed duplicate `require('crypto')` that crashed prod for ~2 minutes. +- **PII scrubbed from git history** — Removed real names and coordinates from seed data across all commits. -### 🐛 Bug Fixes (100+) -- Excel-like column resize — steal proportionally from all right columns -- Panel drag live reflow -- VCR scrub pagination, replay buffer management -- Express route ordering (named before parameterized) -- XSS escaping, WebSocket cleanup, memory leaks -- Dark mode consistency, empty states, SRI hashes -- Stray CSS fragment corrupting live.css -- Geographic prefix disambiguation restored +### 🏗️ Infrastructure -## v1.0.0 (2026-03-19) +- **Docker container deployed to Azure VM** — Live at `https://analyzer.00id.net` with automatic Let's Encrypt TLS via Caddy. +- **`deploy.sh` fixed** — Config mount (`-v config.json:/app/config.json:ro`) was missing, causing every deploy to fall back to placeholder credentials. Added `|| true` to stop/rm to prevent chain failures. +- **CI/CD via GitHub Actions** — Self-hosted runner on VM, auto-deploys on push to master. -Initial release. +--- + +## v2.0.1 — Mobile Packets (2026-03-18) + +See [v2.0.1 release](https://github.com/Kpa-clawbot/meshcore-analyzer/releases/tag/v2.0.1). + +## v2.0.0 — Live Trace Map & VCR Playback (2026-03-17) + +See [v2.0.0 release](https://github.com/Kpa-clawbot/meshcore-analyzer/releases/tag/v2.0.0). diff --git a/README.md b/README.md index 68c7a83..8695e8a 100644 --- a/README.md +++ b/README.md @@ -48,12 +48,16 @@ Full experience on your phone — proper touch controls, iOS safe area support, - **Observer Status** — health monitoring, packet counts, uptime - **Hash Collision Matrix** — detect address collisions across the mesh - **Claimed Nodes** — star your nodes, always sorted to top, visual distinction -- **Dark / Light Mode** — auto-detects system preference, instant toggle +- **Dark / Light Mode** — auto-detects system preference, instant toggle, map tiles swap too +- **Multi-Broker MQTT** — connect to multiple MQTT brokers simultaneously with per-source IATA filtering +- **Observer Detail Pages** — click any observer for analytics, charts, status, radio info, recent packets +- **Channel Key Auto-Derivation** — hashtag channels (`#channel`) keys derived automatically via SHA256 - **Global Search** — search packets, nodes, and channels (Ctrl+K) +- **Shareable URLs** — deep links to individual packets, channels, and observer detail pages - **Mobile Responsive** — proper two-row VCR bar, iOS safe area support, touch-friendly - **Accessible** — ARIA patterns, keyboard navigation, screen reader support, distinct marker shapes -### ⚡ Performance (v2.1.0) +### ⚡ Performance (v2.1.1) Two-layer caching architecture: in-memory packet store + TTL response cache. All packet reads served from RAM — SQLite is write-only. Heavy endpoints pre-warmed on startup. @@ -148,6 +152,17 @@ Edit `config.json`: "broker": "mqtt://localhost:1883", "topic": "meshcore/+/+/packets" }, + "mqttSources": [ + { + "name": "remote-feed", + "broker": "mqtts://remote-broker:8883", + "topics": ["meshcore/+/+/packets", "meshcore/+/+/status"], + "username": "user", + "password": "pass", + "rejectUnauthorized": false, + "iataFilter": ["SJC", "SFO", "OAK"] + } + ], "channelKeys": { "public": "8b3387e9c5cdea6ac9e5edbaa115cd72" }, @@ -163,9 +178,16 @@ Edit `config.json`: | Field | Description | |-------|-------------| | `port` | HTTP server port (default: 3000) | -| `mqtt.broker` | MQTT broker URL. Set to `""` to disable MQTT and use API-only mode | +| `mqtt.broker` | Local MQTT broker URL. Set to `""` to disable | | `mqtt.topic` | MQTT topic pattern for packet ingestion | -| `channelKeys` | Named channel decryption keys (hex). `public` is the default MeshCore public channel | +| `mqttSources` | Array of external MQTT broker connections (optional) | +| `mqttSources[].name` | Friendly name for logging | +| `mqttSources[].broker` | Broker URL (`mqtt://` or `mqtts://` for TLS) | +| `mqttSources[].topics` | Array of MQTT topic patterns to subscribe to | +| `mqttSources[].username` / `password` | Broker credentials | +| `mqttSources[].rejectUnauthorized` | Set `false` for self-signed TLS certs | +| `mqttSources[].iataFilter` | Only accept packets from these IATA regions | +| `channelKeys` | Named channel decryption keys (hex). Hashtag channels auto-derived via SHA256 | | `defaultRegion` | Default IATA region code for the UI | | `regions` | Map of IATA codes to human-readable region names | @@ -255,6 +277,7 @@ meshcore-analyzer/ │ ├── node-analytics.js # Per-node analytics with charts │ ├── traces.js # Packet tracing │ ├── observers.js # Observer status +│ ├── observer-detail.js # Observer detail with analytics │ ├── home.js # Dashboard home page │ └── perf.js # Performance monitoring dashboard └── tools/