high priority low complexity frontend pending frontend specialist Tier 1

Acceptance Criteria

Positive delta renders a green upward arrow with '+X%' formatted text using design token success color
Negative delta renders a red/error-color downward arrow with '-X%' formatted text
Zero delta renders a neutral horizontal arrow with '0%' in secondary text color
When previous period value is zero and current is non-zero, display '+∞' or 'New' label instead of a percentage — no divide-by-zero crash
When both values are zero, display neutral indicator with '–'
Animated counter transition plays when widget first receives loaded data (from loading → loaded state)
Animation respects the system's `disableAnimations` accessibility setting (no animation if enabled)
Compact mode shows only arrow + percentage; expanded mode shows arrow + percentage + absolute delta value
Display mode controlled by a `compact` boolean parameter on the widget
Percentage values are rounded to one decimal place (e.g., '12.3%')

Technical Requirements

frameworks
Flutter
data models
PeriodicSummary
performance requirements
Animation must complete within 300ms to feel snappy
AnimationController disposed properly to prevent memory leaks
security requirements
No user-identifiable data in delta calculations — only aggregate metric counts
ui components
DeltaIndicator (enhanced with animation)
AnimatedCounter (number roll-up effect)
TrendArrowIcon (directional icon widget)

Execution Context

Execution Tier
Tier 1

Tier 1 - 540 tasks

Can start after Tier 0 completes

Implementation Notes

Extract delta calculation into a pure function `calculateDelta(double current, double previous) -> DeltaResult` returning a sealed class/enum with the percentage and direction. This makes it trivially testable without widget overhead. For the divide-by-zero case, check `previous == 0` before dividing; return a `DeltaResult.newValue` variant. For animations, use `AnimationController` + `Tween` with a `CurvedAnimation(curve: Curves.easeOut)`.

Check `MediaQuery.of(context).disableAnimations` and skip the animation controller if true — jump directly to end value. Use `TickerProviderStateMixin` on the parent `StatefulWidget`. Keep animation duration at 250–300ms.

Testing Requirements

Unit tests: (1) delta calculation helper returns correct percentage for all cases including zero-previous, (2) zero/zero case returns neutral indicator, (3) positive/negative/neutral states produce correct color tokens. Widget tests: (1) compact vs expanded mode renders correct child widgets, (2) accessibility setting disables animation. Golden tests for each delta state (positive, negative, neutral, new, zero/zero).

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.