Map internal payload to Bufdir API request schema
epic-bufdir-report-export-api-integration-task-003 — Implement the request mapper inside the bufdir-api-client that translates the canonical internal Bufdir JSON payload (produced by bufdir-format-serializer) into the exact Bufdir API request schema. Cover all required fields, handle optional sections, and apply field-level validation before submission. The mapper must be unit-testable independently of the HTTP layer.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 1 - 540 tasks
Can start after Tier 0 completes
Handles integration between different epics or system components. Requires coordination across multiple development streams.
Implementation Notes
Define a sealed BufdirApiRequest class (or use freezed) so all output fields are type-safe and non-nullable at the type level. Place the mapper in `lib/features/bufdir/data/mappers/bufdir_request_mapper.dart`. Keep the Bufdir API schema version in a single constant (e.g., `BufdirApiSchemaVersion.v2_1`) so version upgrades are a one-line change. For optional sections, use a dedicated `_mapTravelExpenses()` private method that returns null when the list is empty — the caller then uses `if (expenses != null) request.travelExpenses = expenses`.
Avoid dynamic maps; use strongly-typed freezed DTOs for both input and output. Register a BufdirColumnSchema lookup so field mappings can be driven by the org-level bufdir_column_schema config rather than being hardcoded, supporting future schema versions without code changes.
Testing Requirements
Unit tests using flutter_test covering: (1) full happy-path mapping with all optional sections populated, (2) minimal payload with required fields only, (3) all three validation error scenarios as typed exceptions, (4) Norwegian date formatting edge cases (DST boundary, year-end period), (5) float summation accuracy across 500 records. No integration or widget tests needed — mapper is pure logic. Target 100% branch coverage. Tests must be runnable with `flutter test` without network or database access.
Norse Digital Products has not yet completed API negotiations with Bufdir. If negotiations stall or Bufdir's API design diverges significantly from expectations, the API client may need substantial rework, or the epic may be blocked indefinitely.
Mitigation & Contingency
Mitigation: Implement the client against a locally defined stub of the expected Bufdir API schema. Isolate all Bufdir-specific schema mapping in a single adapter class so that changes to the actual API schema require changes in only one place. Keep the epic in 'interface-ready' status until real API credentials are available for integration testing.
Contingency: If API negotiations are not completed within the planned window, defer this epic without impact on any other epic — the PDF/CSV fallback path from Epics 1–4 delivers full standalone value. Mark the epic as blocked and resurface when negotiations conclude.
Bufdir API credentials stored in the application or edge function environment could be exposed through misconfigured secrets management, log leakage, or a compromised deployment pipeline, allowing unauthorised Bufdir submissions on behalf of the organisation.
Mitigation & Contingency
Mitigation: Store all Bufdir API credentials exclusively in Supabase Vault (or the integration credential vault component), never in client-side code or environment variables accessible to the Flutter app. Transmit credentials only from within the edge function, not from the Flutter client. Implement credential rotation support from the outset.
Contingency: If a credential leak is detected, immediately revoke and rotate the affected API credentials through Bufdir's credential management portal, audit submission logs for any unauthorised calls, and notify Bufdir's technical contact per the API agreement's security incident clause.