Commit Graph
35 Commits
Author SHA1 Message Date
gadgethd d728eb0cde Update repository URL in README 2026-03-04 23:55:41 +00:00
Ben fdc754ff89 Split beta link logic and relabel links toggle 2026-03-04 23:47:40 +00:00
Ben 63e127ee8d Improve beta path accuracy with edge/motif priors and split beta pathing 2026-03-04 23:45:27 +00:00
Ben ca29010917 preload viable link metrics in initial ws state 2026-03-04 23:31:41 +00:00
Ben 135b1805db respect directional support on confirmed beta links 2026-03-04 23:28:03 +00:00
Ben 638ba72c44 add historical path-learning priors and sparse-data beta prediction 2026-03-04 23:22:36 +00:00
Ben 8d42910fca improve link visibility and network-scoped viable pairs 2026-03-04 23:10:35 +00:00
Ben 0632ec3351 fix live stats polling cache staleness on app domains 2026-03-04 23:03:46 +00:00
Ben 1359b5277d refactor app orchestration and shared site modules 2026-03-04 22:57:04 +00:00
Ben 6653d3f2f8 Refactor App pathing logic into dedicated utility module 2026-03-04 22:43:01 +00:00
Ben fb6e1369a7 Harden network filtering and coordinate handling across sites 2026-03-04 22:36:53 +00:00
BenandClaude Sonnet 4.6 83afff2401 Improve beta path resolver: directional sorting and tighter skip budget
- getCandidates: sort all tiers by alignment-toward-src combined with distance
  penalty (sortScore = cosine_similarity - dist_km/50) rather than distance alone.
  When src is unknown the alignment term is 0 so distance sorting is preserved.
- maxSkips: changed from pathHashes.length (skip everything) to
  min(2, floor(N/3)) — prevents degenerate paths on sparse data

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 22:12:07 +00:00
BenandClaude Sonnet 4.6 9ef68829c4 Add network column to nodes + network filtering for multi-domain support
- schema.sql: ADD COLUMN nodes.network TEXT DEFAULT 'teesside'
- db/index.ts: upsertNode accepts network, getNodes/getLastNPackets filter by network
- mqtt/client.ts: pass network to all three upsertNode call sites
- ws/server.ts: read ?network= query param, filter initial state nodes/packets
- api/routes.ts: /api/stats and /api/coverage accept ?network= filter
- useWebSocket.ts: accept network param, append ?network= to WS URL
- useCoverage.ts: accept network param, append ?network= to fetch URL
- App.tsx: compute networkFilter (teesside unless VITE_NETWORK=ukmesh), pass to hooks and stats fetch
- UKMqttPage.tsx: replace installer-based broker setup with accurate TOML config block

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 11:40:11 +00:00
BenandClaude Sonnet 4.6 8865a6444d Add ukmesh.com frontend and MQTT infrastructure
www.ukmesh.com (website-ukmesh container, port 3004):
- UKLayout, UKHomePage, UKInstallPage, UKMqttPage components
- VITE_SITE=ukmesh build arg routes to UK pages in main.tsx
- Stats fetched via relative /api path (proxied by Nginx)

app.ukmesh.com (app-ukmesh container, port 3003):
- Same dashboard build with VITE_APP_HOSTNAME=app.ukmesh.com
- VITE_NETWORK=ukmesh for future API filtering

MQTT:
- node-ukmesh Mosquitto user for ukmesh observer nodes
- ACL updated: backend reads meshcore/# and ukmesh/#
- ukmesh nodes publish to ukmesh/{IATA}/{PUBKEY}/packets

Cloudflare routes to add in Zero Trust:
  www.ukmesh.com  -> http://website-ukmesh:80
  app.ukmesh.com  -> http://app-ukmesh:80
  mqtt.ukmesh.com -> http://mosquitto:9001

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 11:16:26 +00:00
BenandClaude Sonnet 4.6 a946a07488 Separate frontend and backend into distinct containers
Splits the monolithic app container into:
- backend: Node.js handling MQTT, WebSocket, API, DB (no static files)
- app: Nginx serving the React SPA, proxying /api and /ws to backend

This means future dashboards (app.ukmesh.com etc.) can be added as
additional Nginx containers pointing at the same backend with no
duplicate calculations or DB connections.

Also updates nginx.website.conf to proxy to backend instead of app,
and bumps website host port from 3001 to 3002 to avoid conflict.

NOTE: Cloudflare Zero Trust tunnel route for app.teessidemesh.com
must be updated from http://app:3000 to http://app:80.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 10:58:23 +00:00
BenandClaude Sonnet 4.6 1e38a98418 Add network column and multi-network MQTT support
Lays groundwork for ukmesh.com alongside teessidemesh.com:
- Add network TEXT column to packets (default teesside)
- Parse network from topic prefix: meshcore/* = teesside, ukmesh/* = ukmesh
- Subscribe to both meshcore/# and ukmesh/# on connect
- Pass network through insertPacket so every packet is tagged at source

All existing packets default to teesside. UK-wide nodes publishing
to the ukmesh/ topic prefix will be tagged ukmesh automatically.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 10:49:53 +00:00
BenandClaude Sonnet 4.6 63e145c050 Remove IATA filter, accept packets from all observers
Removes the MME-only DISPLAY_IATA gate so packets from any observer
location are stored and emitted to the live dashboard. teessidemesh.com
only has MME observers anyway so behaviour is unchanged there.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 03:58:52 +00:00
BenandClaude Sonnet 4.6 97a9917748 Remove packet retention policy, keep all data indefinitely
Removes the 1-year TimescaleDB retention policy from the packets
hypertable so no data is ever automatically deleted. All tables
(nodes, node_links, packets, etc.) are now kept permanently.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 03:17:07 +00:00
BenandClaude Sonnet 4.6 17fd8cbb9b Add force_viable links, restore fade margin, improve path routing
- Add force_viable column to node_links to permanently force specific
  RF links regardless of ITM path loss calculation
- Force Hartlepool-RPT <-> YM-NM-RPT link (147.6 dB, confirmed by 4368
  observations but above the 138 dB fade margin threshold)
- Restore FADE_MARGIN_DB=10 in ITM viability check (both code paths)
- Reduce last-resort fallback distance from 500 km to 150 km in the
  backtracking DFS path resolver
- getViableLinkPairs and /api/nodes/:id/links now include force_viable=true
- Add useLinks hook for link state management

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 03:14:24 +00:00
BenandClaude Sonnet 4.6 437cb9efa9 Extend packet retention from 28 days to 1 year
Longer history is needed for training path-resolution algorithms (Viterbi
etc.) on real observed relay paths. At current traffic (~10 MB/day) a year
of data is ~3.6 GB — manageable on local storage.

Schema uses a DO block to update an existing retention policy via alter_job
rather than requiring a manual DB migration.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 03:03:14 +00:00
BenandClaude Sonnet 4.6 4969ac28b7 Live confirmed-link learning and real-time frontend updates
- Worker loads confirmed links (itm_viable + observed_count >= 5) when
  resolving relay hashes — prefers known neighbours over geographic
  proximity, creating a self-improving feedback loop as traffic accumulates
- Visited-node set added to worker resolver (each node relays once per packet)
- Frontend handles live link_update WebSocket messages: linkPairs and
  viablePairsArr updated in real-time without page refresh
- MIN_LINK_OBSERVATIONS constant defined in both worker and frontend (5)
- link_update added to WSMessageType union

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 02:39:30 +00:00
BenandClaude Sonnet 4.6 eb413a2f68 Require minimum 5 observations before a link is considered confirmed
Single and double observation links are likely noise from path hash
collisions or one-off propagation events. MIN_LINK_OBSERVATIONS=5
applied to the Links map layer, node popup neighbours, and the
backtracking path resolver link pair set.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 02:31:15 +00:00
BenandClaude Sonnet 4.6 99daf1e4d2 Add node links, improved path resolution, and confirmed neighbours
- node_links table: stores ITM-viable hop pairs from observed packet paths
  with directional counts (count_a_to_b / count_b_to_a) and path loss dB
- Historical backfill: decodes all stored packets on first run to populate links
- Per-node /api/nodes/:id/links endpoint: fetched on popup open (not preloaded)
- Node popup: shows confirmed neighbours with directional arrows and path loss
- Links layer: amber polylines on map showing all ITM-viable link pairs
- Beta path resolver rewritten as backtracking DFS:
  - Confirmed neighbours tried first (real observed link data)
  - Falls back to closest node within terrain-derived radio range
  - Backtracks when a candidate leads to dead ends at subsequent hops
  - Skips capped at ceil(hops/3) to prevent degenerate all-skip paths
  - Visited set enforces each node appears at most once per path
  - hopCount used to slice path_hashes to actual relay count
- Viable link pairs sent in WebSocket initial_state for path resolution
- LINK_BUDGET_DB raised to 148 dB; fade margin removed from viability check
- Viewshed worker: directional link tracking, UK mainland clipping fixes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 02:27:27 +00:00
BenandClaude Sonnet 4.6 6fdeaf7d01 Skip prohibited nodes in packet path resolution
Filter out nodes with 🚫 in their name from hop candidates in both
resolvePathWaypoints and resolveBetaPath. For beta paths, change
empty-candidates from return null (abort) to continue (skip hop),
so a prohibited relay is simply omitted from the displayed path.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-03 23:32:54 +00:00
BenandClaude Sonnet 4.6 2af0b7bc9b Animate packet path dashes via rAF loop
Replace CSS keyframe animation (unreliable due to Leaflet calling
_updateStyle on every prop change) with a requestAnimationFrame loop
that directly increments stroke-dashoffset on the Leaflet SVG _path
element. Dashes march forward at ~1.2 cycles/s for both regular and
beta paths.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-03 23:28:44 +00:00
BenandClaude Sonnet 4.6 26d96133af Add Paths (Beta), node elevation, and coverage preview
- Paths (Beta): new map layer with confidence-scored packet path resolution.
  Per-hop candidates filtered by 2-char node ID prefix, ranked by proximity
  to the interpolated src-to-rx line. Each hop scored by ambiguity factor
  (1/n_candidates) and distance factor (reachable within elevation-derived
  range). Threshold slider in the filter panel (default 50%). Purple dashed
  polyline, separate from the existing packet paths layer.

- Node elevation: viewshed worker now writes terrain elevation (m ASL) to
  nodes.elevation_m when computing each viewshed, and backfills existing
  nodes from stored radius_m on startup. Elevation shown in node popup.

- Coverage preview: "Preview coverage" button in node popup shows that
  node's viewshed at lower opacity (10%) for 20 seconds then auto-dismisses.

- Beta path range uses stored radius_m from node_coverage directly instead
  of bounding box estimation.

- Fix homepage Live Map button to link directly to app.teessidemesh.com.

- README Phase 3: clarify nodes must be on MQTT to be claimable.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-03 23:10:18 +00:00
BenandClaude Sonnet 4.6 6fcfda4b5a Expand roadmap with phases 3-6
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-03 22:06:59 +00:00
BenandClaude Sonnet 4.6 e019842e7a Add project roadmap to README
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-03 20:24:42 +00:00
BenandClaude Sonnet 4.6 0218cabb6d Capitalise NEW badge in live packet feed
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-03 20:15:58 +00:00
BenandClaude Sonnet 4.6 ef6e38c4c6 Add Packets page, fix node counters, align stale/inactive thresholds
- Add Packets page to website explaining all 10 packet types
- Fix handleNodeUpdate to add new nodes instead of silently dropping them
- Fix handleNodeUpsert to filter undefined fields before spreading
- Fix WSMessage type to include node_upsert and coverage_update
- Replace Avg RSSI/SNR stats with Active/Stale repeater counts
- Align stale definition: 7-14 days, inactive >14 days across app and website
- Stale nodes show as red markers on map, hidden at 14 days
- Website stale/active counts include prohibited-emoji repeaters
- Map never shows prohibited-emoji nodes at any point

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-03 20:12:00 +00:00
Ben cd76c91bb4 Fix GitHub button visibility and remove em dashes from open source page 2026-03-03 19:28:28 +00:00
Ben 6fd6242c4c Add full acknowledgements and license compatibility notes to README 2026-03-03 19:23:49 +00:00
Ben 521731bd78 Fix website container missing VITE_APP_HOSTNAME build arg 2026-03-03 19:19:25 +00:00
Ben 01650dd15e Add GitHub link to open source page 2026-03-03 19:12:23 +00:00
Ben cb713d6c1a Initial commit 2026-03-03 19:11:05 +00:00