MAP_MODULE_SPEC.md — Canonical Map Module Specification¶
Last updated: April 13, 2026 (Omega v2.7)
Status: CANONICAL — v1.0 launch spec
Owner: Alpha / Beta-1 / Gamma / Delta (builders) + Epsilon (pipeline integration)
Supersedes: files/MAP_MODULE_SPEC.md v1.1 (March 30) + all earlier drafts · V2_5 progressive-zoom pin spec · map_routing_traffic_strategy_LOCKED.md · alaivOS_map_route_strategy.md · alaivOS_map_routing_traffic_strategy.md.
Cross-refs: DATA_PIPELINE.md (traffic engine, POI pipeline, 290 cities, Photon Worker) · VOICE_AND_AI.md (Piper TTS, InstructionEnricher, SkillRouter, Ask Laiv POI) · PRODUCT_SCOPE.md · PRICING_AND_TIERS.md · GHOST_PROTOCOL.md (Ghost DDG enrichment fallback) · INFRASTRUCTURE.md.
1. PURPOSE & IDENTITY¶
The Map module is alaivOS's spatial brain: discovery, intelligence, visualization, navigation. One privacy-first, offline-capable, circadian-adaptive map.
Identity: "Your private map that knows when to tell you to leave, what's nearby, where your family is, and navigates you there — without sending your location to anyone."
Navigation engine roadmap: | Version | Engine | Voice | Instructions | CarPlay | |:--|:--|:--|:--|:--| | v1.0 | OSRM | Piper TTS | Enriched (street names, distances) | — | | v1.1 | Valhalla | Piper | Lane guidance, complex interchanges | — | | v1.2 | Valhalla | Piper | Speed cameras, hazards | CarPlay + Android Auto |
2. FIVE VIEWS¶
| View | Purpose | Default Trigger |
|---|---|---|
| Explore | Full-screen map + POI discovery + category chips + overlays | Module opened normally |
| Directions | Route + travel time + traffic to a destination | Tap "Directions" on POI / saved place |
| Navigate | Voice-guided turn-by-turn, heading-up, real-time | Tap "Navigate" from Directions |
| My Places | Saved locations (home/work/favorites/custom) + private notes | Tap "My Places" icon |
| Trip View | Itinerary pins on map, day selector, safety overlay | Travel mode active with trip, or "View on map" |
Dock position: Scrollable 14-module dock, smart default slot 2 (after Insights). User rearranges in Settings → Dock Customization. Dock = WHERE (modules); OmniOrb = HOW (modes: Travel / Family / Focus / Sports / Wind Down).
3. FEATURE-GATE MATRIX (MAP)¶
| Gate | Min Tier | Controls |
|---|---|---|
interactiveMap |
Starter | Map renders, POI, search, My Places, Trip View, voice nav, motorcycle time, offline maps |
mapTrafficPatterns |
Spark | Historic traffic ETA (proprietary patterns) |
mapLiveTraffic |
Core | Live TomTom traffic ETA, departure alert live recheck |
mapTrafficNavigate |
Pro | Traffic coloring, alt routes, multi-stop optimization, navigate deep link |
mapFamilySharing |
Spark | Family location sharing (local-only v1.0, PARTIAL per V2_7) |
contactMapPins |
Spark | Per-address "Show on map" toggle in People module (PersonPin markers) |
Voice nav + motorcycle time + interactive map + POI pins + offline maps + My Places + Trip View = FREE FOR ALL TIERS INCLUDING STARTER. The premium value is ETA accuracy (traffic data) and advanced routing, not navigation itself.
Full gating matrix by view is in §10.
4. EXPLORE VIEW¶
4.1 Layout¶
Full-screen map, user blue dot always centered by default. Locate-me button (◎). Add-place button (⊕). Search bar top, scrollable category chips bottom, overlays toggleable.
4.2 POI Glass Pins — Progressive Zoom (V2_6 LOCK)¶
| Zoom | Rendering |
|---|---|
| z13-15 | Small colored dots (~8px), category-tinted |
| z16 | Mini glass pins with category emoji (~24px) |
| z17+ | Full detail glass cards: emoji + name + distance |
Contradiction resolved: V2_5 spec (dots z10-12, emoji z13-14, cards z15+) rationalized after V2_6 device testing — cards at z14-15 cluttered the map. V2_6 locked glass-pins-only progressive detail per table above. This V2_7 canonical reflects the V2_6 lock.
Category chips (scrollable, multi-select): Food 🍔 · Health 💊 · ATM 🏧 · Shopping 🛒 · Gas ⛽ · Tourism 🏛️ · Leisure 🌳 · Services 📮 · Transport 🚇.
4.3 Place Detail Sheet¶
Bottom sheet (half → full, draggable). Name, rating, distance, open-now, address, phone, website, hours. Actions: [🧭 Directions] [💾 Save] [📝 Note]. Private local notes + visit count (geofencing-driven, ~50m radius).
4.4 Nearby Places + Ask Laiv POI¶
- Prism "Nearby" card (Insights home) → tap → Map Explore centered on POI with detail sheet open.
- Ask Laiv POI (
laiv_poi_search_service.dart+laiv_poi_card_sheet.dart, 23 tests): cross-module context — budget (Money), allergens (Health), calendar (Events), weather (Insights). On-device Qwen first; Ghost DDG enrichment fallback when user is online and needs web facts. SkillRouter intentpoi_search.
5. OVERLAYS¶
| Overlay | Source | Behaviour |
|---|---|---|
| Rain | RainViewer radar tiles | maxNativeZoom: 12 (tiles don't exist above 12; Flutter upscales). Live net only (not in CDN pipeline). |
| Air Quality (AQ) | Open-Meteo AQI (free, 290 cities, pipeline ≤30 min stale) | City-wide zoom-adaptive tint. Feeds Prism AQ card, Observer Rule #11, Morning Briefing, Checkup integration, Laiv context. |
| Wind | Windy.com style — animated 200 particles, Beaufort scale colors | Canvas particle layer, 60fps, wind-speed-scaled. Decorative + informative. |
| Compass heading cone | Device magnetometer | Cone emitted from user dot showing facing direction; useful for walking nav and orientation. |
Toggle in overlay bar. Rain + AQ + Wind + Compass are all-tier (free).
6. DIRECTIONS VIEW¶
6.1 Transport Modes (all four shown simultaneously)¶
| Mode | Source | Offline |
|---|---|---|
| 🚗 Car | Proprietary patterns → TomTom live → OSRM cold | patterns + OSRM |
| 🏍️ Motorcycle | Car × calibration multiplier (congestion-dependent) | ✅ |
| 🚶 Walking | OSRM foot profile | ✅ |
| 🚲 Cycling | OSRM bicycle profile | ✅ |
| 🚇 Transit | GTFS (v1.2) | ✅ when downloaded |
6.2 Directions Tier Gating¶
Route line + distance + car freeflow + motorcycle + walk/cycle → Starter. Pattern-based ETA → Spark. Live traffic ETA + departure alerts → Core. Traffic coloring + alt routes + multi-stop + navigate deep link → Pro.
6.3 Data Flow¶
- Instant (offline, all tiers): OSRM freeflow + motorcycle multiplier + route geometry.
- Pattern overlay (Spark+): Dijkstra through segment graph using proprietary
patterns.json. "Normally 47 min on Mondays at this time." - Live overlay (Core+): If patterns show >30% deviation, fetch TomTom live.
- Traffic coloring (Pro): TomTom Flow Tiles green/yellow/red on route line.
OSRM coords are longitude,latitude order (not lat,lng). Place-detail sheet expands into Directions state rather than navigating to a new screen (map stays visible).
7. NAVIGATE VIEW (voice-guided, FREE all tiers)¶
7.1 NavigationService state machine¶
idle → navigating → rerouting → arrived. Transitions triggered by FollowEngine, OffRouteDetector, geofence arrival (~30m of destination).
7.2 Map behaviour¶
Heading-up rotation, user dot slightly below center (more road visible ahead), completed route fades, zoom auto-adjusts (zoom-in for turns, zoom-out on long straights), traffic coloring on route for Pro.
7.3 GPS tracking¶
Geolocator.getPositionStream every 2s during navigation. Android foreground service / iOS background-location (already built). Battery indicator visible.
7.4 Enriched OSRM → natural language (21 locales)¶
InstructionEnricher maps OSRM maneuver types (turn, roundabout, merge, depart, arrive, continue) into localized strings via ARB keys. Examples: "In 200 meters, turn left onto Av. Américas" / "En 200 metros, gira a la izquierda hacia Av. Américas".
7.5 NavVoiceService (Piper TTS)¶
SovereignTtsService (sherpa_onnx, en_US-hfc_female-medium + per-locale voices). Requests audio focus → speaks → releases (music/podcasts duck and resume). Prompt timing scales with speed (~25s warning window).
Voice sequence per turn: 1. Advance warning (~500m highway / ~200m city) 2. Immediate warning (~100m) 3. Confirmation after turn Specials: "Rerouting…", "You have arrived", long-straight announcements.
7.6 Off-route + rerouting¶
OffRouteDetector: 100m threshold × 3 consecutive checks → state rerouting → OSRM recalc → new polyline + instructions → voice resumes with next step.
7.7 Navigate tier gating¶
Visual route + next-turn card + Piper voice + off-route rerouting + freeflow ETA + "Open in Google Maps" escape hatch → all tiers. Pattern ETA → Spark. Live ETA → Core. Traffic coloring during nav → Pro.
8. 5-LAYER SEARCH STACK¶
300ms debounced, merged & deduped, ranked by proximity + recency + exact-match weight.
| Layer | Source | Offline | Role |
|---|---|---|---|
| 1 | My Places FTS5 (SQLite) | ✅ | Exact-match first: "Mom's house", "Gym" |
| 2 | POI cache (CDN infra/poi/{city}/) |
✅ | Cached POIs for user's city |
| 3 | Photon Cloudflare Worker | net | Autocomplete / typeahead (pipeline-hosted, zero paid API) |
| 4 | Nominatim (User-Agent: alaivOS/1.0 — mandatory) |
net | Address geocoding fallback |
| 5 | Google Places (luxury, dart-define kill-switch) |
net | Temporary rich-data layer; credit expires June 5, 2026; kill-switch flips → 4 layers remain intact |
Foursquare & Yelp: cancelled. Zero paid API dependencies in core stack.
9. TRAFFIC INTELLIGENCE ENGINE¶
Location: lib/core/location/traffic_intelligence/ — 8 files, 58 tests.
9.1 5-Layer Composite ETA¶
| Layer | Data |
|---|---|
baseline_spline |
Proprietary segment graph. Catmull-Rom cubic spline for Gold cities (smooth time-of-day curve), linear interpolation for Standard cities. |
live_calibration |
TomTom live (Core+ only). Damped multiplier against baseline to avoid jitter. |
weather |
Rain/snow/visibility → severity → minutes added. Pipeline-fed (≤30 min stale). |
calendar |
20-country calendar adjustment: holidays, school-term vs. break, public-sector hours, major cultural days. |
event |
Concerts/matches/protests: proximity to route + decay over time + expected attendance. Largest-only, no stacking (one dominant event per route). |
9.2 Factor Chips (MINUTES, not percentages — locked V2_5)¶
UI displays "Rain expected — adds ~8 min" not "+12%". All chips in minutes. Reference string: "Normally X min on Mondays" pattern-based for Spark+; live-shifted for Core+.
9.3 Integration Points¶
- Directions view ETA block
- Departure alerts (local notifications pre-event)
- Morning Briefing ("Leave for work by 7:45 AM")
- Navigate rolling ETA updates
- SkillRouter intent
navigate_to_x
10. CONTACT ADDRESS PINS (PersonPin)¶
contactMapPins → Spark+. Per-address toggle "Show on map" in People module. Address geocoded via Nominatim on first enable; cached locally. Renders as PersonPin marker (avatar circle with contact initial/photo) on Map Explore. Tap → contact sheet with [🧭 Directions] [💬 Message] [📞 Call].
Rolled out in SPRINT_CONTACT_MAP_PINS.md.
11. GEOFENCING¶
Native geofencing_api / platform APIs. Circular geofences (typical 50–200m). Used for: My Places visit tracking (auto-incrementing visitCount + lastVisited), Trip-stop arrival events, "you've arrived" nav trigger, family-share dwell detection. Max concurrent fences respects platform limits (Android 100 per app, iOS 20) — LRU eviction of distant fences.
12. OFFLINE MAPS — FMTC¶
flutter_map_tile_caching. Cache store per city, per tile style. Auto-download triggers:
| Trigger | What downloads | Size | When |
|---|---|---|---|
| User sets Home | 4 circadian tile styles z12-16 + POI (8 cat) + patterns | ~40-60MB | Silent background |
| User sets Work | Additional tiles if different city | ~10-20MB | Silent background |
| Trip created | Destination tiles + POI + airport indoor | ~30-50MB/city | Background, WiFi preferred |
| Monthly refresh | POI + patterns for cached cities | ~5-10MB | 1st of month |
| User enters new city | Prompt "Download maps for [city]?" | ~30MB | User-prompted |
Low storage (onTrimMemory) → LRU eviction. Never evict Home, Work, active-trip caches. Rolled out in SPRINT_R3_ALPHA_OFFLINE_MAPS.md + SPRINT_TILE_PREFETCH.md.
13. FAMILY LOCATION SHARING (v1.0 PARTIAL)¶
Gate: mapFamilySharing → Spark+. Status per V2_7: PARTIAL — local-only v1.0. No cloud sync service. Device-to-device via E2EE Chat channel; server stores only consent record (who shares with whom, never WHERE). Update cadence: active app 5 min, background 15 min. Reuses existing GPS (no extra polling). Focus mode auto-pauses. Language: "coordinate meetups" / "arrive safely" — never "track" or "monitor".
Cloud-sync service deferred to post-v1.0.
14. TRIP VIEW¶
Numbered pins per itinerary item, route lines colored by transport (drive blue / walk green / flight dashed). Day-selector tabs filter pins. Airport pins include gate/terminal from cached airport JSON (cdn.alaivos.com/infra/airports/{IATA}.json). Hotel pins show check-in/room. Default view when Travel mode active with trip. Safety overlay (foreign country detected): embassy pin (user's nationality from countries_extended.json), nearest hospital pin, border-crossing notification.
15. CIRCADIAN TILE STYLES¶
| Time | CartoDB style |
|---|---|
| 6–10 AM | voyager |
| 10 AM–4 PM | positron |
| 4–8 PM | voyager |
| 8 PM–6 AM | dark_matter |
Brightness sensor override (dark environment → dark_matter regardless of clock). User manual override highest priority. All UI on top of map = mandatory glass blur (ClipRRect + BackdropFilter 24 + gradient white 0.14→0.05).
16. LAZY LOADING & GPS DISCIPLINE¶
16.1 Module load¶
ModuleLoader.ensureLoaded('maps') on first dock tap. Registers providers, hydrates FMTC, initializes TrafficIntelligence, wires SkillRouter.
16.2 GPS 5 Modes¶
| Mode | When | Accuracy | Interval |
|---|---|---|---|
idle |
Default | none | paused |
significantChange |
Background, map not open | low | OS significant-change |
mapExplore |
Explore view active | balanced | ~10s |
navigating |
Navigate view active | best | 2s via position stream |
paused |
Focus mode / user toggle | — | — |
GpsManager centralizes all requests. No module talks to Geolocator directly.
17. SKILLROUTER INTEGRATION¶
skill_router.dart routes intents:
- navigate_to_x → Map Directions (voice: "navigate to Farmacia Guadalajara")
- poi_search → Ask Laiv POI service
- show_family_on_map → Map Explore + family layer
- set_home / set_work → My Places special-place flow
Multilingual keywords EN/ES/PT/FR/DE. All map-facing routes honor tier gates — e.g., mapLiveTraffic required when user asks "how long with traffic right now".
18. COMPLETE TIER-GATING MATRIX¶
| Feature | Starter | Spark | Core | Pro | Elite |
|---|---|---|---|---|---|
| Interactive map (pan/zoom/rotate) | ✅ | ✅ | ✅ | ✅ | ✅ |
| POI pins + categories + overlays (rain/AQ/wind/compass) | ✅ | ✅ | ✅ | ✅ | ✅ |
| 5-layer search stack | ✅ | ✅ | ✅ | ✅ | ✅ |
| My Places + private notes + visit tracking | ✅ | ✅ | ✅ | ✅ | ✅ |
| Trip View + airport indoor + safety overlay | ✅ | ✅ | ✅ | ✅ | ✅ |
| OSRM freeflow ETA (car/motorcycle/walk/bike) | ✅ | ✅ | ✅ | ✅ | ✅ |
| Voice nav (Piper, 21 locales, enriched) | ✅ | ✅ | ✅ | ✅ | ✅ |
| Off-route rerouting | ✅ | ✅ | ✅ | ✅ | ✅ |
| Offline maps (FMTC) | ✅ | ✅ | ✅ | ✅ | ✅ |
| "Open in Google Maps" escape | ✅ | ✅ | ✅ | ✅ | ✅ |
| Historic traffic patterns (ETA + nav) | — | ✅ | ✅ | ✅ | ✅ |
| Contact address pins (PersonPin) | — | ✅ | ✅ | ✅ | ✅ |
| Family location sharing (local-only v1.0) | — | ✅ | ✅ | ✅ | ✅ |
| Live traffic ETA | — | — | ✅ | ✅ | ✅ |
| Departure alerts (live recheck) | — | — | ✅ | ✅ | ✅ |
| Traffic coloring on route | — | — | — | ✅ | ✅ |
| Navigate deep link | — | — | — | ✅ | ✅ |
| Alternative routes + multi-stop optimization | — | — | — | ✅ | ✅ |
19. DATA SOURCES (AT-A-GLANCE)¶
| Data | Source | Offline | Refresh |
|---|---|---|---|
| Base tiles | CartoDB 4 circadian styles via FMTC | ✅ cached | Monthly |
| POI | cdn.alaivos.com/infra/poi/{city}/ (Overpass-built) |
✅ | Monthly |
| Routing freeflow | OSRM (bundled) | ✅ | — |
| Routing patterns | cdn.alaivos.com/infra/traffic/{city}/patterns.json |
✅ | Monthly |
| Live traffic | TomTom API | — | Real-time |
| Traffic coloring | TomTom Flow Tiles | — | Real-time |
| Weather / AQ / events | 3-server pipeline → CDN (≤30 min stale) | ✅ | Pipeline schedule |
| Rain radar | RainViewer (live tiles only) | — | Real-time |
| Airport indoor | cdn.alaivos.com/infra/airports/{IATA}.json |
✅ | Monthly |
| Address geocoding | Nominatim (UA: alaivOS/1.0) | — | Per query |
| Autocomplete | Photon Cloudflare Worker | — | Per query |
| Google luxury | Google Places (dart-define kill-switch, expires 2026-06-05) |
— | Per query |
| Safety data | countries_extended.json (bundled) |
✅ | Per release |
Zero paid API deps in core stack. Pipeline details in DATA_PIPELINE.md.
20. SPRINTS ABSORBED INTO THIS CANONICAL¶
CRA trio: SPRINT_CRA_ALPHA_DATA.md, SPRINT_CRA_BETA.md, SPRINT_CRA_GAMMA_UI.md (category chips, POI data foundations, UI scaffold).
Wave 1 (Map core): SPRINT_W1_ALPHA_MAP_CORE.md, SPRINT_W1_BETA1_MAP_DIRECTIONS.md, SPRINT_W1_GAMMA_MAP_DOCK.md.
Wave 2 (Places + Trip): SPRINT_W2_ALPHA_MAP_PLACES.md, SPRINT_W2_BETA1_MAP_TRIP.md.
Wave 3 (Lazy + Family + Wiring): SPRINT_W3_ALPHA_MAP_LAZY.md, SPRINT_W3_BETA1_MAP_FAMILY.md, SPRINT_W3_GAMMA_MAP_WIRE.md.
Wave 4 (Verify): SPRINT_W4_DELTA_MAP_VERIFY.md.
POI & Search: SPRINT_ALPHA_MAP_POI_PERSONA.md (Ask Laiv POI, 23 tests), SPRINT_ALPHA_MAP_SEARCH.md (5-layer stack).
Overlays: SPRINT_BETA1_MAP_OVERLAYS.md, SPRINT_BETA1_OVERLAY_FIXES.md (rain maxNativeZoom:12, AQ zoom-adaptive, Windy-style 200 particles, compass cone).
Contacts: SPRINT_CONTACT_MAP_PINS.md.
Offline/geofencing: SPRINT_R3_ALPHA_OFFLINE_MAPS.md, SPRINT_R3_BETA_GEOFENCING.md, SPRINT_TILE_PREFETCH.md.
Navigation pipeline: SPRINT_NAV1_FOLLOW_ENGINE.md, SPRINT_NAV2_INSTRUCTION_ENRICHER.md (21 locales), SPRINT_NAV3_VOICE_ORCHESTRATOR.md, SPRINT_NAV4_NAVIGATION_UI.md.
Traffic Intelligence: SPRINT_BETA2_TRAFFIC_ENGINE.md (8 files, 58 tests, 5-layer composite, Catmull-Rom Gold / linear Standard, 20-country calendar, event largest-only, factor chips in minutes).
21. CONTRADICTIONS RESOLVED¶
- POI pin zoom breakpoints. V2_5 had dots z10-12 / emoji z13-14 / cards z15+. V2_6 device testing showed cards at z14-15 cluttered. V2_6 lock (reflected here): dots z13-15 / mini pins z16 / detail z17+. V2_7 confirmed.
- Factor chips. Early drafts used percentages; V2_5 locked minutes. This canonical = minutes only.
- Spline model.
alaivOS_map_routing_traffic_strategy.mdleft spline unspecified; BETA2_TRAFFIC_ENGINE locked Catmull-Rom cubic for Gold cities, linear for Standard. - Cloud Gemini routes in early map drafts (e.g., "Open in Gemini"): DEAD per CLAUDE.md v2.7 (AiProvider = {local, ghost} only).
- Family sharing earlier spec'd full cloud sync; V2_7 PARTIAL — local-only for v1.0, cloud-sync service deferred.
- Foursquare/Yelp referenced in
alaivOS_map_route_strategy.md: cancelled. Stack = My Places FTS5 + POI cache + Photon Worker + Nominatim + Google (kill-switch). - TomTom as primary routing. Earlier strategy doc made TomTom primary; current lock: OSRM + proprietary patterns primary, TomTom is LIVE overlay only (Core+).
- AI model references in early drafts (2B/4B/9B on-device): superseded by Qwen 3.5 0.8B/2B/4B on-device and Gemma 4 E4B Ghost-server per CLAUDE.md v2.7.
End of canonical MAP_MODULE_SPEC.md v2.7.