Implement coordinator role filtering in ContactListService
epic-contact-list-management-business-logic-task-002 — Implement the coordinator-specific filtering branch in ContactListService that delegates to ContactRepository to fetch the coordinator's assigned members and the peer mentors under their supervision. Ensure the result set correctly merges both sub-queries and deduplicates entries. Handle edge cases where a coordinator has no assignments yet.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 1 - 540 tasks
Can start after Tier 0 completes
Implementation Notes
Use `Future.wait([repo.getAssignedMembers(id), repo.getSupervisedPeerMentors(id)])` to issue both queries concurrently. After awaiting, merge with a `LinkedHashSet
If adding context is desired (e.g. for observability), use `throw ContactListServiceException('Coordinator contact fetch failed', cause: e)` with a typed exception class. Avoid loading both results into a flat list before deduplicating ā this wastes memory on large contact sets. The coordinator's own contact record should NOT be included in the result (the list shows contacts they manage, not themselves).
Testing Requirements
Write unit tests using flutter_test with a FakeContactRepository: (1) both sub-queries return results ā assert merged and deduplicated list, (2) a contact appears in both sub-queries ā assert it appears exactly once in output, (3) both sub-queries return empty ā assert empty list returned, (4) only members sub-query returns results ā assert correct list, (5) only peer mentors sub-query returns results ā assert correct list, (6) one sub-query throws ā assert exception propagates with context, (7) assert Future.wait concurrency by recording call order in the fake. Coverage target: 100% on getContactsForCoordinator. All tests must be deterministic.
For organizations with large contact lists (NHF has 1,400 local chapters and potentially thousands of contacts), local in-memory filtering may be too slow and Supabase ILIKE queries without supporting indexes may exceed acceptable response times or accumulate excessive read costs, degrading search usability for power users.
Mitigation & Contingency
Mitigation: Define and document the list-size threshold in ContactSearchService before implementation. Confirm that indexes on name and notes columns exist in the Supabase schema before enabling server-side search. Profile ContactSearchService against realistic data volumes in the staging environment using the largest expected org.
Contingency: If response times are unacceptable in staging, introduce result-count pagination in ContactListService and add a user-visible 'showing top N results ā refine your search' indicator, deferring full pagination to a follow-up task.
In NHF's multi-chapter context, when a user switches organization, Riverpod providers may emit a brief window of stale contact data scoped to the previous organization before the invalidation cycle completes, transiently exposing contacts from the wrong chapter.
Mitigation & Contingency
Mitigation: Model organization context as a Riverpod provider dependency so that any context change immediately marks contact providers as stale. Render a loading skeleton instead of the stale list during the re-fetch transition. Cover this scenario in integration tests with explicit org-switch sequences.
Contingency: If race conditions are observed during QA, add an explicit organization_id equality check in ContactListService that compares each fetched record's scope to the active session org, discarding any mismatched batch before returning results to the provider.