critical priority medium complexity frontend pending frontend specialist Tier 4

Acceptance Criteria

ProxyRegistrationBLoC is implemented using flutter_bloc's Bloc<ProxyRegistrationEvent, ProxyRegistrationState> base class
All BLoC events are sealed classes: MentorSelected, MentorDeselected, TemplateSelected, TemplatePrefillRequested, SingleSubmissionRequested, BulkSubmissionRequested, SubmissionReset
All BLoC states are sealed classes: ProxyRegistrationIdle, ProxyRegistrationValidating, ProxyRegistrationLoading, BulkRegistrationProgress(completedCount, totalCount, outcomes), ProxyRegistrationSuccess, ProxyRegistrationPartialFailure(outcomes), ProxyRegistrationFailure(error)
MentorSelected/MentorDeselected events update a Set<String> of selected mentor IDs in state without triggering any network call
TemplateSelected updates the current template in state and clears any previous validation errors
TemplatePrefillRequested populates form fields from a stored template; existing user edits are overwritten only after an explicit confirmation event
SingleSubmissionRequested delegates to ProxyRegistrationService and emits Success or Failure state based on ProxyActivityResult
BulkSubmissionRequested delegates to BulkRegistrationOrchestrator; as the progress stream emits, BLoC emits sequential BulkRegistrationProgress states; final state is Success, PartialFailure, or Failure
SubmissionReset returns the BLoC to ProxyRegistrationIdle with empty mentor selection and cleared template
BLoC is provided via a MultiBlocProvider at a route level shared by both ProxyRegistrationScreen and BulkProxyRegistrationScreen so both screens share the same BLoC instance
Unit tests using bloc_test cover all event → state transition sequences, including: mentor selection flow, template prefill override guard, single submission success/failure, bulk progress sequence, partial failure final state, reset from success/failure states

Technical Requirements

frameworks
Flutter
BLoC (flutter_bloc ≥8.0)
Riverpod (for injecting services into the BLoC constructor)
bloc_test (testing)
apis
ProxyRegistrationService.submit()
BulkRegistrationOrchestrator.submit() returning BulkSubmissionHandle
data models
ProxyRegistrationState (sealed)
ProxyRegistrationEvent (sealed)
BulkRegistrationProgress
MentorSubmissionOutcome
ProxyActivityResult
BulkSubmissionResult
performance requirements
State emissions during bulk progress must not cause full widget tree rebuilds; use BlocBuilder with buildWhen to scope rebuilds to specific widgets
BLoC must not retain references to completed submission results after SubmissionReset to avoid memory leaks in long-running coordinator sessions
security requirements
BLoC must never store raw PII (mentor full names, phone numbers) in state — only IDs; display names are resolved by the widget layer from the contacts repository
Submission events must be rate-limited at the BLoC layer: if a submission is already in-flight, duplicate BulkSubmissionRequested or SingleSubmissionRequested events are silently dropped

Execution Context

Execution Tier
Tier 4

Tier 4 - 323 tasks

Can start after Tier 3 completes

Implementation Notes

Wire the BulkRegistrationOrchestrator's progress Stream into the BLoC by adding a subscription inside the event handler: await emit.forEach(progressStream, onData: (update) => BulkRegistrationProgress(...)). This is the canonical flutter_bloc pattern for streaming side effects. Use on() with transformer: droppable() from bloc_concurrency to automatically drop duplicate submissions while one is in-flight. For the mentor selection state, store a Set mentorIds inside the state rather than a List to automatically deduplicate selections.

Keep the BLoC thin — all business logic lives in ProxyRegistrationService and BulkRegistrationOrchestrator; the BLoC only coordinates events and maps results to UI states.

Testing Requirements

Use bloc_test's blocTest() to test every event → state sequence. Required test cases: (1) initial state is ProxyRegistrationIdle, (2) MentorSelected adds to selection set, (3) MentorDeselected removes from set, (4) TemplateSelected clears errors, (5) SingleSubmissionRequested → Loading → Success, (6) SingleSubmissionRequested → Loading → Failure, (7) BulkSubmissionRequested → Loading → Progress(1/3) → Progress(2/3) → Progress(3/3) → PartialFailure, (8) SubmissionReset from PartialFailure returns Idle, (9) duplicate BulkSubmissionRequested while Loading is dropped (no state change). Mock both ProxyRegistrationService and BulkRegistrationOrchestrator. Minimum 95% branch coverage on the BLoC class.

Component
Proxy Registration BLoC
service medium
Epic Risks (3)
high impact high prob scope

Partial failures in bulk registration — where some mentors succeed and others fail — create a complex UX state that is easy to mishandle. If the UI does not clearly communicate which records succeeded and which failed, coordinators may re-submit already-saved records (creating duplicates) or miss failed records entirely (creating underreporting).

Mitigation & Contingency

Mitigation: Design the per-mentor result screen as a primary deliverable of this epic, not an afterthought. Use a clear list view with success/failure indicators per mentor name, and offer a 'Retry failed' action that pre-selects only the failed mentors for resubmission.

Contingency: If partial failure UX proves too complex to deliver within scope, implement a simpler all-or-nothing submission mode for the initial release with a clear error message listing which mentors failed, and defer the partial-retry UI to a follow-up sprint.

medium impact medium prob technical

Submitting proxy records for a large group (e.g., 30+ mentors) as individual Supabase inserts may cause latency issues or hit rate limits, degrading the coordinator experience and potentially causing timeout failures that leave data in an inconsistent state.

Mitigation & Contingency

Mitigation: Implement the BulkRegistrationOrchestrator to batch inserts using a Supabase RPC call that accepts an array of proxy records, reducing round-trips to a single network call. Add progress indication using a stream of per-record results if the RPC supports it.

Contingency: If the RPC approach is blocked by Supabase limitations, fall back to chunked parallel inserts (5 records per batch) with retry logic, capping total submission time and surface a progress bar to manage coordinator expectations.

medium impact medium prob technical

Unifying state management for both single and bulk proxy flows in a single BLoC risks state leakage between flows — for example, a previously selected mentor list persisting when a coordinator switches from bulk to single mode — causing confusing UI states or incorrect submissions.

Mitigation & Contingency

Mitigation: Define separate, named state subtrees within the BLoC for single-proxy state and bulk-proxy state, with explicit reset events triggered on flow entry. Write unit tests for state isolation scenarios using the bloc_test package.

Contingency: If unified BLoC state becomes unmanageable, split into two separate BLoCs (ProxySingleRegistrationBLoC and ProxyBulkRegistrationBLoC) sharing only common events via a parent coordinator Cubit.