high priority high complexity frontend pending frontend specialist Tier 15

Acceptance Criteria

ProxyPeerMentorSelector renders in multi-select mode within BulkRegistrationScreen with all visible peer mentors listed and individually selectable
Tapping a mentor who is not yet in the participant list dispatches AddParticipant event and the mentor appears in BulkParticipantList within one frame
Tapping a mentor who is already in the participant list shows an inline snackbar or tooltip with 'Already added' message and does NOT dispatch a second AddParticipant event
Tapping the remove icon on a participant in BulkParticipantList dispatches RemoveParticipant event and the row is removed from the list within one frame
Participant count badge updates reactively after every AddParticipant and RemoveParticipant event and always reflects BLoC state accurately
Count badge is visible and readable with a contrast ratio ≥ 4.5:1 against its background (WCAG 2.2 AA)
All interactive elements (checkboxes, remove icons, mentor rows) have semantic labels readable by TalkBack and VoiceOver
Participant list scrolls independently when it exceeds visible height without interfering with the mentor selector scroll
Screen renders correctly on device widths from 320 px to 428 px without overflow
When BLoC emits a reset state, the participant list clears and count badge resets to 0

Technical Requirements

frameworks
Flutter
flutter_bloc
BLoC
data models
PeerMentor
BulkParticipant
performance requirements
List updates complete within a single frame (≤16 ms) for participant lists up to 50 mentors
Mentor selector search/filter response ≤ 100 ms on mid-range devices
No unnecessary BLoC rebuilds — use BlocBuilder with buildWhen to scope rebuilds to participant list and count badge only
security requirements
Only mentors belonging to the coordinator's organisation are shown in the selector — enforce via Supabase RLS on the query supplying mentor data to the BLoC
Coordinator identity verified via current Supabase session before loading mentor list
ui components
ProxyPeerMentorSelector (multi-select mode)
BulkParticipantList
Participant count badge widget
Duplicate-addition inline feedback (snackbar or tooltip)
Remove icon button per participant row

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 bulk-registration-screen depends on proxy-registration-service
epic-proxy-activity-registration-orchestration-task-002 component Cross-Epic Component bulk-registration-screen depends on proxy-registration-service
epic-proxy-activity-registration-orchestration-task-003 component Cross-Epic Component bulk-registration-screen depends on proxy-registration-service
epic-proxy-activity-registration-orchestration-task-004 component Cross-Epic Component bulk-registration-screen depends on proxy-registration-service
epic-proxy-activity-registration-orchestration-task-005 component Cross-Epic Component bulk-registration-screen depends on proxy-registration-service
epic-proxy-activity-registration-orchestration-task-010 component Cross-Epic Component bulk-registration-screen depends on proxy-registration-service
epic-proxy-activity-registration-orchestration-task-006 component Cross-Epic Component bulk-registration-screen depends on bulk-registration-service
epic-proxy-activity-registration-orchestration-task-007 component Cross-Epic Component bulk-registration-screen depends on bulk-registration-service
epic-proxy-activity-registration-orchestration-task-008 component Cross-Epic Component bulk-registration-screen depends on bulk-registration-service
epic-proxy-activity-registration-orchestration-task-009 component Cross-Epic Component bulk-registration-screen depends on bulk-registration-service
epic-proxy-activity-registration-orchestration-task-011 component Cross-Epic Component bulk-registration-screen depends on bulk-registration-service
epic-proxy-activity-registration-core-services-task-001 component Cross-Epic Component bulk-registration-screen depends on proxy-duplicate-detection-service
epic-proxy-activity-registration-core-services-task-002 component Cross-Epic Component bulk-registration-screen depends on proxy-duplicate-detection-service
epic-proxy-activity-registration-core-services-task-003 component Cross-Epic Component bulk-registration-screen depends on proxy-duplicate-detection-service
epic-proxy-activity-registration-core-services-task-008 component Cross-Epic Component bulk-registration-screen depends on proxy-duplicate-detection-service
epic-proxy-activity-registration-core-services-task-004 component Cross-Epic Component bulk-registration-screen depends on activity-attribution-service
epic-proxy-activity-registration-core-services-task-005 component Cross-Epic Component bulk-registration-screen depends on activity-attribution-service
epic-proxy-activity-registration-core-services-task-006 component Cross-Epic Component bulk-registration-screen depends on activity-attribution-service
epic-proxy-activity-registration-core-services-task-007 component Cross-Epic Component bulk-registration-screen depends on activity-attribution-service
epic-proxy-activity-registration-core-services-task-009 component Cross-Epic Component bulk-registration-screen depends on activity-attribution-service
epic-proxy-activity-registration-core-services-task-010 component Cross-Epic Component bulk-registration-screen depends on activity-attribution-service

Implementation Notes

Use BlocBuilder with a narrow buildWhen predicate (compare participants list and count only) to avoid rebuilding the full screen on unrelated state changes. Maintain participant order by insertion time — use a LinkedHashSet or an ordered list in BLoC state so the UI is deterministic. For duplicate detection, compare by mentor ID (not name) in the BLoC before emitting updated state, and emit a ProxyRegistrationDuplicateAttempt event or side-effect stream so the screen can show the snackbar without polluting state. The count badge should be a simple AnimatedSwitcher-wrapped Text to give a subtle animation on change.

Keep ProxyPeerMentorSelector stateless at the widget level — all selection state lives in the BLoC. Coordinator use case from workshop notes: weekly group training with many participants, so the list may grow to 20–40 mentors; ensure the remove action is large enough (min 44×44 dp tap target) for users with motor impairments.

Testing Requirements

Write widget tests covering: (1) AddParticipant event is dispatched exactly once when an unselected mentor is tapped; (2) RemoveParticipant event is dispatched when remove icon is tapped; (3) duplicate mentor tap shows inline feedback and does not add a second entry; (4) count badge value matches participant list length after a sequence of adds and removes; (5) BLoC reset clears list and resets badge. Use flutter_test with a MockProxyRegistrationBloc (mocktail). Add golden tests for count badge at 0, 1, and 10+ participants. Target ≥ 90% branch coverage for multi-select interaction logic.

Component
Bulk Registration Screen
ui high
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.