high priority low complexity frontend pending frontend specialist Tier 1

Acceptance Criteria

Widget renders a scrollable horizontal chip list or card list showing each template's activity type name and default duration
Loading state: a shimmer or CircularProgressIndicator is displayed while templates are being fetched
Empty state: a message 'No saved templates' (or equivalent) is shown when the coordinator has no templates — no crash or blank space
Selecting a template invokes the onTemplateSelected(RecurringTemplate template) callback exactly once with the correct model
Widget accepts a required onTemplateSelected callback parameter of type void Function(RecurringTemplate)
Widget is stateless (or uses ConsumerWidget) — no local mutable state beyond selection highlight
Currently selected template is visually highlighted (accent color border or background)
Widget renders correctly on screen widths from 320px to 428px (phone range)
All interactive elements meet WCAG 2.2 AA tap target minimum (48x48dp)
Semantic labels are provided for screen reader support on each template chip/card

Technical Requirements

frameworks
Flutter
Riverpod
data models
activity_type
performance requirements
Widget build method completes in under 16ms (single frame budget)
No blocking calls inside build() — all async work via Riverpod AsyncValue
security requirements
Template data is display-only — no PII stored in template names or notes previews shown in this widget
ui components
RecurringTemplateSelector (this widget)
Template chip/card item widget
Loading shimmer widget
Empty state widget

Execution Context

Execution Tier
Tier 1

Tier 1 - 540 tasks

Can start after Tier 0 completes

Implementation Notes

Implement as a `ConsumerWidget` that watches a `recurringTemplatesProvider` (AsyncNotifierProvider). The provider will be wired in task-005; for this task, accept the provider as an override-injectable dependency or use a simple FutureProvider placeholder. Expose the widget via `onTemplateSelected` callback rather than managing selected state internally — let the parent (ProxyRegistrationFormCubit) own the state. Use `ListView.separated` with horizontal scroll direction for the chip list, or `Wrap` if a grid layout is preferred.

Apply design tokens for spacing and color — do not hardcode hex values. For accessibility, wrap each chip in `Semantics(label: '${template.activityTypeName}, ${template.defaultDuration} minutes', button: true, child: ...)`. The `RecurringTemplate` model should be a simple immutable data class with `activityTypeId`, `activityTypeName`, `defaultDurationMinutes`, and `notesTemplate` fields.

Testing Requirements

Widget tests using flutter_test. Create `test/widget/recurring_template_selector_test.dart`. Test cases: (1) shows loading indicator when AsyncValue is loading, (2) shows empty state when template list is empty, (3) renders correct number of chips for N templates, (4) tapping a chip fires onTemplateSelected with the correct RecurringTemplate instance, (5) selected chip has visual distinction (check decoration/color). Use `ProviderScope` with overridden provider returning fake data.

Pump with `tester.pumpWidget()` and `tester.pump()`. No golden tests required for this task.

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.