critical priority medium complexity backend pending backend specialist Tier 6

Acceptance Criteria

ContactListRiverpodProvider uses ref.watch() on both the authenticated user role provider and the organisation context provider so any change triggers a rebuild
When the active organisation changes (e.g., NHF user switching between chapters), both the contacts stream and the peer mentor stream are invalidated within one frame
When the user role changes (coordinator → org_admin or similar), the provider automatically re-fetches with the new role-scoped RLS filter
No stale contacts from the previous organisation or role appear in the list after a context change
If the user has multiple organisation memberships (up to 5 per NHF spec), switching between them triggers a clean re-fetch for each selected organisation
Provider state is disposed and recreated cleanly when auth context is invalidated — no memory leaks or dangling stream subscriptions
A loading state is emitted immediately upon context change so the UI can display a spinner rather than stale data
Error state is emitted correctly if the re-fetch after context change fails, with a descriptive error surfaced to the UI layer

Technical Requirements

frameworks
Flutter
Riverpod
apis
Supabase Realtime streams
Supabase RLS-scoped queries
data models
UserRole
OrganisationContext
Contact
PeerMentor
performance requirements
Re-fetch must complete within 2 seconds on a standard 4G connection
No duplicate Supabase subscriptions after multiple rapid context switches
Stream cancellation must occur before the new subscription is opened to avoid double data delivery
security requirements
After an organisation switch, the previous organisation's contacts must never be accessible in memory or displayed
Role downgrade (e.g., org_admin → peer_mentor) must immediately restrict the visible contact set to the narrower role scope
Supabase JWT scoping must be re-validated on re-fetch, not cached from the previous session

Execution Context

Execution Tier
Tier 6

Tier 6 - 158 tasks

Can start after Tier 5 completes

Implementation Notes

Use ref.watch() rather than ref.listen() for role and organisation context so the provider is automatically disposed and rebuilt by Riverpod's dependency graph — this is cleaner than manually calling ref.invalidateSelf(). Place the watch calls at the very top of the build/create method so Riverpod registers the dependency before any async work starts. For the multi-chapter NHF case, the organisation context provider should expose a single 'active organisation id' value; the ContactListRiverpodProvider watches that single value, keeping the invalidation logic simple. Avoid storing the previous organisation id inside the provider — rely entirely on Riverpod's rebuild cycle.

Use autoDispose modifier on the provider to ensure streams are cancelled when the contacts screen is not active, preventing background Supabase socket usage.

Testing Requirements

Write unit tests using ProviderContainer to verify that mutating the role provider value causes ContactListRiverpodProvider to re-build. Write integration tests simulating an organisation switch event and asserting that the contacts AsyncValue transitions through loading → data with the new org-scoped data. Test rapid consecutive switches (3 switches in <500ms) to confirm only the last context triggers a final stable fetch. Verify that the old stream subscription is cancelled by inspecting active listener counts.

All tests use flutter_test and mock Supabase client; no live network calls.

Component
Contact List Riverpod Provider
data medium
Epic Risks (2)
medium impact medium prob technical

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.

high impact low prob security

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.