high priority medium complexity frontend pending frontend specialist Tier 1

Acceptance Criteria

Widget renders all four pipeline stages (fetching, categorising, deduplicating, distributing) as a horizontal or vertical step sequence
Each stage shows: a stage-specific icon, a localised label string, and a visual state indicator (pending/active/completed)
Active stage is visually distinct from pending and completed stages using design token colours
Completed stages show a checkmark or filled indicator using the design token success colour
Pending stages use the design token muted/disabled colour
Colour contrast ratio between stage label text and background meets WCAG 2.2 AA minimum (4.5:1 for normal text)
Widget transitions between stages with an animation of 300ms or less — no jarring instant jumps
Widget rebuilds only when the BLoC stage changes — no unnecessary full redraws
Widget renders correctly in AggregationInitial state (all stages pending)
Widget renders correctly in AggregationComplete state (all stages shown as completed)
Widget uses only design token values for colours, spacing, and typography — no hardcoded hex values or pixel values
Widget is accessible: each stage has a Semantics label describing its name and current state (e.g., 'Fetching data, completed')
Widget passes flutter_test golden test for each of the four active-stage permutations

Technical Requirements

frameworks
flutter
bloc
flutter_bloc
data models
AggregationState
AggregationStage
AggregationInProgress
performance requirements
Stage transition animation must complete in 300ms or less
Widget must not trigger a full subtree rebuild on unrelated BLoC state emissions — use BlocSelector to filter on stage only
Widget frame rendering must stay above 60fps during animations
security requirements
Widget must not display any raw error information — error rendering is handled by task-003
ui components
AggregationProgressIndicator (stateless widget, BLoC-connected)
_StageStep (private stateless widget for individual stage rendering)
_StageConnector (private widget for the line/arrow between stages)

Execution Context

Execution Tier
Tier 1

Tier 1 - 540 tasks

Can start after Tier 0 completes

Implementation Notes

Use BlocSelector to extract only the current stage, preventing full rebuilds on AggregationWarning or AggregationFailed emissions. Implement the stage sequence as a List in order — derive completed/active/pending from the index of the current stage relative to each item in the list. Use AnimatedContainer or AnimatedSwitcher for the active state transition to achieve smooth 300ms animations. Access design tokens via the project's existing token system (AppColors, AppSpacing, AppTypography) — check constants.ts or the existing design token file before choosing colour variables.

Wrap each _StageStep in a Semantics widget with a dynamically constructed label: '${stage.label}, ${stateDescription}' where stateDescription is 'pending', 'in progress', or 'completed'. For icons, use Flutter's built-in Icons constants (Icons.download_rounded for fetching, Icons.category_outlined for categorising, Icons.filter_alt_outlined for deduplicating, Icons.send_rounded for distributing) unless the project has a custom icon set.

Testing Requirements

Unit and widget tests using flutter_test. Test cases: (1) widget renders all four stages when BLoC is in AggregationInitial; (2) for each AggregationStage value, the corresponding stage node shows active styling and all prior stages show completed styling; (3) BlocSelector is used — emit an unrelated state and verify the widget does not rebuild unnecessarily using a render count tracker; (4) golden tests for each active-stage permutation saved under test/goldens/aggregation_progress/; (5) Semantics tree test verifying each stage has a descriptive label. Use pumpAndSettle() after emitting a new stage to ensure animations complete before asserting visual state.

Epic Risks (2)
medium impact high prob scope

For NHF with 1,400 local chapters, rendering a geographic breakdown as a flat list in the AggregationSummaryWidget would produce an unscrollable wall of data that is unusable on a mobile screen. Coordinators need to verify geographic completeness before export, but the raw chapter list is too long to review.

Mitigation & Contingency

Mitigation: Design the geographic distribution section as a collapsible two-level hierarchy: regions are shown expanded by default with their aggregate count, individual chapters are collapsed under each region and expandable on tap. Show only non-zero regions by default with a 'show empty regions' toggle.

Contingency: If the hierarchical display is too complex to implement before the submission deadline, fall back to a region-only summary view with a total count of active chapters per region and a note that chapter-level detail is available in the full export file.

medium impact medium prob technical

The aggregation BLoC must handle a multi-stage async pipeline with partial success states, warning accumulation across stages, and retry logic for individual failed stages. If the state model is too simplistic (e.g., loading/success/error), warning states and partial results will be lost on retry, confusing coordinators who see warnings disappear and reappear.

Mitigation & Contingency

Mitigation: Model the BLoC state as a rich sealed class hierarchy: AggregationIdle, AggregationRunning(stage, completedStages, accumulatedWarnings), AggregationComplete(result, warnings), AggregationFailed(failedStage, accumulatedWarnings, error). Accumulated warnings persist across retry attempts so coordinators see the full warning history.

Contingency: If state management complexity causes repeated bugs near the deadline, simplify to a single AggregationResult value object that captures success, warnings, and error as nullable fields, and drive both UI components from that single object rather than a live BLoC stream.