high priority medium complexity infrastructure pending frontend specialist Tier 1

Acceptance Criteria

FlChartAdapter exposes two factory methods: buildBarChartData(List<BarChartSeriesViewModel>, BuildContext) and buildDonutChartData(List<DonutSegmentViewModel>, BuildContext)
buildBarChartData returns a fully configured BarChartData including BarGroups, BarTouch, FlGridData, FlBorderData, FlTitlesData with formatted axis labels
buildDonutChartData returns a PieChartData with PieSections, PieTouch, and centre hole radius consistent with design token spacing
All Color values in the returned chart data objects are sourced from DesignTokenTheme — zero hardcoded hex or Color(0xABCDEF) literals inside FlChartAdapter
All TextStyle instances use design token font sizes and weights — no hardcoded font size numbers
Tooltip renderers format values as integers for activity counts and as 'Xh Ym' for duration values
Animation duration is sourced from a design token constant (e.g., AppDurations.chartAnimation) defaulting to 350ms
Adapter handles empty data gracefully — empty BarChartSeriesViewModel list produces a valid BarChartData with no bars and a visible empty-state axis
FlChartAdapter is a pure utility class with static methods or a const constructor — it holds no state
Charts rendered using FlChartAdapter pass WCAG 2.2 AA colour contrast ratio (4.5:1) between bar fill and background for all three organisation themes
Widget tests render the produced BarChartData and PieChartData inside a MaterialApp and assert no exceptions are thrown

Technical Requirements

frameworks
Flutter
Dart
fl_chart
data models
BarChartSeriesViewModel
DonutSegmentViewModel
DesignTokenTheme
performance requirements
buildBarChartData and buildDonutChartData must complete in under 5ms for up to 12 data series
Chart widgets must render at 60fps — no expensive computation inside build callbacks
security requirements
Tooltip renderers must not display raw database IDs or internal field names — only human-readable labels from ViewModels
ui components
BarChart (fl_chart)
PieChart (fl_chart)
FlTitlesData axis label widgets
BarTouchData tooltip widget
PieTouchData tooltip widget

Execution Context

Execution Tier
Tier 1

Tier 1 - 540 tasks

Can start after Tier 0 completes

Implementation Notes

fl_chart's BarChartData is immutable and constructed via named parameters — build it entirely inside the factory method without storing intermediate mutable state. Access design tokens via `Theme.of(context).extension()` or the equivalent pattern used elsewhere in the app — do not use a global singleton. For multi-org theme support, the adapter must accept a `BuildContext` (to resolve the current theme) rather than accepting raw Color parameters — this keeps theme switching automatic. For the donut chart centre hole, use `PieChartData(sectionsSpace: 2, centerSpaceRadius: 40)` where `40` should reference a token like `AppSizing.chartCentreRadius`.

For WCAG validation, verify each organisation's accent colour passes contrast against `AppColors.chartBackground` before committing — use a helper: `contrastRatio(Color fg, Color bg)` based on WCAG 2.1 relative luminance formula. Avoid defining chart colours inside FlChartAdapter — delegate colour selection to the calling ViewModel layer so the adapter remains a pure formatting utility.

Testing Requirements

Widget tests with flutter_test: (1) Render buildBarChartData output inside BarChart widget with a known list of BarChartSeriesViewModel — assert widget builds without error and the correct number of bar groups is present. (2) Render buildDonutChartData output inside PieChart — assert the correct number of PieSections with non-zero percentages. (3) Pass empty BarChartSeriesViewModel list — assert no exception and a valid empty chart renders. (4) For each of the three organisation themes (NHF, HLF, Blindeforbundet), override the DesignTokenTheme and assert that colours in the returned chart data change accordingly.

(5) Assert WCAG contrast ratio for the primary bar fill colour against the chart background using a helper function that computes relative luminance. Golden file tests are optional but recommended for tooltip renderer output.

Component
fl_chart Adapter
infrastructure medium
Epic Risks (3)
medium impact medium prob technical

fl_chart's default colour palette may not meet WCAG 2.2 AA contrast requirements when rendered on the app's dark or light backgrounds. If segment colours are insufficient, the donut chart will fail accessibility audits, which is a compliance blocker for all three organisations.

Mitigation & Contingency

Mitigation: Define all chart colours in the design token system with pre-validated contrast ratios. Run the contrast-ratio-validator against every chart colour during the adapter's unit tests. Use the contrast-safe-color-palette as the source palette.

Contingency: If a colour fails validation, replace with the nearest compliant token. If activity types exceed the available token set, implement a deterministic hashing algorithm that maps activity type IDs to compliant colours.

medium impact medium prob technical

StatsBloc subscribing to the activity registration stream creates a long-lived subscription. If the subscription is not disposed correctly when the dashboard is closed, it will cause a stream leak and potentially trigger re-fetches on a disposed BLoC, resulting in uncaught errors in production.

Mitigation & Contingency

Mitigation: Implement subscription disposal in the BLoC's close() override. Write a widget test that navigates away from the dashboard and asserts no BLoC events are emitted after disposal.

Contingency: If leaks are detected in QA, add a mounted check guard before emitting states from async callbacks, and audit all other BLoC stream subscriptions in the codebase for the same pattern.

low impact low prob scope

PersonalStatsService's Phase 4 gamification data structure is designed against an assumed future schema. If the Phase 4 Spotify Wrapped feature defines a different data contract when it is developed, the structure built now will require a breaking change and migration.

Mitigation & Contingency

Mitigation: Document the contribution data structure with explicit field semantics and versioning comments. Keep the Phase 4 fields as optional/nullable so they do not break existing consumers if the schema evolves.

Contingency: If the Phase 4 schema diverges significantly, the personal stats data can be re-mapped in a thin adapter layer without changing PersonalStatsService's core implementation.