high priority high complexity frontend pending frontend specialist Tier 14

Acceptance Criteria

BulkRegistrationScreen is registered as a named GoRouter route (e.g. /bulk-registration) with coordinator-only role guard enforced at router level
Non-coordinator roles see the existing NoAccessWidget with appropriate message and back navigation
Screen AppBar displays title 'Bulk Activity Registration' with a back button
Screen body is a single scrollable column with two clearly delineated sections: (1) 'Participants' section at the top for multi-mentor selection, (2) 'Activity Details' section below for the shared ProxyActivityForm
Each section has a visible section header using design token typography (e.g. AppTextStyle.labelLarge)
Screen dispatches a LoadBulkRegistrationData event to ProxyRegistrationBloc on mount, passing a bulkMode: true flag
BulkRegistrationDefaultsProvider is read on screen init and used to pre-populate ProxyActivityForm: today's date and a configurable default duration (e.g. 60 minutes for recurring sessions)
Loading state shows a centered CircularProgressIndicator; error state shows retry option
A sticky bottom bar contains a 'Register for All' button (disabled during loading) and a participant count label showing 'X mentor(s) selected'
Screen is fully accessible: section headers have semantic heading roles, participant count is announced as a live region when count changes
BlocProvider scopes ProxyRegistrationBloc (bulk mode) to this screen's lifetime

Technical Requirements

frameworks
Flutter
BLoC
GoRouter
Riverpod (for BulkRegistrationDefaultsProvider)
data models
BulkRegistrationDefaults (defaultDate, defaultDuration, defaultActivityType)
ProxyRegistrationState (bulkMode, selectedMentorIds, participantCount)
ProxyRegistrationEvent (LoadBulkRegistrationData)
performance requirements
Screen must reach first meaningful paint within 300ms
Participant count label must update within one frame of mentor selection change
Scrollable two-section layout must not jank on devices with 60Hz refresh rate
security requirements
Bulk registration route must be inaccessible to peer mentor roles even via direct deep link — enforced at GoRouter redirect level
Coordinator identity for attribution must come from authenticated Supabase session only
ui components
AppBar with design token styling
Two-section Column layout with SliverList or CustomScrollView for performance
Section header widgets using AppTextStyle.labelLarge
ProxyActivityForm (task-010) with defaults injected
Placeholder for multi-mentor selector (to be added in subsequent tasks)
Sticky bottom bar with AppButton ('Register for All') and Text participant count
Semantics(liveRegion: true) wrapping participant count
NoAccessWidget for role gate

Execution Context

Execution Tier
Tier 14

Tier 14 - 3 tasks

Can start after Tier 13 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

BulkRegistrationDefaultsProvider should be implemented as a Riverpod Provider (or simple singleton service) that reads from app-level configuration or user preferences — not hardcoded in the widget. Pass defaults into ProxyActivityForm via its initialValues parameter (add this parameter in task-010 if not already present). The two-section layout should use a single CustomScrollView with two SliverToBoxAdapter sections rather than a nested ListView to avoid scroll conflicts. The sticky bottom bar participant count ('X mentor(s) selected') must use BlocSelector scoped only to selectedMentorIds.length to avoid rebuilding the entire screen.

The 'Register for All' button label should also show the count: 'Register for 3 Mentors' — update label dynamically. This screen is architecturally the most complex in the epic; ensure the BLoC clearly distinguishes bulk mode from single-mentor mode via a mode enum in state, rather than using two separate BLoCs, to share submission and conflict-handling logic.

Testing Requirements

Widget tests (flutter_test): verify no-access state for peer mentor role (mock auth), verify two-section layout renders for coordinator role with correct section headers, verify LoadBulkRegistrationData event dispatched on mount (MockBloc), verify BulkRegistrationDefaultsProvider values pre-populate form fields (mock provider), verify loading state shows progress indicator, verify 'Register for All' button is disabled during loading, verify participant count label starts at '0 mentor(s) selected'. Unit tests: BLoC LoadBulkRegistrationData transition, BulkRegistrationDefaultsProvider default value logic. Accessibility test: verify section headers have Semantics(header: true), verify participant count has liveRegion: true. Integration test: navigate to route as coordinator, verify screen mounts without exceptions.

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.