Build Export History Panel UI Component
epic-accounting-system-export-engine-task-008 — Build the Export History Panel Flutter widget that displays a chronological list of completed export runs for the current organization. Each row must show: export date range, run timestamp, number of claims included, exporter type (Xledger/Dynamics), and run status. Fetch data from the Export Run Repository. The panel is read-only and supports pull-to-refresh. Use design token system for styling.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 4 - 323 tasks
Can start after Tier 3 completes
Implementation Notes
Keep ExportHistoryPanel a pure presentation widget β accept a list of ExportRunViewModel objects as its data input, not a repository reference. The BLoC/Riverpod layer handles fetching and exposes a stream/state that the panel listens to. Define ExportRunViewModel as an immutable Dart class with only display-ready fields (pre-formatted date strings, localised status label, count as int). Use ListView.builder with itemExtent set to a design-token-derived value for smooth scrolling performance.
For the status badge, use a small Container with BorderRadius and a background colour derived from design tokens β avoid third-party badge packages. The exporter type label ('Xledger' / 'Dynamics 365') should be derived from an enum with a display name getter, not a raw string stored in the database, so the UI is resilient to schema changes.
Testing Requirements
Widget tests using flutter_test: render panel with mock list of 0, 1, and 20 export runs; verify each row displays all required fields; verify pull-to-refresh triggers repository re-fetch; verify design token classes are applied (spot-check key Text and Container styles); verify no overflow on 320px width. Golden file tests for the ExportRunListTile to catch visual regressions. No integration tests required for this task.
The Xledger CSV/JSON import specification may not be available in full detail at implementation time. If the field format, column ordering, encoding requirements, or required fields differ from assumptions, the generated file will be rejected by Xledger on first production use.
Mitigation & Contingency
Mitigation: Obtain the official Xledger import specification document from Blindeforbundet before starting XledgerExporter implementation. Build a dedicated acceptance test that validates a sample export file against all documented constraints.
Contingency: If the spec arrives late, implement a configurable column-mapping layer so that field order and names can be adjusted via configuration without code changes. Ship a file-based export that coordinators can manually verify before connecting to Xledger import.
The atomic claim-marking transaction in Double-Export Guard could fail under high concurrency if two coordinators trigger an export for overlapping date ranges simultaneously, potentially allowing duplicate exports to proceed past the guard.
Mitigation & Contingency
Mitigation: Use a database-level advisory lock or a SELECT FOR UPDATE on the relevant claim rows within the export transaction to serialize concurrent exports per organization. Add an integration test that simulates concurrent export triggers.
Contingency: If locking proves problematic at the database level, implement an application-level distributed lock using a Supabase row in a dedicated export_locks table with an expiry timestamp and automatic cleanup on failure.
HLF's Dynamics portal API endpoint may not be available or documented in time for Phase 1, leaving DynamicsExporter unable to be validated against a real system and potentially shipping with an incorrect field schema.
Mitigation & Contingency
Mitigation: Design DynamicsExporter for file-based export first (CSV/JSON download), with the API push implemented behind a feature flag. Request a Dynamics test environment or sandbox from HLF as early as possible.
Contingency: Ship DynamicsExporter as a file export only for Phase 1. Phase the API push integration into a follow-on task once the Dynamics sandbox is available, using the same AccountingExporter interface with no breaking changes.