high priority low complexity frontend pending frontend specialist Tier 5

Acceptance Criteria

PeriodComparisonWidget is embedded in the PeriodicSummaryCard widget, receiving currentPeriod and priorPeriod data objects from the parent BLoC state
PeriodComparisonWidget is embedded in the coordinator team mentor detail view, receiving the selected mentor's currentPeriod and priorPeriod data from the CoordinatorTeamSummaryBloc or mentor detail BLoC
Widget correctly renders when priorPeriod data is null or all-zero (first period scenario) — shows 'No prior period data' or equivalent placeholder without throwing exceptions
Widget renders correctly with offline-cached data: when Supabase is unreachable, cached priorPeriod and currentPeriod values are shown with an 'Offline — cached data' indicator
No RenderFlex overflow errors occur on screen widths of 320px, 375px, or 390px in either portrait or landscape orientation
Overflow check: widget uses Flexible/Expanded appropriately within Row children to prevent horizontal overflow
Delta indicators (arrows, percentage changes) render correctly when current > prior, current < prior, and current == prior
Widget does not make independent API calls — all data is passed via constructor parameters from the parent
Widget is covered by at least one golden test at 320px width capturing the overflow-safe layout

Technical Requirements

frameworks
Flutter
BLoC (flutter_bloc)
Dart
apis
No direct API calls — data passed from parent BLoC via constructor
data models
PeriodSummaryData (currentPeriod, priorPeriod)
PeriodComparisonViewModel
performance requirements
Widget must be stateless (const constructor) — no internal state or rebuilds
All layout must use Flexible or Expanded for Row/Column children to prevent overflow on small screens
ui components
PeriodComparisonWidget — reusable stateless widget
DeltaIndicator — up/down/neutral arrow with percentage label
OfflineCacheIndicator — subtle banner or icon showing cached data state

Execution Context

Execution Tier
Tier 5

Tier 5 - 253 tasks

Can start after Tier 4 completes

Implementation Notes

PeriodComparisonWidget should be a pure stateless widget with no BLoC dependency — it receives PeriodSummaryData via constructor. This makes it reusable across any parent. Guard against division by zero in delta calculations: if priorPeriod.hours == 0 and currentPeriod.hours > 0, show '+∞%' or 'New' rather than crashing. If both are zero, show '—'.

For layout safety on 320px screens, use Flexible(child: Text(..., overflow: TextOverflow.ellipsis)) inside Row widgets rather than fixed-width containers. The offline indicator should be driven by an optional isOffline: bool parameter defaulting to false — this keeps the widget decoupled from connectivity detection logic.

Testing Requirements

Widget tests: render with valid currentPeriod + priorPeriod (verify delta indicators); render with priorPeriod = null (verify no crash, placeholder shown); render with all-zero priorPeriod (verify delta is 0% or 'N/A', not NaN/infinity); render with offline cached data flag (verify offline indicator visible); verify no overflow at 320px width using tester.binding.window.physicalSizeTestValue. Golden tests: 320px and 390px widths, light and dark themes, for both the PeriodicSummaryCard embed and the mentor detail embed.

Component
Period Comparison Widget
ui low
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.