high priority medium complexity frontend pending frontend specialist Tier 13

Acceptance Criteria

Typing in the TextField triggers a debounced search after 300ms of inactivity — no query fires on every keystroke
Search query is sent to Supabase with a chapter scope filter (chapterScope parameter), returning only peer mentors belonging to the coordinator's chapter
Result overlay renders a scrollable list of PeerMentorResultTile widgets, each showing mentor full name and chapter label
Each result tile is tappable and calls onChanged with the selected PeerMentor
Overlay shows a loading indicator while the query is in-flight
Overlay shows 'No peer mentors found' message for empty results (query returned 0 rows)
Overlay shows an error message with a Retry button if the Supabase call fails
Minimum query length: search only fires when input is ≥2 characters; below that the overlay is hidden
Clearing the TextField (clear button or backspace to empty) dismisses the overlay and resets selection to null
Search is case-insensitive and matches on partial name (e.g., 'jo' matches 'Jonas', 'Jorunn')
Results list is limited to a maximum of 10 items to prevent an unscrollable long overlay
WCAG 2.2 AA: each result tile has a Semantics label readable by screen readers

Technical Requirements

frameworks
Flutter
Riverpod
Supabase Flutter SDK
apis
Supabase: peer_mentors table query with ilike filter on name column and eq filter on chapter_id
Example: supabase.from('peer_mentors').select().eq('chapter_id', chapterScope).ilike('name', '%$query%').limit(10)
data models
PeerMentor { id, name, chapterId, chapterName }
PeerMentorSearchState { idle, loading, results: List<PeerMentor>, empty, error: String }
performance requirements
Debounce delay: 300ms
Supabase query response target: <500ms on 3G network
Result list rendering: no jank — use ListView.builder for efficient rendering
security requirements
Chapter scope filter is enforced server-side via Supabase RLS (Row Level Security) policies — client-side filter alone is insufficient
Input is passed as a parameterized query (Supabase SDK handles this) — no raw SQL string interpolation
Only authenticated coordinators can query peer mentors in their chapter — verify RLS policy covers this route
ui components
PeerMentorResultTile widget (mentor name + chapter label + tap handler)
ListView.builder inside overlay
Loading indicator (existing CircularProgressIndicator from task-007)
Error state with Retry button (TextButton)
Empty state Text widget

Execution Context

Execution Tier
Tier 13

Tier 13 - 6 tasks

Can start after Tier 12 completes

Dependencies (21)
epic-proxy-activity-registration-orchestration-task-001 component Cross-Epic Component proxy-peer-mentor-selector depends on proxy-registration-service
epic-proxy-activity-registration-orchestration-task-002 component Cross-Epic Component proxy-peer-mentor-selector depends on proxy-registration-service
epic-proxy-activity-registration-orchestration-task-003 component Cross-Epic Component proxy-peer-mentor-selector depends on proxy-registration-service
epic-proxy-activity-registration-orchestration-task-004 component Cross-Epic Component proxy-peer-mentor-selector depends on proxy-registration-service
epic-proxy-activity-registration-orchestration-task-005 component Cross-Epic Component proxy-peer-mentor-selector depends on proxy-registration-service
epic-proxy-activity-registration-orchestration-task-010 component Cross-Epic Component proxy-peer-mentor-selector depends on proxy-registration-service
epic-proxy-activity-registration-orchestration-task-006 component Cross-Epic Component proxy-peer-mentor-selector depends on bulk-registration-service
epic-proxy-activity-registration-orchestration-task-007 component Cross-Epic Component proxy-peer-mentor-selector depends on bulk-registration-service
epic-proxy-activity-registration-orchestration-task-008 component Cross-Epic Component proxy-peer-mentor-selector depends on bulk-registration-service
epic-proxy-activity-registration-orchestration-task-009 component Cross-Epic Component proxy-peer-mentor-selector depends on bulk-registration-service
epic-proxy-activity-registration-orchestration-task-011 component Cross-Epic Component proxy-peer-mentor-selector depends on bulk-registration-service
epic-proxy-activity-registration-core-services-task-001 component Cross-Epic Component proxy-peer-mentor-selector depends on proxy-duplicate-detection-service
epic-proxy-activity-registration-core-services-task-002 component Cross-Epic Component proxy-peer-mentor-selector depends on proxy-duplicate-detection-service
epic-proxy-activity-registration-core-services-task-003 component Cross-Epic Component proxy-peer-mentor-selector depends on proxy-duplicate-detection-service
epic-proxy-activity-registration-core-services-task-008 component Cross-Epic Component proxy-peer-mentor-selector depends on proxy-duplicate-detection-service
epic-proxy-activity-registration-core-services-task-004 component Cross-Epic Component proxy-peer-mentor-selector depends on activity-attribution-service
epic-proxy-activity-registration-core-services-task-005 component Cross-Epic Component proxy-peer-mentor-selector depends on activity-attribution-service
epic-proxy-activity-registration-core-services-task-006 component Cross-Epic Component proxy-peer-mentor-selector depends on activity-attribution-service
epic-proxy-activity-registration-core-services-task-007 component Cross-Epic Component proxy-peer-mentor-selector depends on activity-attribution-service
epic-proxy-activity-registration-core-services-task-009 component Cross-Epic Component proxy-peer-mentor-selector depends on activity-attribution-service
epic-proxy-activity-registration-core-services-task-010 component Cross-Epic Component proxy-peer-mentor-selector depends on activity-attribution-service

Implementation Notes

Implement debounce using a Timer in the Riverpod notifier or a custom debounce utility — cancel and restart the timer on each keystroke. The Riverpod provider should be scoped to the widget (using ref.watch inside a ConsumerStatefulWidget) and auto-disposed. Supabase query: use the Supabase Flutter client's .ilike() for case-insensitive partial match. The chapterScope parameter must be the chapter UUID (not display name) for reliable filtering.

Validate that Supabase RLS policies restrict peer_mentor queries to the authenticated coordinator's chapter — if RLS is not yet in place, add a TODO and enforce in application layer. PeerMentorResultTile should be a separate widget file to keep the selector manageable. Use ListView.builder with itemCount capped at 10 (max results from API). Ensure OverlayEntry from task-007 is updated via setState() when results arrive.

Testing Requirements

Widget tests with mocked Supabase/Riverpod provider: (1) input '<2 chars' → overlay hidden; (2) input '≥2 chars' → loading state → results rendered after debounce; (3) Supabase mock returns empty list → empty state shown; (4) Supabase mock throws → error state shown with Retry button; (5) tap result tile → onChanged called with correct PeerMentor; (6) clear input → overlay dismissed. Integration test: real Supabase test instance query with chapter_id filter returns only chapter-scoped mentors. Use fake_async package to test debounce timing without real delays.

Component
Proxy Peer Mentor Selector
ui medium
Epic Risks (4)
medium impact high prob scope

The bulk registration screen combines pre-filled defaults, a dynamic multi-select participant list, per-participant conflict badges, and a batch submission confirmation — making it one of the most complex screens in the application. Scope creep or underestimated interaction complexity could cause the epic to exceed its estimate significantly.

Mitigation & Contingency

Mitigation: Implement the bulk screen in two vertical slices: (1) participant selection and form submission without conflict handling, (2) conflict badge rendering and override flow. Validate slice 1 with coordinators before building slice 2.

Contingency: If the full conflict review UI cannot be completed within the epic, ship the bulk screen with a simplified 'skip all duplicates' fallback mode and defer per-participant override toggles to a follow-up sprint.

medium impact medium prob technical

The proxy-registration-bloc must manage state across two distinct flows (single proxy and bulk) with branching conflict paths, intermediate buffering of bulk participant selections, and reliable state reset. Incorrect state transitions could leave the UI in a loading or stale-conflict state after submission.

Mitigation & Contingency

Mitigation: Model the BLoC state as a sealed class hierarchy with exhaustive pattern matching in the UI. Write state-machine unit tests that exercise every valid transition and assert that invalid transitions are no-ops. Use flutter_bloc's BlocObserver in debug builds to log all transitions.

Contingency: If BLoC state bugs surface in QA, introduce an explicit ResetToIdle event triggered on screen disposal to guarantee clean state, and add a 'Start over' affordance visible to the coordinator at any conflict step.

high impact medium prob technical

The typeahead peer mentor selector with multi-select mode may be difficult to operate with VoiceOver/TalkBack, particularly the dynamic search results list and the selected-chip removal controls, risking WCAG 2.2 AA non-compliance for screen reader users.

Mitigation & Contingency

Mitigation: Wrap all search result items and selected chips with explicit Semantics widgets providing role, label, and selected-state announcements. Test the selector with VoiceOver on iOS and TalkBack on Android during development, not only at QA time.

Contingency: If the multi-select typeahead cannot be made fully accessible within the sprint, provide an alternative flat scrollable list with checkboxes as a fallback mode, toggled by an accessibility-settings flag.

high impact medium prob security

The peer mentor selector must apply RLS chapter-scope filtering to show only mentors the coordinator is responsible for. If the Supabase query for the selector does not correctly join against the coordinator's chapter assignments, coordinators may see mentors from other chapters, violating data isolation.

Mitigation & Contingency

Mitigation: Implement the selector's data query using the same RLS-aware Supabase client used by the contact list feature, which already handles chapter-scope filtering. Write an integration test with a multi-chapter coordinator fixture asserting cross-chapter mentors are not returned.

Contingency: If a data isolation breach is discovered, immediately add a client-side chapter_id filter as a defence-in-depth measure and audit selector query logs for any unauthorised cross-chapter results.