critical priority medium complexity frontend pending frontend specialist Tier 2

Acceptance Criteria

CoordinatorStatsScreen renders a page header with Semantics(header: true) and the active chapter name as a subtitle below or beside the title
ChapterScopeResolver provides the active chapter; screen reads it via ref.watch(activeChapterProvider)
Single-chapter coordinators see no chapter switcher — the chapter name is displayed as static text
Multi-chapter coordinators (2+ affiliated chapters) see a ChapterSwitcherWidget (e.g. dropdown or segmented control) above the stats content
Switching chapter updates activeChapterProvider and triggers a full data reload for all stats widgets on the screen
Placeholder sections for StatsSummaryCards, ActivityChartWidget, and PeerMentorStatsList are rendered with correct spacing and skeleton appearance until task-012 integrates real widgets
Loading state shows skeletons for all placeholder sections simultaneously
Error state renders a full-screen retry card
Chapter switcher is accessible: each chapter option has a Semantics label 'Switch to chapter {name}'; selected state is announced
Screen scaffold uses the shared AppScaffold component — no custom AppBar
Active chapter persists across screen navigations within the session (stored in a StateProvider or equivalent, not in widget local state)

Technical Requirements

frameworks
Flutter
Riverpod
apis
Supabase — query coordinator's affiliated chapters (coordinator_chapters join table)
data models
CoordinatorProfile
Chapter
ActiveChapterState
CoordinatorStatsState
performance requirements
Chapter list loaded once on screen init and cached — no re-fetch on chapter switch
Chapter switch triggers only a provider.ref.invalidate() for the stats provider, not a full screen rebuild
security requirements
Chapter list filtered by authenticated coordinator's userId — coordinator cannot select a chapter they are not affiliated with
Active chapter validated against the fetched chapter list before being set
ui components
AppScaffold / PageHeader with chapter subtitle
ChapterSwitcherWidget (DropdownButton or SegmentedButton — conditional on chapter count)
Placeholder section containers with skeleton shimmer
TimeWindowSelector (task-002)
Full-screen ErrorCard with retry

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

Model the active chapter state as a StateProvider(null) initialised to the first chapter in the coordinator's chapter list. ChapterScopeResolver should be a separate provider that reads the coordinator profile and returns their affiliated chapters. Use a family provider for coordinator stats: coordinatorStatsProvider(ChapterScope scope) where ChapterScope bundles chapterId + timeWindow. On chapter switch, update the activeChapterProvider state — because coordinatorStatsProvider watches activeChapterProvider, Riverpod will automatically re-run the notifier's build.

Do NOT store chapterId in a GoRouter route parameter — the scope is session-state, not URL-state, since coordinators navigate chapters within the same screen. The ChapterSwitcherWidget should use DropdownButton for 3+ chapters and a two-option ToggleButtons/SegmentedButton for exactly 2 chapters.

Testing Requirements

Widget tests with ProviderScope overrides. Test cases: (1) single-chapter coordinator sees no ChapterSwitcherWidget; (2) multi-chapter coordinator sees ChapterSwitcherWidget with correct chapter options; (3) selecting a chapter updates activeChapterProvider — verify with a listener; (4) chapter switch triggers stats provider invalidation (mock provider, verify rebuild counter); (5) loading state shows skeleton placeholders; (6) error state shows retry. Use fake chapter data — no real Supabase calls.

Component
Coordinator Stats Screen
ui high
Epic Risks (4)
high impact high prob technical

fl_chart renders chart elements on a Canvas, making individual bars and data points invisible to the Flutter Semantics tree by default. Without explicit Semantics wrappers, VoiceOver and TalkBack users receive no chart information, violating the WCAG 2.2 AA requirement mandated by all three partner organizations.

Mitigation & Contingency

Mitigation: Wrap the fl_chart widget in a Semantics node with a dynamically generated textual description of the chart data (e.g., 'Bar chart: January 12, February 8, March 15 sessions'). Implement a collapsible data table alternative beneath the chart that screen readers can navigate row by row. Validate with VoiceOver on iOS and TalkBack on Android before the epic is marked complete.

Contingency: If fl_chart's Canvas rendering cannot be made accessible within the epic timeline, ship the chart hidden from the Semantics tree with ExcludeSemantics and promote the data table alternative to first-class UI so screen reader users have full access to the information. Log a tech-debt item to revisit native chart accessibility in a future sprint.

medium impact medium prob scope

Coordinators managing up to 5 chapters (NHF requirement) require the PeerMentorStatsList to display chapter affiliation labels for each row. With large chapter lists and many peer mentors, the list could become overwhelming and cause layout overflow or scrolling performance issues on lower-end Android devices.

Mitigation & Contingency

Mitigation: Implement chapter filtering as a segmented control above the list so coordinators can scope the list to one chapter at a time. Use ListView.builder (lazy rendering) rather than a Column of all rows. Profile scroll performance on a low-end Android device (Pixel 4a equivalent) with 50 peer mentors in scope during development.

Contingency: If multi-chapter display causes unacceptable performance, ship with single-chapter scope as the default view and a chapter switcher dropdown, deferring the combined cross-chapter list to a follow-up sprint.

low impact low prob technical

Summary cards and the chart widget rebuilding simultaneously on provider state change could cause a visible jank frame on slower devices, degrading perceived quality especially since this screen is intended to feel motivating and polished for gamification purposes.

Mitigation & Contingency

Mitigation: Use AnimatedSwitcher with a short fade transition (150ms) on the stats cards and chart so that data replacement feels intentional rather than jarring. Profile with Flutter DevTools on a mid-range device and ensure no frame exceeds 16ms during a time-window switch.

Contingency: If animation introduces complexity that delays delivery, ship without animation and use a loading skeleton (shimmer effect) during re-fetch instead, which is simpler and equally effective at masking the data swap.

high impact low prob security

If the role-based screen dispatch is misconfigured, a peer mentor could navigate to the coordinator stats screen and see aggregated chapter data for all peer mentors, which is a data privacy violation and a compliance risk for all three organizations.

Mitigation & Contingency

Mitigation: Implement role guard at the router level using an existing role-route-guard component so the coordinator screen route is unreachable for peer mentor roles. Add a widget test that mounts the coordinator screen with a peer mentor session token and asserts that the guard redirects to the no-access screen.

Contingency: If a bypass is found in QA, add a secondary in-screen role assertion in the coordinator screen's initState that throws an AuthorizationException and navigates to the error screen, ensuring defence in depth regardless of router configuration.