critical priority high complexity frontend pending frontend specialist Tier 17

Acceptance Criteria

ProxyRegistrationBloc initialises in ProxyRegistrationInitial state and transitions to ProxyRegistrationLoading when LoadMentors event is dispatched
After mentors load successfully, state transitions to ProxyRegistrationReady containing the loaded mentor list and an empty participant list
AddParticipant event updates participants list in state; adding a duplicate mentor ID does not change the list and triggers a ProxyRegistrationDuplicateAttempt side effect or equivalent
RemoveParticipant event removes the matching participant from state; no-op if ID not present
UpdateFormField event updates the relevant form field value in state; BLoC performs field-level validation and emits validation errors as part of state
CheckConflicts event calls ProxyRegistrationService.checkConflicts, transitions to ProxyRegistrationConflictsDetected with per-participant conflict details when conflicts exist, or remains in ready state when none found
SubmitBulkRegistration event transitions to ProxyRegistrationSubmitting, calls BulkRegistrationService.submitBatch, then transitions to ProxyRegistrationSuccess with result summary or ProxyRegistrationError with error message
SubmitSingleRegistration event follows equivalent flow using ProxyRegistrationService.submit
ResetForm event (and automatic reset after success) transitions back to ProxyRegistrationReady with cleared form fields and empty participant list
CancelRegistration event transitions to reset state from any non-submitting state
BLoC properly cancels in-flight async operations when closed (dispose of subscriptions)
All state transitions are covered by unit tests with no unhandled exception escapes

Technical Requirements

frameworks
Flutter
flutter_bloc
BLoC
Riverpod
apis
ProxyRegistrationService.checkConflicts
ProxyRegistrationService.submit
BulkRegistrationService.submitBatch
MentorRepository.getMentorsByOrganisation
data models
ProxyRegistrationForm
BulkParticipant
ConflictDetail
BulkRegistrationResult
ProxyRegistrationResult
performance requirements
State transitions complete synchronously for local mutations (AddParticipant, RemoveParticipant, UpdateFormField) — no unnecessary async overhead
Conflict check completes within 3 seconds on standard network; BLoC must remain responsive during async call
Batch submission handles up to 50 participants without timeout
security requirements
BLoC obtains coordinator user ID from injected auth repository — never accepts it as an event parameter
Service calls include Supabase JWT from session; BLoC does not store or log tokens
Form data containing PII (mentor names, activity details) is not persisted in BLoC beyond the current session lifetime

Execution Context

Execution Tier
Tier 17

Tier 17 - 1 tasks

Can start after Tier 16 completes

Dependencies (11)
epic-proxy-activity-registration-orchestration-task-001 component Cross-Epic Component proxy-registration-bloc depends on proxy-registration-service
epic-proxy-activity-registration-orchestration-task-002 component Cross-Epic Component proxy-registration-bloc depends on proxy-registration-service
epic-proxy-activity-registration-orchestration-task-003 component Cross-Epic Component proxy-registration-bloc depends on proxy-registration-service
epic-proxy-activity-registration-orchestration-task-004 component Cross-Epic Component proxy-registration-bloc depends on proxy-registration-service
epic-proxy-activity-registration-orchestration-task-005 component Cross-Epic Component proxy-registration-bloc depends on proxy-registration-service
epic-proxy-activity-registration-orchestration-task-010 component Cross-Epic Component proxy-registration-bloc depends on proxy-registration-service
epic-proxy-activity-registration-orchestration-task-006 component Cross-Epic Component proxy-registration-bloc depends on bulk-registration-service
epic-proxy-activity-registration-orchestration-task-007 component Cross-Epic Component proxy-registration-bloc depends on bulk-registration-service
epic-proxy-activity-registration-orchestration-task-008 component Cross-Epic Component proxy-registration-bloc depends on bulk-registration-service
epic-proxy-activity-registration-orchestration-task-009 component Cross-Epic Component proxy-registration-bloc depends on bulk-registration-service
epic-proxy-activity-registration-orchestration-task-011 component Cross-Epic Component proxy-registration-bloc depends on bulk-registration-service

Implementation Notes

Use Equatable on all state and event classes to enable value-equality in bloc_test assertions. Model state as a sealed class (Dart 3 sealed) or a discriminated union with a single ProxyRegistrationState base: ProxyRegistrationInitial, ProxyRegistrationLoading, ProxyRegistrationReady (holds form, participants, validationErrors, conflicts), ProxyRegistrationSubmitting, ProxyRegistrationSuccess, ProxyRegistrationError. Avoid splitting into too many state classes — ProxyRegistrationReady should carry all mutable form state to keep transitions predictable. For duplicate detection, the BLoC should check by mentorId in the current participants list before forwarding to the service.

Use StreamSubscription and cancel in close() for any real-time streams (e.g. mentor availability). Provide the BLoC via a Riverpod Provider (or BlocProvider inside a Riverpod-aware widget) so it can be scoped to the route and automatically disposed on pop. This BLoC is the authoritative state owner for both the individual proxy screen and the bulk screen — the two screens should share one BLoC instance scoped to their common route ancestor.

Testing Requirements

Full BLoC unit test suite using bloc_test package: test every event→state transition including happy path, error paths, and edge cases (duplicate add, submit while empty, service timeout). Use mocktail to mock ProxyRegistrationService, BulkRegistrationService, and MentorRepository. Verify: (1) state sequence for full happy-path bulk flow (load→ready→add participants→check conflicts→submit→success→reset); (2) error state emitted when service throws; (3) duplicate add produces no state change to participant list; (4) CancelRegistration from any intermediate state reaches reset; (5) BLoC.close() cancels in-flight streams. Target 100% state transition coverage and ≥ 95% line coverage for BLoC class.

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