high priority medium complexity frontend pending frontend specialist Tier 15

Acceptance Criteria

ProxyPeerMentorSelector is rendered in single-select mode inside the scrollable body of ProxyRegistrationScreen, above the activity form
Selecting a mentor dispatches a SelectMentor(mentorId, mentorName) event to ProxyRegistrationBloc
After selection, a confirmation chip displays the selected mentor's full name with an 'x' clear button
Tapping the clear button dispatches a ClearMentorSelection event and removes the chip
When the submit button is tapped with no mentor selected, an inline validation error message 'Please select a peer mentor' appears below the selector
The validation error is dismissed as soon as a mentor is selected
The confirmation chip uses the design token for role/mentor entity color (rose #fb7185 or equivalent from token palette)
The selector and chip are accessible: chip has a semanticsLabel describing the selected mentor, clear button has tooltip and semanticsLabel 'Remove selected mentor'
BLoC state correctly stores the selected mentorId and exposes it for the submission step

Technical Requirements

frameworks
Flutter
BLoC
data models
PeerMentorSummary (id, fullName)
ProxyRegistrationState (selectedMentorId, selectedMentorName, mentorValidationError)
performance requirements
Chip render and clear must complete within a single frame (no async operations)
security requirements
Mentor list must only include peer mentors accessible to the current coordinator — enforced by the Supabase query in the BLoC, not filtered client-side only
ui components
ProxyPeerMentorSelector (single-select mode, from task-009)
FilterChip or InputChip with delete icon for selected mentor display
Text widget styled with AppTextStyle.errorSmall for validation error
Semantics wrapping chip and clear button

Execution Context

Execution Tier
Tier 15

Tier 15 - 2 tasks

Can start after Tier 14 completes

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

Implementation Notes

Use BlocBuilder scoped to only the mentor-selection slice of ProxyRegistrationState to avoid rebuilding the entire screen on every BLoC state change — consider using BlocSelector. The validation error should be stored as a nullable string in the BLoC state, not as a local widget variable, so that it survives widget rebuilds and is testable. The confirmation chip should use InputChip (which has built-in delete support) rather than a custom Row. Do not use FilterChip for the selected state as it lacks semantic delete action.

The mentor selector from task-009 should be passed a callback that the screen translates into a BLoC event — keep the selector widget decoupled from BLoC directly for reusability.

Testing Requirements

Widget tests (flutter_test): stub BLoC with mentor-loaded state, verify selector renders, simulate mentor selection and verify SelectMentor event is emitted, verify confirmation chip appears with correct name, tap clear button and verify ClearMentorSelection event is emitted and chip disappears, tap submit with no mentor selected and verify validation error text appears. Unit tests: BLoC transitions for SelectMentor and ClearMentorSelection events. Accessibility test: confirm chip and clear button have correct semantics labels via SemanticsController.

Component
Proxy Registration Screen
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.