high priority low complexity frontend pending frontend specialist Tier 4

Acceptance Criteria

ExportReadinessBanner is positioned at the top of BufdirExportScreen's Scaffold body, visible across all three phases
Banner displays red status when scope is missing OR period is missing
Banner displays amber status when scope and period are valid but the preview has unmapped activity warnings (non-blocking)
Banner displays amber status when scope and period are valid but the preview has not yet been fetched
Banner displays green status when scope and period are valid, preview loaded successfully, and there are no unmapped warnings
Banner displays red status when the preview loaded with blocking errors, regardless of other conditions
Status icons and text meet WCAG 2.2 AA contrast requirements in both light and dark themes (use design token colours, not raw hex)
Status icon is never the sole indicator — each status also carries a text label (e.g. 'Ready to export', 'Incomplete selection', 'Warnings found')
A Semantics widget with liveRegion: true wraps the banner text so screen readers announce changes automatically
Banner updates synchronously whenever scope, period, preview state, or warning count changes — no manual refresh

Technical Requirements

frameworks
Flutter
BLoC (flutter_bloc)
Riverpod
data models
ExportReadinessStatus (enum: ready, incomplete, warnings, blocked)
ExportScreenState
ExportPreviewState
performance requirements
Banner re-render must be scoped to avoid rebuilding the entire screen — use BlocSelector or select() on providers
security requirements
Banner must not display raw internal error messages — map all error states to user-safe strings
ui components
ExportReadinessBanner (stateless widget)
Status icon (Icons.check_circle / warning_amber / error from design token palette)
Semantics live region wrapper

Execution Context

Execution Tier
Tier 4

Tier 4 - 323 tasks

Can start after Tier 3 completes

Implementation Notes

Implement ExportReadinessBanner as a pure function of ExportReadinessStatus — compute the status in a dedicated pure function (computeReadiness(scope, period, previewState, warningCount)) that is unit-testable independently of Flutter. Observe state via a MultiRepositoryProvider or a combined Riverpod provider that merges exportScopeProvider, exportPeriodProvider, and ExportPreviewCubit state. Avoid direct BlocBuilder nesting; prefer BlocSelector targeting only the relevant state fields. Use SemanticsService.announce() as a fallback for older Flutter versions if the liveRegion approach does not fire reliably during CI tests.

Testing Requirements

Widget tests covering all four status combinations: (1) red when scope null, (2) red when period null, (3) red when preview has blocking error, (4) amber when preview not yet fetched, (5) amber when unmapped warnings present, (6) green when all conditions satisfied. Semantics test: verify liveRegion is true and label text matches expected string for each status. Accessibility test: run flutter_test semanticsEnabled tests and confirm no contrast violations with design token colours.

Component
Bufdir Export Screen
ui medium
Epic Risks (2)
medium impact medium prob technical

The preview panel requires a round-trip to the edge function to compute aggregated counts. If this call takes 5–15 seconds for large scopes, users may assume the app has frozen and navigate away, potentially triggering duplicate preview requests or leaving the export in an undefined state.

Mitigation & Contingency

Mitigation: Show an immediate skeleton loading state on the preview panel as soon as the period and scope are confirmed, with named stage labels (e.g. 'Querying activities…', 'Computing totals…') streamed from the edge function's progress events. Set a clear user-visible timeout with a retry option. Pre-warm the edge function with a lightweight ping when the scope selector is opened.

Contingency: If preview latency consistently exceeds 10 seconds for large scopes, cache the preview payload in local BLoC state and allow the coordinator to proceed to confirmation without re-fetching if scope and period have not changed since the last preview.

high impact medium prob scope

The export preview panel contains dynamic content (warning badges, loading skeletons, aggregated counts) that must be announced correctly by VoiceOver and TalkBack. Incorrect semantics annotations could make the preview unreadable for blind coordinators, violating the project's WCAG 2.2 AA accessibility mandate.

Mitigation & Contingency

Mitigation: Implement semantic annotations using Flutter's Semantics widget with explicit labels for all dynamic content. Use live region announcements for loading state transitions. Schedule a dedicated accessibility review session with a screen reader user (Blindeforbundet has relevant expertise) before marking the epic complete.

Contingency: If the preview panel cannot be made fully screen-reader-accessible in time for launch, ship a simplified text-only summary mode activated by a toggle at the top of the preview panel, which renders all data as a single readable paragraph with no interactive badges.