Mapbox integration — dev brief
Branch: polish/map-pin-and-home-flows
Repo: https://github.com/NEOx-y-z/public-plans-prototypes
Commit: 86d73bc — mapbox search box + chat design
UX is prototype-level and may change. This doc covers Mapbox APIs, wiring, and data flow only.
1. Mapbox products in use
| Product | Purpose | How we call it |
|---|---|---|
Mapbox Maps SDK (mapbox_maps_flutter) | Interactive maps (Plans tab, home preview, plan picker, profile tile) | Native SDK — tiles, camera, annotations |
Mapbox Search Box API (searchbox/v1) | Address autocomplete + coordinate resolution | REST over http — see MapboxSearchService |
| Mapbox Standard style (Studio) | Basemap look, day/evening presets, custom font | mapbox://styles/... + runtime style import config |
We do not use Google Places. Old GooglePlacesService / API key scaffolding has been removed.
2. Auth & config
| Item | Location |
|---|---|
| Public access token | lib/secrets/mapbox_token.dart (gitignored; copy from mapbox_token.example.dart) |
| Style URI | lib/mapbox_config.dart → mapboxStyleUri |
| Custom glyphs | mapboxGlyphsUrl → mapbox://fonts/justgetneo/\{fontstack\}/\{range\}.pbf |
| Patched basemap JSON | assets/map/standard_basemap_patched.json |
Token is passed to:
- Maps SDK at app init (
main.dart) - Every Search Box REST request as
access_tokenquery param
3. Search Box API (address / home point)
Implementation: lib/services/mapbox_search_service.dart
Consumers:
lib/widgets/set_home_postcode_dialog.dart— home pointlib/screens/plan_place_map_picker_screen.dart— plan location picker
Base URL: https://api.mapbox.com/search/searchbox/v1
3.1 Session model (billing)
Mapbox bills suggest + retrieve as one session when they share a session_token.
- Token = UUID v4, created on first
suggestin a session - Reused across all
suggestcalls while user types retrieveends the session →resetSession()clears token- Changing country in home flow also calls
resetSession()
Do not call retrieve without a prior suggest in the same session for the same user action.
3.2 GET /suggest
Autocomplete while typing (min query length: 2 chars in our code).
Query params we send:
| Param | Value |
|---|---|
q | User search text |
session_token | Active session UUID |
access_token | Mapbox public token |
language | en |
limit | 5 (default) |
country | ISO 3166-1 alpha-2 — US or TH from PostcodeCountry |
proximity | lng,lat — country bias center (Austin for US, Bangkok for TH) |
Response parsing: We read suggestions[] and map each to:
PlaceSuggestion {
description: string, // full_address | name + place_formatted
mapboxId: string, // required for retrieve
lat: 0, lng: 0 // NOT populated at suggest stage
}
Error handling: Non-200 or malformed JSON → empty list (no thrown error).
3.3 GET /retrieve/\{mapbox_id\}
Resolves a chosen suggestion to coordinates + formatted address.
Query params:
| Param | Value |
|---|---|
session_token | Same session as suggest |
access_token | Mapbox public token |
Response parsing: GeoJSON-like features[0]:
geometry.coordinates→[lng, lat](note order)properties.full_address/place_formatted/name→ display address
Mapped to:
PlanPlaceSelection {
address: string,
lat: double,
lng: double,
}
After success: session is reset.
Error handling: Non-200 or missing address → null.
3.4 GET /reverse
Coordinates → address. Used in plan place map picker when user confirms a map position without picking a suggestion.
Query params:
| Param | Value |
|---|---|
longitude, latitude | Map centre |
access_token | Token |
language | en |
limit | 1 |
country | Optional ISO filter |
Same _parseRetrieveFeature as retrieve. No session_token on reverse.
4. Home point — end-to-end data flow
User types
→ MapboxSearchService.suggest(q, country, proximity)
→ UI shows PlaceSuggestion list (labels only, no coords)
User selects suggestion
→ MapboxSearchService.retrieve(mapboxId)
→ PlanPlaceSelection { address, lat, lng }
→ HomeLocationResult stored in UI
→ On submit: MapPinService.moveHomePin(lat, lng, postcode: address)
Persistence today: In-memory only (MapPinService._homePostcode + home pin annotation). No backend API.
Map preview on confirm screen: Mapbox GL map widget only (tiles/style). No Search Box call on pan/zoom.
5. Maps SDK (non-Search Box)
5.1 Style application
lib/services/mapbox_style_service.dart — applyBasemapStyle(mapboxMap, ...)
- Loads patched Standard basemap import from bundled JSON
- Sets
lightPreset(day/eveningetc.) - Applies custom font via glyphs URL
- Location picker mode:
showLandmarkIcons: true, POI/place labels off - Plans map mode: optional POI hiding
5.2 Pins & annotations
lib/services/map_pin_service.dart — point annotations via Maps SDK annotation manager. Home pin position updated from resolved lat/lng after Search Box retrieve.
5.3 SDK init
main.dart sets MapboxOptions.setAccessToken(...) before runApp.
6. Key files (quick reference)
lib/services/mapbox_search_service.dart ← Search Box REST client
lib/services/mapbox_style_service.dart ← Basemap style config
lib/mapbox_config.dart ← Style URI, fonts, glyphs
lib/secrets/mapbox_token.dart ← Access token (local only)
lib/models/plan_place_selection.dart ← PlaceSuggestion, PlanPlaceSelection
lib/models/postcode_country.dart ← country + proximity bias for suggest
lib/widgets/set_home_postcode_dialog.dart ← Home point UI → Search Box
lib/screens/plan_place_map_picker_screen.dart ← Plan picker → suggest/retrieve/reverse
lib/screens/plans_map_screen.dart ← Main map + home pin (SDK only for map)
7. What to implement / watch for in production
- Session discipline — Always pair
retrievewith the samesession_tokenused forsuggest. Don't reuse tokens across unrelated searches. - Token scope — Public token needs Search Box + Maps scopes enabled in Mapbox dashboard.
- Rate limits / errors — Currently silent failure (empty/
null). Production should log status codes and surface user-visible errors. - Backend — Home point and plan locations are not synced server-side yet; integrate when API exists.
- Country list — Only
USandTHwired inPostcodeCountry; extendisoCode+searchBiasCenterfor new markets. - No Geocoding API v5 — Address search is Search Box only (
searchbox/v1), not the older Geocoding API.
8. Useful Mapbox docs
Copy/paste this to the team as-is. I can also save it as a file in the repo (e.g. docs/mapbox-dev-brief.md) or open a PR with it if you want.