Implement role-based access guard for export action
epic-accounting-system-export-ui-task-007 — Implement a RoleGuard wrapper inside AccountingExportScreen that reads the current user role from the role state provider and conditionally renders the export date picker and trigger button only when the role is coordinator or org_admin. Peer mentors see a read-only history panel without any export action. The guard must re-evaluate on role switch (supporting multi-role users). Add a Semantics widget with an excludeSemantics flag on hidden elements so screen readers are not confused by off-screen controls.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 4 - 323 tasks
Can start after Tier 3 completes
Implementation Notes
Implement RoleGuard as a generic reusable widget: RoleGuard({ required List
Do NOT use Visibility(visible: false) or Opacity(opacity: 0) to hide the export action — this still keeps the widget in the semantics tree. The roleStateProvider should be a StateNotifierProvider or NotifierProvider that listens to Supabase Auth state changes and updates the active role whenever the session changes, supporting the multi-role switch feature described in the app architecture.
Testing Requirements
Unit tests: none required (pure widget logic). Widget tests: pump RoleGuard with roleStateProvider overridden to each role value and verify: (1) coordinator role renders authorisedBuilder; (2) org_admin role renders authorisedBuilder; (3) peer_mentor role renders unauthorisedBuilder; (4) null/unresolved role renders loadingBuilder. Semantics test: verify that when unauthorisedBuilder is shown, no semantic nodes from authorisedBuilder exist in the semantics tree (use flutter_test SemanticsHandle). Role switch test: pump with peer_mentor, then update provider to coordinator, pump again, verify authorisedBuilder is now rendered.
Test the guard with RoleGuard used inside AccountingExportScreen by pumping the full screen with different role overrides. Target 95%+ widget test coverage.
Export operations may take several seconds, and the UI must handle all intermediate states (loading, partial success, failure, duplicate warning) without leaving the coordinator on a blank or unresponsive screen. Missing state handling causes confusion and potentially double-submissions.
Mitigation & Contingency
Mitigation: Design the BLoC state machine with explicit states for each transition before writing any widget code: ExportIdle, ExportDuplicateWarning, ExportInProgress, ExportSuccess, ExportPartialSuccess, ExportFailed. Each state maps to a distinct UI. Widget tests cover all states.
Contingency: If a loading state is missed in production, surface a generic error state with a retry action rather than leaving the UI stuck. Add a timeout on the Edge Function call (default 30 seconds) that transitions to ExportFailed with a user-readable message.
The custom Export Date Range Picker may not be fully navigable with VoiceOver if the underlying Flutter date widgets do not expose the correct semantic tree. This is a critical accessibility failure for Blindeforbundet users who rely on screen readers.
Mitigation & Contingency
Mitigation: Use Flutter's built-in DateRangePicker as the base and wrap with explicit Semantics nodes for start and end labels. Test with VoiceOver on a physical iOS device as part of the definition of done for this component. Reference the existing AccessibilityTestHarness pattern used elsewhere in the app.
Contingency: If the custom picker fails accessibility audit, replace it with two independent DatePicker fields (start and end) using Flutter's standard accessible date input, which has broader VoiceOver support than range variants.