Skip to main content

Mapbox integration — dev brief

Branch: polish/map-pin-and-home-flows
Repo: https://github.com/NEOx-y-z/public-plans-prototypes
Commit: 86d73bcmapbox 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

ProductPurposeHow 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 resolutionREST over http — see MapboxSearchService
Mapbox Standard style (Studio)Basemap look, day/evening presets, custom fontmapbox://styles/... + runtime style import config

We do not use Google Places. Old GooglePlacesService / API key scaffolding has been removed.


2. Auth & config

ItemLocation
Public access tokenlib/secrets/mapbox_token.dart (gitignored; copy from mapbox_token.example.dart)
Style URIlib/mapbox_config.dartmapboxStyleUri
Custom glyphsmapboxGlyphsUrlmapbox://fonts/justgetneo/\{fontstack\}/\{range\}.pbf
Patched basemap JSONassets/map/standard_basemap_patched.json

Token is passed to:

  • Maps SDK at app init (main.dart)
  • Every Search Box REST request as access_token query param

3. Search Box API (address / home point)

Implementation: lib/services/mapbox_search_service.dart
Consumers:

  • lib/widgets/set_home_postcode_dialog.dart — home point
  • lib/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 suggest in a session
  • Reused across all suggest calls while user types
  • retrieve ends the sessionresetSession() 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:

ParamValue
qUser search text
session_tokenActive session UUID
access_tokenMapbox public token
languageen
limit5 (default)
countryISO 3166-1 alpha-2 — US or TH from PostcodeCountry
proximitylng,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:

ParamValue
session_tokenSame session as suggest
access_tokenMapbox 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:

ParamValue
longitude, latitudeMap centre
access_tokenToken
languageen
limit1
countryOptional 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.1 Style application

lib/services/mapbox_style_service.dartapplyBasemapStyle(mapboxMap, ...)

  • Loads patched Standard basemap import from bundled JSON
  • Sets lightPreset (day / evening etc.)
  • 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

  1. Session discipline — Always pair retrieve with the same session_token used for suggest. Don't reuse tokens across unrelated searches.
  2. Token scope — Public token needs Search Box + Maps scopes enabled in Mapbox dashboard.
  3. Rate limits / errors — Currently silent failure (empty/null). Production should log status codes and surface user-visible errors.
  4. Backend — Home point and plan locations are not synced server-side yet; integrate when API exists.
  5. Country list — Only US and TH wired in PostcodeCountry; extend isoCode + searchBiasCenter for new markets.
  6. 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.