document map page architecture (#3)

This commit is contained in:
n30nex
2026-05-23 13:19:05 -04:00
committed by GitHub
parent 9352cb0f8f
commit 870337e767
7 changed files with 251 additions and 0 deletions
+1
View File
@@ -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)
@@ -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.
@@ -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.
@@ -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.
@@ -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.
@@ -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.
@@ -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.