high priority high complexity integration pending frontend specialist Tier 1

Acceptance Criteria

MapProviderIntegration abstract class/interface is defined with buildMapWidget(center, zoom, markers, onBoundsChanged) returning Widget and getBoundsFromController() returning LatLngBounds
No flutter_map types (TileLayer, MapController, LatLng from flutter_map) leak into callers — all public API uses domain-level or dart:ui types
OpenStreetMapProviderIntegration concrete implementation wraps flutter_map and satisfies all interface methods
Riverpod provider (mapProviderIntegrationProvider) is registered and returns the OSM-backed implementation by default
buildMapWidget renders a visible tile layer when given valid center coordinates and zoom level
onBoundsChanged callback fires with correct LatLngBounds after simulated pan or zoom gesture
getBoundsFromController() returns non-null LatLngBounds reflecting the currently visible map region
Swapping the Riverpod provider override to a stub implementation requires zero changes in call sites
All marker data passed via markers parameter is rendered without throwing exceptions, including empty list
Widget disposes MapController cleanly with no memory leaks detectable via flutter_test leak tracking

Technical Requirements

frameworks
Flutter
flutter_map
Riverpod
BLoC
apis
OpenStreetMap Tile API (public, no key required)
performance requirements
Map widget must reach first tile render within 2 seconds on a standard test device with network
onBoundsChanged must not fire more than once per 300ms during continuous pan (debounce required)
MapController must be disposed when the widget is unmounted to prevent listener leaks
security requirements
No API keys required for OSM tile layer — confirm no secrets are embedded
Mentor location coordinates must never be passed to the tile provider URL or logged
Tile requests must use HTTPS endpoints only

Execution Context

Execution Tier
Tier 1

Tier 1 - 540 tasks

Can start after Tier 0 completes

Implementation Notes

Define a sealed abstract class MapProviderIntegration (or Dart abstract interface) in lib/map/map_provider_integration.dart. Use a value object MapMarker (id, lat, lng, label) as the marker type so no flutter_map LatLng leaks. Inside OpenStreetMapProviderIntegration, hold a MapController internally and expose only LatLngBounds through getBoundsFromController(). Register via Riverpod: final mapProviderIntegrationProvider = Provider((ref) => OpenStreetMapProviderIntegration()).

Use a ChangeNotifierProvider or StateNotifierProvider if the controller needs lifecycle management. Debounce the onBoundsChanged callback using a Timer in the listener to avoid flooding the BLoC with events on every frame during pan. Consider using flutter_map's MapEventMoveEnd instead of continuous stream events.

Testing Requirements

Unit tests using flutter_test and Mockito: (1) verify buildMapWidget returns a non-null Widget; (2) mock onBoundsChanged and assert it is called after simulated pan; (3) assert getBoundsFromController returns valid bounds. Widget tests with pumpWidget: render the abstraction widget and verify no RenderFlex overflow or null-check errors occur. Abstraction boundary test: import the caller module and confirm no flutter_map symbols are present in its import graph. Riverpod override test: override mapProviderIntegrationProvider with a MockMapProviderIntegration and verify callers receive the mock.

Minimum 80% line coverage on the integration class itself.

Component
Map Provider Integration
infrastructure high
Epic Risks (3)
high impact medium prob integration

Supabase's hosted PostGIS extension behaviour may differ from the local emulator for spatial RPC functions, causing bounding-box queries to return incorrect results or fail in production while passing locally.

Mitigation & Contingency

Mitigation: Write integration tests against the Supabase emulator from the start and run the same test suite against a staging Supabase project before merging. Use ST_DWithin and ST_MakeEnvelope in plain SQL first, validate with psql, then wrap as RPC.

Contingency: If PostGIS RPC proves unreliable, fall back to client-side bounding box filtering on a full fetch of consented mentor locations (acceptable for up to ~200 mentors per chapter) until the spatial query is stabilised.

medium impact low prob dependency

OpenStreetMap tile usage may require attribution handling and rate limiting. Switching to Google Maps Flutter plugin mid-implementation would require significant rework of the map-provider-integration abstraction.

Mitigation & Contingency

Mitigation: Define the map-provider-integration abstraction interface before selecting the SDK so that the concrete implementation is swappable. Implement OSM first with correct attribution. Document Google Maps as the alternate with its API key setup steps.

Contingency: If OSM tiles are rejected by stakeholders or tile server limits are hit, activate the Google Maps Flutter plugin implementation behind the same interface without touching any UI or service code.

high impact low prob security

Incorrect RLS configuration could allow a coordinator to query mentor locations from a different organisation, constituting a GDPR data breach.

Mitigation & Contingency

Mitigation: Write dedicated RLS integration tests with two isolated test organisations and assert that cross-organisation queries return zero rows. Include these tests in CI. Have a second developer review all RLS policy SQL before migration is applied.

Contingency: If a cross-organisation data leak is discovered post-deployment, immediately disable the map feature via the organisation feature flag, revoke the affected Supabase RLS policy, and notify the data protection officer per the organisation's GDPR incident response procedure.