critical priority low complexity backend pending backend specialist Tier 0

Acceptance Criteria

An abstract class `AccountingExporter` is defined in Dart under `lib/domain/accounting/` with no concrete implementation
The abstract class declares a single async method: `Future<ExportPayloadWrapper> export(List<ApprovedClaim> claims)` — signature must not be altered by implementors
A sealed class `AccountingExportError` is defined with at minimum three variants: `ValidationError(List<FieldValidationFailure> failures)`, `SerializationError(String message)`, and `SystemError(Object cause)`
A value class `ExportPayloadWrapper` is defined containing: `String exportRunId`, `AccountingSystemType system` (enum), `List<String> exportedClaimIds`, and `dynamic payload` (typed as `Object` or a sealed `ExportPayload` union)
An enum `AccountingSystemType` is defined with at minimum `xledger` and `dynamics` values
All types are exported from a single barrel file `lib/domain/accounting/accounting_exporter.dart`
No concrete logic or Supabase calls exist in this file — it is a pure Dart contract
Dart analyzer produces zero warnings and zero errors on the interface file
A `FieldValidationFailure` value class captures `fieldName`, `providedValue`, and `reason` for structured error reporting

Technical Requirements

frameworks
Flutter
Dart
data models
ApprovedClaim
ExportPayloadWrapper
AccountingExportError
AccountingSystemType
FieldValidationFailure
performance requirements
Abstract interface introduces zero runtime overhead — pure polymorphism contract
All types must be immutable (use `final` fields, consider `@immutable` annotation or `freezed`)
security requirements
No sensitive claim data (amounts, personal identifiers) must appear in error messages or logs at this layer
Error types must not expose raw database or network exception internals

Execution Context

Execution Tier
Tier 0

Tier 0 - 440 tasks

Implementation Notes

Use Dart's `abstract class` (not `abstract interface class`) to allow shared utility methods to be added later without breaking implementors. Prefer a sealed class over a plain Exception hierarchy for `AccountingExportError` — sealed classes force exhaustive handling in `switch` expressions which catches missing error cases at compile time. Use `freezed` for `ExportPayloadWrapper` and `FieldValidationFailure` to get immutability, equality, and copyWith for free. Place all types in `lib/domain/accounting/` following the project's existing domain layer conventions.

Do NOT add any Supabase, http, or Flutter imports — this file must have zero external dependencies so it can be tested in pure Dart unit tests. The `AccountingExporterService` (orchestrator) will depend only on this abstract type, never on the concrete exporters directly.

Testing Requirements

Unit tests using `flutter_test`. Create a mock concrete implementation `_MockExporter` that implements `AccountingExporter` and verify: (1) the abstract class cannot be instantiated directly (compile-time check, documented), (2) a mock implementation satisfying the interface compiles and runs, (3) `ExportPayloadWrapper` equality and copyWith work correctly if using `freezed`, (4) all `AccountingExportError` sealed variants can be pattern-matched exhaustively. Minimum 5 unit tests. No integration tests needed at this layer.

Component
Xledger Exporter
service high
Epic Risks (3)
high impact medium prob dependency

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.

high impact low prob technical

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.

medium impact high prob integration

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.