critical priority high complexity integration pending integration specialist Tier 2

Acceptance Criteria

BufdirExportService.invokeEdgeFunction() sends a POST request to the Bufdir export edge function URL with scope, period, and format in the JSON body
The JWT from the current Supabase session is included in the Authorization header on every request
HTTP 4xx responses are mapped to typed BufdirClientException with the response body preserved for diagnostics
HTTP 5xx responses are mapped to typed BufdirServerException distinguishing server fault from timeout
Network-level failures (SocketException, TimeoutException) are caught and rethrown as BufdirNetworkException
Edge function timeout (configurable, default 30 s) triggers BufdirTimeoutException with elapsed time included
The raw response payload (Uint8List or Map) is returned as-is without parsing to allow downstream routing
Organisation credentials are never included in the mobile request body — they are resolved server-side from the JWT org claim
All exception types are sealed classes implementing a common BufdirExportException base
Unit tests cover: successful 200 response, 401 unauthenticated, 422 validation error, 500 server error, timeout, and network failure

Technical Requirements

frameworks
Flutter
Riverpod
Supabase Edge Functions (Deno)
apis
Supabase Edge Functions REST API
Supabase Auth (JWT retrieval)
data models
bufdir_export_audit_log
bufdir_column_schema
performance requirements
Request timeout set to 30 seconds configurable via app config
No response body buffering beyond 10 MB to prevent OOM on large exports
Edge function invocation must not block the UI thread — executed in an isolate or async Dart Future
security requirements
Service role key must never be present in the mobile client — only user-scoped JWT is sent
Organisation context derived from JWT claims server-side, never passed as a trusted client parameter
TLS enforced — no plain HTTP fallback
Function input validated server-side; client should not trust response without schema validation

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

Use Supabase's `functions.invoke()` client method rather than raw http.Client to benefit from built-in JWT injection and error normalisation. Wrap the call in a try/catch hierarchy: FunctionException first (Supabase SDK typed error), then TimeoutException, then SocketException. Define the exception hierarchy in a dedicated `bufdir_export_exceptions.dart` file. Do not parse the response body here — return the raw FunctionResponse.data so that the routing layer (task-008) can decide how to handle PDF vs CSV payloads.

Log failures with severity level; do not log raw response bodies as they may contain PII.

Testing Requirements

Unit tests using flutter_test with http.Client mocked via mockito or http_mock_adapter. Cover: (1) successful 200 with raw payload returned, (2) 401 → BufdirClientException, (3) 422 → BufdirClientException with body, (4) 500 → BufdirServerException, (5) timeout → BufdirTimeoutException, (6) SocketException → BufdirNetworkException. Assert that the JWT header is present in every request. Assert organisation credentials are absent from the request body.

Minimum 90% branch coverage on BufdirExportService.

Component
Bufdir Export Service
service high
Epic Risks (2)
high impact medium prob security

The scope selector must accurately reflect each coordinator's access rights within the org hierarchy. If a coordinator can select a scope broader than their authorised access, the edge function's RLS enforcement must catch the attempt — but a permissive RLS policy or a bug in the scope resolver could allow unauthorised data to be exported.

Mitigation & Contingency

Mitigation: Implement permission enforcement at two independent layers: (1) the scope selector only renders options permitted by the user's role record, and (2) the edge function re-validates the requested scope against the user's JWT claims before executing any queries. Write integration tests that attempt to invoke the edge function with a scope beyond the user's permissions and assert rejection.

Contingency: If a permission bypass is discovered post-launch, immediately disable the export feature via the org-level feature flag while the fix is deployed. Review all audit records for exports that may have included out-of-scope data and notify affected organisations.

medium impact medium prob technical

The export workflow has 7+ discrete states (idle, scope selected, period selected, preview loading, preview ready, confirming, exporting, complete, failed) and several conditional transitions. An incomplete BLoC state machine could allow duplicate submissions, stale preview data to be confirmed, or error states to be unrecoverable without a restart.

Mitigation & Contingency

Mitigation: Model the state machine explicitly as a sealed class hierarchy before coding. Review the state diagram against all user story acceptance criteria. Write bloc unit tests for every valid and invalid state transition, including the happy path and all documented error states.

Contingency: If the BLoC grows too complex to test reliably, decompose it into two cooperating blocs: one for configuration (scope + period selection) and one for execution (preview + confirm + export), linked by a coordinator object.