Wire ExportScopeSelector into the export screen state
epic-bufdir-report-export-orchestration-task-009 — Connect the ExportScopeSelector widget to the export screen's Riverpod provider so that scope selection updates are reflected in the BufdirExportRequest that BufdirExportService will receive. Ensure the export action button is disabled until a valid scope and period are both selected. Propagate scope-access errors to an inline error banner using the design token colour system.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 3 - 413 tasks
Can start after Tier 2 completes
Implementation Notes
Model the export screen state as a Riverpod StateNotifierProvider or AsyncNotifierProvider with a BufdirExportScreenState freezed class containing: selectedScope, selectedPeriod, exportRequest (derived), scopeError. Use a computed getter `bool get canExport => selectedScope != null && selectedPeriod != null` on the state class to drive button enabled state. In the widget, use `ref.watch(exportScreenProvider.select((s) => s.canExport))` for fine-grained rebuilds rather than watching the whole state. For the error banner, create a reusable InlineErrorBanner widget that accepts a String?
message and uses AppTheme.of(context).errorColor from design tokens — do not hardcode colours. Ensure ExportScopeSelector passes scope selection up via a callback rather than managing state internally to keep it a pure presentational widget.
Testing Requirements
Widget tests with flutter_test and ProviderScope override: (1) renders only permitted scopes for a coordinator role, (2) renders all org scopes for org admin role, (3) export button disabled when scope is null, (4) export button disabled when period is null, (5) export button enabled when both scope and period are non-null, (6) PermissionDenied error surfaced as InlineErrorBanner with correct error token colour, (7) selecting new scope clears existing error banner, (8) provider state contains correct scope after selection. Accessibility: assert semanticsLabel is present on error banner.
The scope selector must accurately reflect each coordinator's access rights within the org hierarchy. If a coordinator can select a scope broader than their authorised access, the edge function's RLS enforcement must catch the attempt — but a permissive RLS policy or a bug in the scope resolver could allow unauthorised data to be exported.
Mitigation & Contingency
Mitigation: Implement permission enforcement at two independent layers: (1) the scope selector only renders options permitted by the user's role record, and (2) the edge function re-validates the requested scope against the user's JWT claims before executing any queries. Write integration tests that attempt to invoke the edge function with a scope beyond the user's permissions and assert rejection.
Contingency: If a permission bypass is discovered post-launch, immediately disable the export feature via the org-level feature flag while the fix is deployed. Review all audit records for exports that may have included out-of-scope data and notify affected organisations.
The export workflow has 7+ discrete states (idle, scope selected, period selected, preview loading, preview ready, confirming, exporting, complete, failed) and several conditional transitions. An incomplete BLoC state machine could allow duplicate submissions, stale preview data to be confirmed, or error states to be unrecoverable without a restart.
Mitigation & Contingency
Mitigation: Model the state machine explicitly as a sealed class hierarchy before coding. Review the state diagram against all user story acceptance criteria. Write bloc unit tests for every valid and invalid state transition, including the happy path and all documented error states.
Contingency: If the BLoC grows too complex to test reliably, decompose it into two cooperating blocs: one for configuration (scope + period selection) and one for execution (preview + confirm + export), linked by a coordinator object.