Build Export History Panel UI component
epic-accounting-system-export-foundation-task-012 — Implement the ExportHistoryPanel Flutter widget that displays a scrollable list of past export runs for the current org. Each list item shows: export date, date range covered, target system badge, status (pending/completed/failed), record count, and a download button for the generated file. Consume ExportRunRepository for data. Apply empty state, loading skeleton, and error state. Make download button invoke a signed URL fetch and open the native file handler via url_launcher.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 2 - 518 tasks
Can start after Tier 1 completes
Implementation Notes
Use Riverpod's AsyncNotifierProvider for exportHistoryProvider — it gives clean loading/error/data states without manual StreamController management. The provider should call ExportRunRepository.getExportRunsForOrg(orgId) once and cache; expose a refresh() method on the notifier for the Retry button. List item: use Flutter's ListTile or a custom card — match the design system card style. TargetSystemBadge and StatusBadge should be extracted as shared widgets usable from the confirmation dialog (task-008) as well.
For the shimmer effect: if the shimmer package is already in pubspec, use it; otherwise implement a simple animated opacity pulse with AnimationController — do not add a new dependency solely for this. Download flow: use a local bool _isDownloading per list item (or a Set
Testing Requirements
Widget tests (flutter_test): use ProviderScope with overridden exportHistoryProvider; test loading state renders 3 skeleton items; test empty state renders correct message; test error state renders Retry button; test completed run renders Download button; test pending run hides Download button; test tapping Download triggers getSignedUrl and launchUrl. Mock ExportRunRepository and url_launcher in tests. Accessibility test: verify Semantics labels on status badges and download buttons. No golden tests required for this task.
Test file: test/widgets/export_history_panel_test.dart.
Adding exported_at and export_run_id columns to expense_claims requires a live migration on a table shared with the approval workflow. A poorly timed migration could lock the table and block claim submissions or approvals.
Mitigation & Contingency
Mitigation: Use non-blocking ADD COLUMN with a DEFAULT of NULL (no backfill needed) executed during a low-traffic window. Test migration rollback on a staging replica before production deployment.
Contingency: If migration causes table lock contention, roll back and reschedule for a maintenance window. Use a feature flag to gate the export UI until the migration completes successfully.
Chart of accounts mapping configurations for Xledger and Dynamics may not be fully specified by stakeholders at development time, leaving the mapper with incomplete data and causing validation failures for unmapped expense categories.
Mitigation & Contingency
Mitigation: Implement the mapper to return a structured validation error (not a crash) for any unmapped field, and surface these errors clearly in the export confirmation dialog. Request full mapping tables from Blindeforbundet and HLF stakeholders as a pre-condition for this epic.
Contingency: If mappings arrive incomplete, ship the mapper with the available subset and mark unmapped categories as excluded (skipped with reason). Coordinators see which categories are skipped and can manually submit those records.
Supabase Vault configuration for storing per-org accounting credentials may require infra permissions or environment secrets not yet provisioned in staging or production, blocking development and testing of credential retrieval.
Mitigation & Contingency
Mitigation: Provision Vault secrets and environment configuration in staging as the first task of this epic. Document the exact secret naming convention and rotation procedure before implementation begins.
Contingency: If Vault is unavailable, use environment variables scoped to the Edge Function as a temporary fallback for development. Block production deployment until Vault-based storage is confirmed operational.