From 870337e767c764084e2f16cd5d59da97ace5ef3b Mon Sep 17 00:00:00 2001 From: n30nex Date: Sat, 23 May 2026 13:19:05 -0400 Subject: [PATCH] document map page architecture (#3) --- codex-thoughts/README.md | 1 + .../map-page-architecture/README.md | 22 +++++++ .../api-contract-deltas.md | 57 +++++++++++++++++++ .../cartolive-parity-inventory.md | 47 +++++++++++++++ .../live-layer-policy.md | 34 +++++++++++ .../map-page-architecture/staged-roadmap.md | 43 ++++++++++++++ .../tower-map-architecture.md | 47 +++++++++++++++ 7 files changed, 251 insertions(+) create mode 100644 codex-thoughts/map-page-architecture/README.md create mode 100644 codex-thoughts/map-page-architecture/api-contract-deltas.md create mode 100644 codex-thoughts/map-page-architecture/cartolive-parity-inventory.md create mode 100644 codex-thoughts/map-page-architecture/live-layer-policy.md create mode 100644 codex-thoughts/map-page-architecture/staged-roadmap.md create mode 100644 codex-thoughts/map-page-architecture/tower-map-architecture.md diff --git a/codex-thoughts/README.md b/codex-thoughts/README.md index 6e26cc7..e966b4b 100644 --- a/codex-thoughts/README.md +++ b/codex-thoughts/README.md @@ -17,4 +17,5 @@ It is meant for documents that help future code review, implementation planning, - [Initial baseline thoughts and suggestions](initial-baseline-thoughts.md) - [Initial tower-server baseline thoughts](initial-server-baseline-thoughts.md) +- [Map page architecture](map-page-architecture/README.md) - [PR and commit commenting operating model](pr-commenting-operating-model.md) diff --git a/codex-thoughts/map-page-architecture/README.md b/codex-thoughts/map-page-architecture/README.md new file mode 100644 index 0000000..82049c3 --- /dev/null +++ b/codex-thoughts/map-page-architecture/README.md @@ -0,0 +1,22 @@ +# MeshCore Tower Map Page Architecture + +This folder tracks the staged map-page implementation plan for MeshCore Tower. +The target is MC-CartoLive feature parity where it fits Tower, but with Tower's +own backend contracts, privacy boundaries, IATA scoping, and path-confidence +rules. + +The first implementation slice is intentionally small: + +- MapLibre GL JS renders the browser map. +- OpenFreeMap provides the default basemap style and tiles. +- `tower-server` owns all mesh state through Tower-native API contracts. +- Live traffic overlays stay behind a master Live toggle and default off. +- Routes remain empty until ordered per-hop path confidence is complete. + +## Documents + +- `cartolive-parity-inventory.md` lists CartoLive behaviors and their Tower status. +- `tower-map-architecture.md` describes the Tower map shape and boundaries. +- `staged-roadmap.md` breaks parity into safe implementation stages. +- `api-contract-deltas.md` records map-specific backend contract additions. +- `live-layer-policy.md` captures the Live toggle and animation safety rules. diff --git a/codex-thoughts/map-page-architecture/api-contract-deltas.md b/codex-thoughts/map-page-architecture/api-contract-deltas.md new file mode 100644 index 0000000..5b18f5d --- /dev/null +++ b/codex-thoughts/map-page-architecture/api-contract-deltas.md @@ -0,0 +1,57 @@ +# API Contract Deltas + +This file records map-specific API additions that extend the existing Tower API +without copying MC-CartoLive's public-state contract. + +## `GET /api/v1/map/state` + +Query parameters: + +- `iata=YOW`: restrict map state to one IATA. +- `regionId=1`: expand the region to its member IATAs. +- Omitting both returns all mappable public state. + +`iata` and `regionId` are mutually exclusive. + +Response shape: + +```json +{ + "serverTime": 1760000000000, + "scope": { "iatas": ["YOW"], "regionId": 1 }, + "metadata": { + "basemap": "openfreemap", + "routesComplete": false, + "routesStatus": "blocked_by_ordered_path_confidence", + "liveDefaultEnabled": false + }, + "nodes": [], + "observers": [], + "routes": [], + "activitySummary": { + "packets24h": 0, + "observations24h": 0, + "activeObservers24h": 0, + "activeIatas24h": 0, + "lastHeardAt": null + } +} +``` + +## Route Contract Requirement + +Routes must not be populated until path resolution returns one item per hop: + +- hop order preserved from packet path bytes +- `confidence = high | ambiguous | none` +- candidates retained for ambiguous detail UI +- raw bytes and full public keys excluded from public map responses + +Only all-high observations may produce map route edges. + +## Live Contract Direction + +The existing WebSocket remains the primary live channel. If the current +`packetObservation` event remains too slim for map animation, add a map-safe +event shape rather than exposing packet internals. REST remains authoritative; +WebSocket events update freshness and optional animation only. diff --git a/codex-thoughts/map-page-architecture/cartolive-parity-inventory.md b/codex-thoughts/map-page-architecture/cartolive-parity-inventory.md new file mode 100644 index 0000000..d10ff26 --- /dev/null +++ b/codex-thoughts/map-page-architecture/cartolive-parity-inventory.md @@ -0,0 +1,47 @@ +# MC-CartoLive Parity Inventory + +This inventory treats MC-CartoLive as the behavior reference, not as an API or +code structure to copy directly. Tower must keep its own server contracts, +schema, privacy rules, and UI conventions. + +## Stage 1: Map Foundation + +- OpenFreeMap basemap rendered through MapLibre GL JS. +- Full-viewport operational map inside the existing Tower shell. +- Mappable nodes from Tower server only. +- Mappable observers from Tower server only. +- Initial fit to data once per selected region or IATA. +- No auto-zoom on new packet traffic. + +## Stage 2: Static Topology + +- Low-zoom node clustering. +- High-zoom node and observer points. +- Node and observer hover/click inspection. +- Role/type filters. +- Stale or offline visual states. +- Passive route lines only when Tower can prove every hop is high confidence. + +## Stage 3: Operational Panels + +- Busy Pathways summary. +- Reachable-node phonebook. +- Route highlighting from a selected node. +- Plot routes between node endpoints or map points. +- Compact panel restore behavior for mobile and dense desktop use. + +## Stage 4: Live Layer + +- Master Live toggle defaults off. +- Packet comets, route glows, observer auras, and message bubbles render only + when Live is enabled. +- Payload and channel filters apply before animation. +- Events may be dropped or throttled under load. +- VCR playback, scrubbing, and replay are intentionally excluded from Tower. + +## Not Directly Portable + +- CartoLive's `/api/v1/public/state` contract. +- Public hash and path shortcuts that do not match Tower privacy policy. +- Any route rendering that relies on guessed, ambiguous, or unordered paths. +- VCR state and history playback UI. diff --git a/codex-thoughts/map-page-architecture/live-layer-policy.md b/codex-thoughts/map-page-architecture/live-layer-policy.md new file mode 100644 index 0000000..cdfaf43 --- /dev/null +++ b/codex-thoughts/map-page-architecture/live-layer-policy.md @@ -0,0 +1,34 @@ +# Live Layer Policy + +The Tower map treats live traffic as an explicit overlay, not as the default map +state. + +## Defaults + +- Live is off on first load. +- Static nodes, observers, and high-confidence routes may render without Live. +- Packet comets, route glows, observer auras, message bubbles, and live-follow + movement require Live to be on. + +## Safety Rules + +- Do not animate ambiguous or unresolved paths. +- Do not animate stale events outside the accepted live window. +- Do not zoom or pan the map in response to packet traffic. +- Prefer frame drops over UI jank under load. +- Keep live visuals separate from route and node source truth. + +## Subscription Rules + +The map should attach live handlers only while Live is enabled. Turning Live off +must clear transient overlays and detach map-specific listeners without affecting +the packet list's WebSocket behavior. + +## Future Controls + +- Payload type filters. +- Channel filters when channel visibility exists. +- Optional observer-only activity aura. +- Optional message bubbles for sanitized decoded public messages. + +VCR playback and scrub controls stay out of scope. diff --git a/codex-thoughts/map-page-architecture/staged-roadmap.md b/codex-thoughts/map-page-architecture/staged-roadmap.md new file mode 100644 index 0000000..d99a11a --- /dev/null +++ b/codex-thoughts/map-page-architecture/staged-roadmap.md @@ -0,0 +1,43 @@ +# Staged Roadmap + +The map should reach parity in small PRs because the server and frontend are +changing quickly and multiple people are working in the repos. + +## Stage 1: Static Map Foundation + +- Add `GET /api/v1/map/state`. +- Add MapLibre GL JS and OpenFreeMap to `tower-web`. +- Render nodes, observers, and empty routes from Tower state. +- Fit to visible data once when the selected IATA changes. +- Add compact layer toggles. +- Keep Live off by default. + +## Stage 2: Confidence-Correct Routes + +- Replace flattened path resolution with ordered per-hop results. +- Store or derive route-safe observations only from all-high paths. +- Add route edges to `/api/v1/map/state`. +- Render passive route lines with no click-stealing. +- Add route-focused tests for ambiguous and unresolved paths. + +## Stage 3: Inspection And Topology Tools + +- Add node/observer detail drawer. +- Add route and neighbor highlighting. +- Add searchable reachable-node phonebook. +- Add Busy Pathways from recent high-confidence route activity. +- Add route plotting by selected endpoints or map corners. + +## Stage 4: Live Layer + +- Add map-safe live event payloads if the existing WebSocket packet event stays + too slim. +- Convert high-confidence live observations into packet comets and route glows. +- Convert observer-only observations into observer auras. +- Add payload/channel filters. +- Throttle and drop frames under load. + +## Excluded + +VCR playback, scrub bars, replay mode, and historical animation are not part of +Tower map parity. diff --git a/codex-thoughts/map-page-architecture/tower-map-architecture.md b/codex-thoughts/map-page-architecture/tower-map-architecture.md new file mode 100644 index 0000000..0082169 --- /dev/null +++ b/codex-thoughts/map-page-architecture/tower-map-architecture.md @@ -0,0 +1,47 @@ +# Tower Map Architecture + +The Tower map is a Tower-native feature. It should reuse CartoLive's proven +interaction model where appropriate, but all data must flow from `tower-server` +and all UI must follow the compact Tower shell. + +## Rendering Stack + +- Renderer: MapLibre GL JS. +- Basemap: OpenFreeMap style URL, defaulting to Liberty unless configured. +- Overlay data: GeoJSON sources owned by `src/features/map`. +- Live effects: a separate source/layer or canvas overlay, controlled by the + Live toggle. + +## Frontend Boundaries + +The map feature should stay under `tower-web/src/features/map`: + +- `api.ts`: fetches Tower map state. +- `types.ts`: map-specific frontend contract types. +- `geojson.ts`: pure source builders for nodes, observers, routes, and live + overlays. +- `layers.ts`: MapLibre source and layer declarations. +- `live.ts`: safe conversion from Tower live events to map pulses. +- `MapView.tsx`: React lifecycle and controls. + +The feature should not require packet-list internals. It may listen to the +shared WebSocket manager only when the Live toggle is on. + +## Backend Boundaries + +The map API should expose sanitized, mappable records only: + +- Node UUIDs, labels, roles, coordinates, IATAs, last seen, and counts. +- Observer UUIDs, labels, type, IATA, coordinates, online state, and counts. +- Route edges only after ordered path confidence exists. +- Aggregate activity counts for panels and status. + +The API must not expose full public keys, raw path bytes, packet hashes, owner +metadata, broker secrets, channel keys, or resolver debug internals. + +## Route Rule + +Map routes are allowed only when every hop resolves in order with confidence +`high`. Any `ambiguous` or `none` hop blocks route drawing for that observation. +The UI may show ambiguity in details later, but must not promote it into a map +edge.