high priority medium complexity frontend pending frontend specialist Tier 2

Acceptance Criteria

Export button is rendered in the AppBar and is tappable with a minimum touch target of 48×48 dp
Tapping Export with no active validation warnings navigates directly to the export screen, passing current session state via GoRouter
Tapping Export with active warnings opens an AlertDialog before any navigation occurs
AlertDialog title is 'Export with warnings?' (or locale-equivalent)
AlertDialog body lists each active warning as a bullet point — minimum one warning visible without scrolling, additional warnings scrollable within the dialog
AlertDialog has two actions: 'Cancel' (dismisses dialog, returns focus to Export button) and 'Export anyway' (proceeds to export screen)
Focus is placed on the AlertDialog's first focusable element (Cancel button) immediately on open — verified via Semantics traversal
On Cancel, focus returns to the Export button in the AppBar
On 'Export anyway', current session state from BufdirPreviewService is passed to export screen navigation
Dialog is not shown a second time if the user taps Export again within the same session without new warnings appearing
All dialog text strings are externalised (no hardcoded strings in widget code)

Technical Requirements

frameworks
Flutter
Riverpod
GoRouter
data models
BufdirFieldIssue
BufdirPreviewState
BufdirExportSession
performance requirements
Dialog must open within one frame after button tap — no async operation before showDialog call
Validation check is synchronous read from already-loaded provider state — no additional API call triggered
security requirements
Session state passed to export screen must be a serialisable value object — no passing raw database handles or mutable singletons
Export action must re-validate role permissions before navigating — guard against direct deep-link bypasses
ui components
IconButton (Export, in AppBar)
AlertDialog with scrollable content area
FocusNode management for WCAG focus control
ListView or SingleChildScrollView inside dialog body

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

Extract the validation-check-and-navigate logic into a private _handleExportTap(BuildContext context, WidgetRef ref) method to keep the AppBar action widget lean. Use showDialog() and await the result — true means 'Export anyway', null/false means dismissed. Do not use Navigator.of(context) directly — use context.push() from GoRouter to stay within the routing paradigm. Create a FocusNode for the Cancel button and pass it to the AlertDialog's actions list; call FocusScope.of(context).requestFocus(cancelFocusNode) inside an addPostFrameCallback to meet WCAG 2.2 AA focus management.

Wrap dialog body content in a ConstrainedBox with maxHeight to prevent the dialog from growing taller than 60% of screen height on devices with many warnings. All warning strings in the dialog must be the same source as displayed in the validation banner — derive them from BufdirFieldIssue.displayMessage, not re-fetched separately.

Testing Requirements

Write widget tests for: (1) tapping Export with empty warnings list navigates without showing dialog, (2) tapping Export with warnings shows AlertDialog with correct warning count, (3) tapping Cancel dismisses dialog and does not navigate, (4) tapping 'Export anyway' navigates to export screen with correct session argument, (5) Semantics tree shows dialog as the focused container on open. Use GoRouter's redirect override in tests to capture navigation events. Use tester.tap + tester.pumpAndSettle. Assert no navigation occurred before dialog confirmation when warnings are present.

Verify FocusNode is on Cancel button via FocusManager.instance.primaryFocus.

Component
Bufdir Report Preview Screen
ui high
Epic Risks (3)
medium impact medium prob integration

The preview screen must pass period, scope, and aggregation session state to the Bufdir Report Export screen via navigation arguments. If the export screen's navigation argument schema is not yet finalized when this epic begins, the handoff will require rework — potentially after TestFlight is already in use by coordinators.

Mitigation & Contingency

Mitigation: Define the shared BufdirExportNavigationArgs Dart class jointly with the Bufdir Report Export feature team before this epic starts. Store it in a shared models package both features depend on. Treat the class as an API contract with a minor-version bump policy.

Contingency: If the export screen's argument schema changes after the preview screen is implemented, the BufdirPreviewService session state model can be adapted with a compatibility shim. The preview screen itself requires only a one-line navigation call change.

medium impact low prob technical

The period diff view loads prior-period data on demand and renders it inline with the current report. On a large report (many sections, many fields) combined with slow Supabase connectivity, the diff overlay could block the UI or produce a janky re-render that degrades the coordinator experience during the pre-submission review.

Mitigation & Contingency

Mitigation: Load prior-period data in a background Riverpod FutureProvider that starts prefetching when the preview screen mounts (not when the user taps the diff toggle). Show a shimmer placeholder on each field row's prior-period column while loading. Cache prior-period data in BufdirPreviewRepository using the same local cache as current-period data.

Contingency: If diff view performance is unacceptable on TestFlight devices, disable the toggle for the initial TestFlight release and ship the diff view in the following sprint after profiling the Supabase query plan and adding an appropriate Postgres index on the prior-period data table.

high impact medium prob scope

The full preview screen will be reviewed by coordinators on TestFlight who will cross-reference it against their physical Bufdir reporting forms. Any section ordering difference or label mismatch discovered during UAT will require a fix before the feature can be signed off, potentially delaying the entire Bufdir reporting pipeline.

Mitigation & Contingency

Mitigation: Conduct a pre-TestFlight alignment review with at least one coordinator from NHF and one from HLF using a static screenshot of the preview screen layout. Obtain written sign-off on section order and field labels before distributing to the full test group of 5-8 people.

Contingency: If label mismatches are found during TestFlight UAT, update BufdirReportStructureMapper constants and rebuild. Since the mapper is a pure Dart class with no persisted state, corrections are deployed in the next TestFlight build with no database migration required.