Build Export History List Data Layer
epic-bufdir-reporting-export-ui-task-009 — Implement the Riverpod provider and repository interface for the export history list. The provider must query the Supabase export_audit_log table filtered by the current user's organisation scope, return a paginated stream of ExportHistoryEntry models (id, period, format, status, created_at, file_url), and expose loading/error states. Implement RLS-safe query construction.
Acceptance Criteria
Technical Requirements
Implementation Notes
Use Supabase's `.from('bufdir_export_audit_log').select().eq('organization_id', orgId).order('created_at', ascending: false).range(from, to)` for pagination. Extract orgId from `Supabase.instance.client.auth.currentSession?.user.userMetadata?['organization_id']` — validate it is non-null before querying and throw an AuthenticationException if absent. Model ExportStatus as a Dart enum with a fromString factory that defaults to ExportStatus.pending for unknown values to prevent runtime crashes from new server-side statuses. Keep the repository thin — no business logic, only data fetching and mapping.
The Riverpod notifier handles pagination state (currentPage, allItems, hasMore). Use AsyncNotifier rather than StateNotifier for cleaner async loading patterns.
Testing Requirements
Write unit tests with flutter_test and mockito/mocktail covering: (1) fetchPage returns correct ExportHistoryEntry list from mocked Supabase response, (2) fetchPage with empty response sets hasMore to false, (3) loadNextPage appends items correctly to existing list, (4) Supabase exception maps to ExportHistoryException and provider enters AsyncError, (5) organisation_id is correctly extracted from auth session and appended to query. Test ExportHistoryNotifier state transitions with ProviderContainer. Do not hit a real Supabase instance in unit tests.
For large exports that run for 10–30 seconds, a static loading spinner will feel broken to users on slow mobile connections. If the UI cannot display meaningful progress during the export pipeline, coordinators may abandon the flow or trigger duplicate exports by pressing the button multiple times.
Mitigation & Contingency
Mitigation: Implement streaming progress events from the orchestrator BLoC through named pipeline stages (querying, mapping, generating, uploading). Display each stage label with a progress indicator on the trigger screen. Disable the generate button immediately on first tap to prevent duplicates.
Contingency: If streaming pipeline progress is not feasible in the first release, implement a deterministic stage-based progress animation (10% querying, 50% generating, 90% uploading) that gives users feedback without requiring real server events.
Custom date range pickers are among the most common accessibility failures in mobile apps. Blindeforbundet users rely on VoiceOver, and NHF users include people with cognitive impairments. A non-accessible period picker could make the entire export workflow unusable for a significant portion of the intended user base.
Mitigation & Contingency
Mitigation: Build the period picker using Flutter's native date picker semantics as the foundation, with preset shortcuts as primary navigation (reducing the need to interact with the custom range picker at all). Test with VoiceOver on iOS and TalkBack on Android before UI epic sign-off. Engage Blindeforbundet's test contact for accessibility validation.
Contingency: If the custom date range picker cannot be made fully accessible before release, ship only the preset period shortcuts (covering the majority of use cases) and add the custom range picker in a follow-up sprint after dedicated accessibility remediation.