Implement HTTP submission and response handling
epic-bufdir-report-export-api-integration-task-004 — Build the HTTP submission layer in the bufdir-api-client: POST to the Bufdir API endpoint, parse the confirmation response, extract the Bufdir reference number, handle HTTP error codes (400, 409, 422, 500) with structured error types, and implement exponential backoff retry for transient failures. Return a strongly-typed BufdirSubmissionResult to callers.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 2 - 518 tasks
Can start after Tier 1 completes
Handles integration between different epics or system components. Requires coordination across multiple development streams.
Implementation Notes
Implement BufdirApiClient as a class injected with an http.Client (or Dio instance) so tests can substitute a mock. Use a RetryPolicy helper with configurable maxAttempts and backoff strategy — do not inline retry logic in the submit method. Route the actual HTTP call through a Supabase Edge Function (`functions/bufdir-submit`) which holds the real Bufdir credentials; the mobile client calls the Edge Function, not Bufdir directly. Use Dio's interceptor stack for logging (masked) and for injecting the Supabase JWT.
Model BufdirSubmissionResult with freezed sealed classes: `BufdirSubmissionResult` → `BufdirSubmissionSuccess(referenceNumber: String)` | `BufdirSubmissionError(type: BufdirErrorType, message: String, attempts: int)`. After each failed attempt, write an interim 'submission_failed' row to bufdir_export_audit_log so coordinators can see retry history.
Testing Requirements
Unit tests using flutter_test with a MockHttpClient (or mockito): (1) successful submission extracts reference number, (2) each error code (400, 409, 422, 500) maps to correct error variant, (3) three 500 errors exhaust retries and return transientFailure, (4) 409 is not retried, (5) network timeout surfaces as timeout error, (6) concurrent duplicate call returns same Future. Integration test against Bufdir sandbox environment (if available) covering happy-path and 409 conflict. All tests must run without real network access in CI.
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.