Integrate MentorFilterService into MentorLocationService fetch pipeline
epic-geographic-peer-mentor-map-core-services-task-005 — Wire MentorFilterService into MentorLocationService so that every call to fetchMentorsInBoundingBox first validates and normalises FilterCriteria via MentorFilterService before issuing the repository query. Ensure FilterCriteria are passed through as Supabase-compatible query parameters to the repository layer.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 3 - 413 tasks
Can start after Tier 2 completes
Implementation Notes
Inject MentorFilterService into MentorLocationService via constructor to keep the dependency explicit and testable. Define a private _applyFiltersToQuery(SupabaseQueryBuilder q, FilterCriteria? criteria) helper that translates each FilterCriteria dimension to a Supabase builder call. This keeps fetchMentorsInBoundingBox readable and makes each filter dimension independently testable.
Prefer .overlaps() for array columns if mentor tags are stored as a Postgres array; prefer .contains() if stored as JSONB. Confirm column type with the database schema before choosing. Do not call MentorFilterService.validate() inside _applyFiltersToQuery — validation must happen at the entry point of fetchMentorsInBoundingBox so that invalid criteria are rejected before any query builder state is mutated.
Testing Requirements
Unit tests (flutter_test): mock MentorFilterService using Mockito/mocktail and verify it is invoked with the exact FilterCriteria passed by the caller; verify that filter translation produces the correct Supabase query builder chain using a fake QueryBuilder spy. Integration tests: use Supabase local emulator or a dedicated test schema; verify that active/paused/all availability filters return the correct subset of rows; verify bounding-box + tag combination filters. Edge-case tests: null FilterCriteria, empty tag list, all-paused dataset. Minimum 90% branch coverage on MentorLocationService filter pipeline path.
The dual BLoC state machines (map view state + filter state) may introduce subtle synchronisation bugs where filter changes do not correctly re-trigger viewport queries, causing stale data to appear on the map.
Mitigation & Contingency
Mitigation: Define all BLoC state transitions in a state diagram before implementation. Use flutter_bloc's BlocObserver in development mode to log every state transition. Write explicit unit tests for filter-change → re-query transitions.
Contingency: If state synchronisation bugs appear in integration testing, refactor to a single unified BLoC that owns both map viewport state and filter state, eliminating cross-BLoC dependencies.
Cached mentor location data may become stale (mentors move, pause, or revoke consent) and coordinators in offline mode could be shown incorrect mentor information, leading to wasted outreach.
Mitigation & Contingency
Mitigation: Display a clear timestamp on cached data indicating when it was last synced. Set cache TTL to 24 hours and show an 'offline — data from [date]' banner. Revoked consent removes the mentor from the cache on next successful sync via contact-cache-sync-repository.
Contingency: If cache staleness causes user complaints, reduce TTL to 4 hours and implement background sync on app foreground. Accept that very-recently-revoked mentors may appear briefly in offline mode — document this as a known limitation in the privacy policy.