critical priority medium complexity frontend pending frontend specialist Tier 3

Acceptance Criteria

CoordinatorTeamSummaryView is a BlocBuilder/BlocConsumer widget consuming CoordinatorTeamSummaryBloc
Loading state renders a shimmer or CircularProgressIndicator centered on the screen
Error state renders a descriptive error message with a retry button that dispatches LoadTeamSummary
Loaded state renders a scrollable ListView of MentorSummaryRow widgets
Each MentorSummaryRow displays: mentor full name (prominent), sessions completed count, hours logged (formatted as '4h 30m'), and — when isOutlier is true — an outlier badge with the outlier_reason label
Outlier badges use distinct design token colors (e.g., 'At Risk' in warning amber, 'Overdue' in error red) and are never plain black text
A period selector widget (dropdown or segmented control) is rendered at the top of the screen and dispatches LoadTeamSummary with the selected PeriodFilter on change
A team aggregate stat bar below the period selector shows totals: total sessions, total hours, number of outliers for the selected period
Tapping any mentor row navigates to the mentor's detail profile screen passing mentor_id as a route parameter
Pull-to-refresh (RefreshIndicator) dispatches RefreshTeamSummary event
All spacing, typography, and colors use design tokens exclusively — no hardcoded hex values or pixel literals
Screen renders correctly on screen widths from 320px to 428px without horizontal overflow
Empty state (zero mentors) renders a descriptive message, not a blank screen

Technical Requirements

frameworks
Flutter
BLoC (flutter_bloc)
Dart
apis
No direct API calls — all data sourced from CoordinatorTeamSummaryBloc stream
data models
MentorSummaryModel
PeriodFilter
TeamAggregateStats
performance requirements
ListView must use ListView.builder with itemCount for lazy rendering — never a Column with mapped children
Each MentorSummaryRow must be a const constructor widget where possible to minimize rebuilds
BlocBuilder must use buildWhen to avoid re-rendering on irrelevant state changes
security requirements
Mentor PII (name, stats) must not be persisted to device logs or crash reporting without explicit consent
ui components
MentorSummaryRow — list tile with name, stats, and optional outlier badge
OutlierBadge — reusable chip/tag widget with design token color variants
TeamAggregateStatBar — horizontal row of 3 stat tiles
PeriodSelectorWidget — dropdown or SegmentedButton for period selection
EmptyMentorListWidget — illustrated empty state

Execution Context

Execution Tier
Tier 3

Tier 3 - 413 tasks

Can start after Tier 2 completes

Implementation Notes

Structure the screen as CoordinatorTeamSummaryView (scaffold + BlocBuilder) containing a Column with: PeriodSelectorWidget, TeamAggregateStatBar, and an Expanded ListView.builder. Extract MentorSummaryRow as a separate stateless widget file to keep the main file under 200 lines. OutlierBadge should accept a BadgeSeverity enum (warning, error, info) mapped from the outlier_reason string in the BLoC — this mapping belongs in a presentation mapper, not the BLoC. For navigation, use GoRouter with a named route; pass only the mentor_id, not the full model, to avoid stale data issues on the detail screen.

Design token usage: reference AppColors.warning, AppColors.error, AppTypography.bodyMedium, AppSpacing.md etc. — never Theme.of(context).colorScheme directly in feature widgets.

Testing Requirements

Widget tests using flutter_test. Provide a FakeCoordinatorTeamSummaryBloc (or use mocktail) to inject each state variant. Test: loading state shows progress indicator; error state shows retry button; loaded state renders correct number of rows; mentor row shows outlier badge only when isOutlier is true; tapping a row triggers the expected navigation route (use a NavigatorObserver mock); pull-to-refresh dispatches RefreshTeamSummary; period selector dispatches LoadTeamSummary with correct filter; aggregate stat bar shows correct totals. Golden tests for loaded state (light + dark, 375px and 390px widths).

Component
Coordinator Team Summary View
ui medium
Epic Risks (3)
medium impact medium prob technical

If the cached summary is from a prior period (e.g., previous quarter's card is still cached), the digest card could appear on the home screen with outdated numbers after a new period begins, confusing users who have already seen that data.

Mitigation & Contingency

Mitigation: In the SummaryCacheRepository, store the period_start and period_end alongside cached data. In the PeriodicSummaryCard BLoC, compare the cached record's period against the current date using PeriodCalculatorService. Only render the card if the cached summary belongs to the active period.

Contingency: If stale cards appear in production, push a hotfix that adds the period validity check to the BLoC and clears all cached summaries older than the current period boundary via a forced cache flush on next app launch.

medium impact medium prob technical

Using colour alone to distinguish underactive from overloaded mentors in the coordinator view would fail WCAG 1.4.1 (use of colour). This is especially critical for organisations serving users with colour vision deficiency.

Mitigation & Contingency

Mitigation: Always pair colour indicators with a text label or icon (e.g., a downward arrow + 'Underactive' text alongside the amber colour). Use the contrast-safe-color-palette design tokens throughout. Run the contrast-ratio-validator on all new colour combinations in CI.

Contingency: If an accessibility audit flags colour-only indicators post-launch, introduce icon-based indicators as a patch release and update the design token definitions to enforce the paired-indicator pattern going forward.

low impact medium prob integration

Inserting a new card into the role-based home screen requires changes to shared home screen widget composition, which may conflict with parallel feature branches also modifying the home screen layout, causing merge conflicts and integration delays.

Mitigation & Contingency

Mitigation: Implement the PeriodicSummaryCard as a fully self-contained widget that the home screen conditionally renders based on a BLoC state flag. Minimise changes to the home screen itself to a single conditional insertion point, reducing the surface area for merge conflicts.

Contingency: If integration conflicts block the PR, isolate the card behind the organisation-scoped feature flag so it can be toggled independently and merged without affecting other home screen changes.