11c — Maps, Location & Wayfinding
Scope: Property map block, in-property wayfinding (Phase 3), airport/transport options, local recommendations layer.
1. Property map block (MapEmbed)
See 07-block-and-page-builder-spec.md §3.5 for the full MapEmbed block spec.
Map providers:
| Provider | Use case | Required credentials |
|---|---|---|
| Mapbox | Default for consumer web (prettier styles; vector tiles) | MAPBOX_PUBLIC_TOKEN per tenant |
| Google Maps | Alternative (some tenants prefer Google brand recognition) | GOOGLE_MAPS_API_KEY per tenant |
| OpenStreetMap (Leaflet) | Fallback if no provider configured; free; no API key | None |
Tenant configures their preferred provider in theme-config-service. The MapEmbed block renders the appropriate provider.
Offline: A static image snapshot of the map (generated server-side by Mapbox Static API) is shown when the map SDK fails to load.
2. Search results map view (meta-web)
Consumer search results have a map/list toggle. Map view:
[List] | [Map]
[Map canvas — full screen or split]
[Property card pin: ★ $95/night]
[Property card pin: $85/night]
...
[Hover/tap pin → property card flyout]
Implementation:
- Mapbox GL JS (web) / React Native Maps (mobile)
- Property pins are custom markers (tenant-branded color from token; fallback to primary)
- Cluster: properties within 30 px of each other cluster into a count badge
- Cluster tap: zooms to reveal individual pins
- Pin tap: opens property card drawer (right slide-in)
Telemetry: map_view.opened, map_pin.clicked, map_cluster.expanded
Performance: Mapbox GL JS is large (~250 kB); lazy-loaded only when user switches to map view.
3. Airport / transport options
On the property detail page, a "Getting here" section:
Getting to Hotel Kabul Palace
──────────────────────────────────────────────
🚗 From KBL Airport: 25 min by taxi (~$15)
🚐 Shuttle available: Request in guest portal
🚌 Bus: Route 12 → 20 min walk (not recommended for luggage)
Data source: Tenant-entered in theme-config-service transport_options[]. Free-form text + estimated time + estimated cost.
Flight integration (Phase 2): If the guest's booking has a flight number (from pre-arrival form), show real-time estimated drive time from the airport adjusted for current flight arrival time (uses flight-info-service).
4. Local recommendations layer
On the property detail map, a curated POI (Points of Interest) layer:
[Nearby: Restaurants 🍽️ | Culture 🏛️ | Shopping 🛍️ | Transport 🚉]
POIs are tenant-curated (entered in theme-config-service local_pois[]):
- Name, category, distance, description, Google Maps link (optional)
Consumer mobile: "Explore nearby" tab in the property detail screen. Uses device GPS if permission granted (shows walking distance from current location); falls back to property coordinates.
5. In-property wayfinding (Phase 3)
Goal: Guest opens the app and gets turn-by-turn directions from the hotel lobby to their room.
Technology options (Phase 3):
| Option | Pros | Cons |
|---|---|---|
| Mappedin | Purpose-built for indoor maps; rich SDK | Licence cost; onboarding required |
| IndoorAtlas | WiFi/BLE-based indoor positioning | Requires BLE beacon installation |
| Custom SVG floor plan | Low cost; fully controlled | No real positioning; tap-to-navigate only |
Phase 3 scope (placeholder for spec):
- Tenant uploads floor plan (each floor as a separate image or SVG)
- Rooms are tagged with their position on the floor plan
- Guest taps "Find my room" → animated path from lobby to room is overlaid on the floor plan
- Step-by-step text directions as fallback
6. Accessibility notes for maps
- Map iframes:
titleattribute required - Adjacent text address required (for users who cannot use the map — SC 1.1.1)
- Map pins: not interactive by keyboard by default in most map SDKs — add
tabindex="0"+keydownhandler for Enter/Space - Color-blind safe: property pins must be distinguishable by shape + color (not color alone)
- Zoom controls: must be keyboard accessible