critical priority medium complexity frontend pending frontend specialist Tier 2

Acceptance Criteria

Screen displays form fields: activity type (dropdown), date (date picker), start time (time picker), duration (dropdown or stepper in 15-min increments), notes (multiline text field), and mentor selector (MentorSingleSelectWidget)
ProxyRegistrationFormCubit holds the complete form state as an immutable value object with fields: activityTypeId, date, startTime, durationMinutes, notes, selectedMentorId
All fields start with null/default values; the cubit exposes a `isDirty` flag set to true after the first user interaction
Validation is triggered on submit: required fields (activityTypeId, date, startTime, durationMinutes, selectedMentorId) show inline error messages if empty
Duration defaults to 30 minutes on initial load (matching the design principle of useful defaults)
Date field defaults to today's date on initial load
Notes field is optional — no validation error for empty notes
Form is scrollable so all fields are reachable on small screens (320px width)
Submit button is disabled while the cubit is in a loading/submitting state
Back/cancel navigation prompts the user with a discard-changes dialog if isDirty is true
All form field labels and error messages are accessible to screen readers via Semantics widgets
WCAG 2.2 AA: all interactive elements have ≥ 48dp tap targets, sufficient color contrast on labels and error text

Technical Requirements

frameworks
Flutter
BLoC/Cubit
Riverpod
data models
activity
activity_type
assignment
performance requirements
Screen initial render completes within one frame (≤16ms) — no synchronous heavy computation in build()
Form field updates emit cubit state changes within 8ms
security requirements
Notes field input is sanitized before submission — strip leading/trailing whitespace, enforce max length of 2000 characters
No PII from the mentor record is stored in the form cubit state beyond the mentor UUID
ui components
ProxyRegistrationScreen
ProxyRegistrationFormCubit
ProxyRegistrationFormState (immutable value class)
MentorSingleSelectWidget (existing, from foundation epic)
ActivityTypeSelectorWidget (dropdown)
DurationSelectorWidget (stepper/dropdown)
DatePickerField
TimePickerField
NotesTextField

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

Use `Cubit` rather than full `Bloc` — form state management does not need discrete events, simple method calls on the cubit are cleaner. Define `ProxyRegistrationFormState` as an `@immutable` class using `copyWith`. Keep the cubit free of Supabase/repository dependencies — it is pure UI state; submission is handled by ProxyRegistrationService (task-008). For date and time pickers, use Flutter's built-in `showDatePicker` / `showTimePicker` and map the result back to the cubit via `context.read().updateDate(picked)`.

Duration selector: use a `DropdownButtonFormField` with values `[15, 30, 45, 60, 90, 120]` minutes — avoids free-text errors. For the discard dialog, use `WillPopScope` (or `PopScope` in Flutter 3.10+) that checks `cubit.state.isDirty` before allowing navigation.

Testing Requirements

Widget tests in `test/widget/proxy_registration_screen_test.dart`. Test cases: (1) all form fields render with correct defaults (30min, today), (2) submitting with empty required fields shows inline validation errors, (3) filling all required fields and submitting does not show errors, (4) cubit emits dirty state after first field interaction, (5) back navigation with dirty state shows discard dialog, (6) back navigation with clean state navigates without dialog. Use `BlocProvider` / `ProviderScope` to inject fake cubit. Also add cubit unit tests in `test/unit/proxy_registration_form_cubit_test.dart` covering state transitions for each field update and validation logic.

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.