critical priority low complexity frontend pending frontend specialist Tier 4

Acceptance Criteria

The screen renders a scrollable list of all peer mentors from the Proxy Contact List Provider; list is ordered alphabetically by full name by default
Each list row displays: full name (primary text), and at least one piece of relevant metadata (e.g., area/district, active status) as secondary text
While the provider is in loading state, a loading indicator (CircularProgressIndicator or skeleton) is shown instead of the list
When the contact list is empty, a plain-language empty state message is displayed (e.g., 'No peer mentors found') with guidance for the coordinator
When the provider returns an error, an inline error message is shown with a retry action
The screen uses the Proxy Contact List Provider (Riverpod) and does NOT make direct Supabase calls
The list is virtual/lazy-rendered via ListView.builder for performance with large contact lists
The screen follows the project's existing page header and navigation patterns (AppBar with back button, page header widget)

Technical Requirements

frameworks
Flutter
Riverpod
flutter_test
apis
Proxy Contact List Provider (Riverpod)
data models
PeerMentor / Contact (id, fullName, metadata fields)
AsyncValue<List<PeerMentor>>
performance requirements
ListView.builder must be used — never ListView with a pre-built children list for contact lists
Provider data must be cached; screen must not trigger a new Supabase fetch on every rebuild
Initial render with 100+ contacts must complete within 300 ms on a mid-range device
security requirements
Only peer mentors belonging to the coordinator's own organisation are shown — enforced by Supabase RLS and provider query filter
No sensitive personal data (e.g., phone numbers, addresses) is displayed in the list row without explicit design approval
ui components
ConsumerWidget or ConsumerStatefulWidget (Riverpod)
ListView.builder — lazy scrollable list
ListTile or custom row widget matching project design tokens
CircularProgressIndicator or skeleton loader for loading state
Empty state widget (reuse project pattern or create inline)
AppBar / page header widget from project shared components

Execution Context

Execution Tier
Tier 4

Tier 4 - 323 tasks

Can start after Tier 3 completes

Implementation Notes

Scaffold the screen as a ConsumerWidget watching the proxyContactListProvider (FutureProvider or StateNotifierProvider). Use AsyncValue's .when() pattern to branch on loading/data/error cleanly — avoid nested if/else on AsyncValue states. For the list row, extract a dedicated PeerMentorListTile widget so it can be tested in isolation and reused in the multi-select task (task-008). The row widget should accept a PeerMentor model and a boolean isSelected parameter (defaulting to false here) so task-006 can extend it for selection state without a rewrite.

Alphabetical sort should happen in the provider selector or a derived provider, not inside the build method. Follow the project's existing patterns for page headers and AppBar back navigation.

Testing Requirements

Write widget tests covering: (1) loading state — mock provider returns AsyncLoading, assert loading indicator is present; (2) populated state — mock provider returns a list of 3 mentors, assert all names are rendered; (3) empty state — mock provider returns empty list, assert empty state message is visible; (4) error state — mock provider returns AsyncError, assert error message and retry button are visible. Use Riverpod ProviderScope overrides with a mock or stub provider. Also write a unit test for any list-sorting logic. Test with 0, 1, and 50+ items.

Component
Peer Mentor Single Selector
ui low
Epic Risks (2)
medium impact medium prob technical

NHF coordinators may manage dozens of peer mentors across multiple chapters. If the multi-select list renders all contacts in a single unsorted ListView, performance degrades with 50+ items, and coordinators cannot efficiently locate a specific mentor, increasing the probability of selection errors and wrong-person proxy registrations.

Mitigation & Contingency

Mitigation: Use a SliverList with itemExtent for fixed-height rows to enable O(1) scroll position calculation. Implement the search filter using a debounce utility operating on an in-memory list (no extra API calls). Sort the contact list alphabetically by default. Add chapter-filter chips above the list for NHF's multi-chapter coordinators.

Contingency: If performance issues arise in testing with real data sets, introduce pagination with a 'load more' trigger at the bottom of the list and cache rendered rows using Flutter's AutomaticKeepAliveClientMixin.

high impact medium prob security

NHF has a complex 12-national-association / 9-region / 1,400-chapter hierarchy. It is ambiguous whether a coordinator can proxy-register for peer mentors outside their immediately assigned chapter. If the contact list is not correctly scoped by RLS, coordinators might see — and register on behalf of — peer mentors they do not manage, creating fraudulent activity records that skew Bufdir statistics.

Mitigation & Contingency

Mitigation: The Proxy Contact List Provider must query only peer mentors linked to the coordinator's own chapter scope via RLS. Add an explicit Supabase query test asserting that a coordinator from chapter A cannot retrieve peer mentors from chapter B. Display each mentor's chapter affiliation in the list row so coordinators can visually verify scope.

Contingency: If RLS scope is found to be too permissive in testing, apply a server-side coordinator_id filter as a secondary guard on the query. Block the feature release until the scope test passes consistently.