critical priority medium complexity frontend pending frontend specialist Tier 4

Acceptance Criteria

Tapping the submit button triggers ProxyRegistrationFormCubit.submit() exactly once; rapid double-taps do not dispatch two service calls
Submit button is visually disabled (opacity 0.4, non-interactive) and shows a CircularProgressIndicator while the cubit state is ProxyRegistrationSubmitting
When ProxyRegistrationService returns an AttributionValidationFailure, each field-level error message is rendered inline beneath its corresponding form field without clearing existing field values
When the service call succeeds, the router navigates to the confirmation screen with the newly created proxy activity ID passed as a route parameter
When the service call fails with a network error (timeout, no connectivity), a SnackBar appears with the error message and a 'Retry' action that re-dispatches the same submit payload
On retry the submit button re-disables and the loading indicator reappears until the second call resolves
The cubit emits states in the correct sequence: ProxyRegistrationIdle → ProxyRegistrationSubmitting → ProxyRegistrationSuccess | ProxyRegistrationFailure
No orphaned loading states remain if the widget is disposed mid-flight (cubit closes cleanly)

Technical Requirements

frameworks
Flutter
BLoC/Cubit
flutter_bloc
apis
ProxyRegistrationService.submit()
AttributionValidator API
GoRouter or Navigator 2.0 for confirmation screen navigation
data models
ProxyActivity
AttributionValidationResult
ProxyRegistrationFormState
performance requirements
Submit debounce or single-flight guard must prevent duplicate in-flight requests
State transition from submitting to success/failure must complete within 300 ms of service response receipt (UI update latency)
security requirements
Coordinator identity (coordinator_id) must be injected server-side via Supabase RLS — never trust client-supplied coordinator_id
Form payload must be validated both client-side (AttributionValidator) and server-side before persistence
ui components
AppButton (disabled state)
CircularProgressIndicator
Inline field error Text widgets
ScaffoldMessenger SnackBar with retry action

Execution Context

Execution Tier
Tier 4

Tier 4 - 323 tasks

Can start after Tier 3 completes

Implementation Notes

Use BlocConsumer to split UI rebuilds (builder) from side-effect navigation/snackbar logic (listener). The submit guard belongs in the cubit, not in the widget — set a bool _isSubmitting flag or rely on the Submitting state being non-re-entrant. For navigation, push the confirmation route from the BlocListener when state is ProxyRegistrationSuccess, passing activityId. For the retry SnackBar use ScaffoldMessenger.of(context).showSnackBar() inside the listener.

Keep the cubit unaware of BuildContext — all navigation and snackbar calls stay in the widget layer. Ensure cubit.close() is handled by BlocProvider so in-flight futures that complete after disposal do not call emit() (wrap with isClosed guard in the cubit or use stream subscriptions that cancel on close).

Testing Requirements

Unit-test ProxyRegistrationFormCubit submit() method: stub ProxyRegistrationService with mockito/mocktail to return success, validation failure, and network error; assert correct state sequences. Widget-test the ProxyRegistrationScreen: verify button disables on submit, inline errors render on validation failure, SnackBar appears on network error with retry affordance, and navigation is triggered on success (use a mock GoRouter or NavigatorObserver). Achieve 100% branch coverage on the cubit's submit path. Regression test: verify double-tap does not produce two service calls.

Component
Proxy Registration Screen
ui medium
Epic Risks (3)
medium impact medium prob technical

The 2-hour window duplicate detection logic requires querying existing proxy records with compound key matching (mentor + date + activity type within time range). If the query is too broad it produces false positives that frustrate coordinators; if too narrow it misses genuine duplicates that corrupt Bufdir data.

Mitigation & Contingency

Mitigation: Define the duplicate detection window as a configurable parameter from the start. Prototype the Supabase query with representative data covering edge cases (midnight boundaries, different activity types same day, same activity type different mentors) before finalising the implementation.

Contingency: If the detection produces excessive false positives in UAT, allow coordinators to explicitly acknowledge and bypass the duplicate warning with a reason field, preserving safety while reducing friction.

high impact medium prob scope

If the proxy registration form does not clearly distinguish between the acting coordinator and the attributed mentor, coordinators may submit records attributing activities to themselves, causing inaccurate Bufdir reporting and potential funding issues.

Mitigation & Contingency

Mitigation: Conduct UAT with at least one real coordinator via TestFlight before release. Use distinct visual treatment (different card colours, explicit 'Registering on behalf of:' label) and require the confirmation screen to show both identities prominently.

Contingency: Add a mandatory confirmation checkbox on the confirmation screen that explicitly names the attributed mentor, preventing accidental self-attribution from slipping through.

high impact medium prob security

Coordinators with multi-chapter access must select an active chapter context before the mentor list is filtered correctly. If chapter scope resolution fails or is bypassed, cross-org proxy registrations could occur, violating data isolation between chapters.

Mitigation & Contingency

Mitigation: Reuse the existing active-chapter-state and hierarchy-service components established by the org hierarchy feature. Add a guard that blocks entry to the proxy flow if no chapter context is active, prompting chapter selection first.

Contingency: If the chapter resolution service is unavailable, default to the most restrictive scope (no mentors visible) and surface a clear error message rather than showing an unfiltered mentor list.