high priority medium complexity frontend pending frontend specialist Tier 0

Acceptance Criteria

BufdirPreviewScreen is a StatefulWidget that renders without errors on both iOS and Android
AppBar displays a title, an export IconButton (right side), and a diff toggle IconButton (right side, next to export)
Screen body contains three vertically-stacked placeholder slots: (1) validation banner area at top, (2) scrollable ListView for report sections in the middle, (3) footer navigation bar at bottom
BufdirPreviewService is wired via a Riverpod ConsumerStatefulWidget (or ConsumerWidget) and the provider is correctly scoped
Loading state renders a centred CircularProgressIndicator that occupies the full body area
Error state renders a centred error message with a retry button that calls ref.invalidate() on the provider
Screen correctly disposes any local controllers on unmount (no memory leaks detected by Flutter DevTools)
Route accepts a required reportId or session parameter passed via GoRouter extras or path segment
No hardcoded colours or text styles — all values reference the project's design token system
Widget builds in under 16 ms on a mid-range device (verified via flutter_test pumping)

Technical Requirements

frameworks
Flutter
Riverpod
GoRouter
data models
BufdirReport
BufdirPreviewState
performance requirements
Initial build must complete within one frame budget (16 ms) on a Pixel 4 equivalent
Provider fetch must not block UI thread — all async work via AsyncNotifier or FutureProvider
ListView uses lazy-loading (ListView.builder) to avoid upfront widget tree construction
security requirements
Route must be protected by role-based access control — only peer mentors and coordinators may access
reportId must be validated as a non-empty UUID before provider fetch is initiated
No sensitive report data written to non-encrypted local storage
ui components
AppBar with custom actions
CircularProgressIndicator (loading state)
ErrorWidget with retry button
ListView.builder (section list placeholder)
BottomNavigationBar or custom footer widget

Execution Context

Execution Tier
Tier 0

Tier 0 - 440 tasks

Implementation Notes

Extend ConsumerStatefulWidget (not StatefulWidget) so ref is available in State methods without passing it around. Use AsyncValue.when() for the three UI states to keep build() clean. Define the AppBar actions as private _buildActions() method returning a List to keep the build tree readable. Use const constructors for all stateless sub-widgets to improve rebuild performance.

The footer navigation should reuse the shared bottom nav widget from the design system — do not create a new one. Place placeholder Container widgets with a fixed height (0) for the banner and section list slots so the layout contract is established before child tasks fill them in. Use GoRouter's extra parameter (typed) to pass the session/report context from the calling screen rather than fetching again.

Testing Requirements

Write widget tests using flutter_test. Test (1) loading state renders CircularProgressIndicator, (2) error state renders error message and retry button, (3) loaded state renders AppBar with both action buttons, (4) provider is called exactly once on first build, (5) route receives reportId parameter correctly. Mock BufdirPreviewService with a ProviderScope override returning AsyncLoading, AsyncError, and AsyncData variants. Aim for 100% branch coverage of the loading/error/data conditional.

Run flutter analyze with zero warnings before merging.

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.