critical priority medium complexity backend pending backend specialist Tier 0

Acceptance Criteria

ExportRequest is an immutable value object with: orgId (String), requestingUserId (String), reportingPeriod (ReportingPeriod), exportFormat (ExportFormat enum: csv, xlsx), and locale (String, default 'nb')
ExportFormat enum has at minimum: csv and xlsx variants
ExportResult is a Dart sealed class with two variants: ExportSuccess and ExportFailure
ExportSuccess contains: auditId (String), downloadArtifact (DownloadArtifact), partialFailures (List<PartialFailureReport>), and completedAt (DateTime)
ExportFailure contains: auditId (String?), errorCode (ExportErrorCode enum), message (String), and failedAt (DateTime)
ExportErrorCode enum covers at minimum: noDataForPeriod, columnMappingUnavailable, fileGenerationFailed, auditServiceUnavailable, permissionDenied
DownloadArtifact contains: fileBytes (Uint8List), fileName (String), mimeType (String), and fileSizeBytes (int)
PartialFailureReport contains: affectedRowIndices (List<int>), failureReason (String), subServiceName (String), and isFatal (bool)
Abstract ExportOrchestrator interface exposes: Future<ExportResult> export(ExportRequest request)
ExportSuccess.partialFailures may be non-empty while still being a success — partial failures are informational, not blocking

Technical Requirements

frameworks
Dart (domain layer)
dart:typed_data for Uint8List
data models
ExportRequest
ExportResult
ExportSuccess
ExportFailure
DownloadArtifact
PartialFailureReport
ExportErrorCode
ReportingPeriod
performance requirements
DownloadArtifact.fileBytes must be lazily populated — do not hold entire file in memory longer than needed
PartialFailureReport list must be bounded — enforce max 1000 entries, truncate with a summary entry beyond that
security requirements
ExportRequest.requestingUserId must be validated against session context before orchestrator accepts request
DownloadArtifact must not be cached in memory beyond the response delivery — clear after use

Execution Context

Execution Tier
Tier 0

Tier 0 - 440 tasks

Implementation Notes

Place under lib/features/bufdir_export/domain/orchestrator/. The sealed class pattern for ExportResult is critical — it forces all callers (UI, BLoC) to handle both success and failure branches at compile time, preventing silent error swallowing. DownloadArtifact wrapping Uint8List is intentional — it co-locates the file bytes with metadata needed for proper HTTP response headers or share_plus integration. ReportingPeriod should be defined as a shared value object reusable across the export domain (start: DateTime, end: DateTime) with a isValid getter (end >= start, both UTC).

Do NOT use Future> — the sealed ExportResult is more idiomatic Dart and avoids fp_dart dependency in the domain layer.

Testing Requirements

Unit tests for ExportResult sealed class pattern matching exhaustiveness. Test ExportSuccess with empty and non-empty partialFailures. Test ExportFailure for each ExportErrorCode variant. Test ExportRequest validation (null orgId, null userId, invalid period where end < start).

Test PartialFailureReport truncation at 1000 entries. Test DownloadArtifact MIME type inference per ExportFormat. No infrastructure mocks needed at this layer — pure model tests only.

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

Bufdir's column schema may have per-field business rules (conditional required fields, cross-field validation, organisation-specific category taxonomies) that cannot be expressed in a simple key-value mapping configuration. If the configuration model is too simple, supporting NHF's specific requirements will require hardcoded organisation logic, undermining the configuration-driven design.

Mitigation & Contingency

Mitigation: Design the column configuration schema as a full JSON document supporting field-level transformation rules, conditional expressions, and org-specific value enumerations. Validate the design against a real NHF Bufdir Excel template before implementation begins.

Contingency: If the configuration model cannot express all required rules, implement a thin transformation plugin interface where org-specific logic can be added as a named Dart class registered against the organisation ID, with the JSON config covering only the common cases.

high impact medium prob technical

For large organisations like NHF with potentially tens of thousands of activity records, the full export pipeline (query + map + generate + bundle + upload) may exceed Supabase Edge Function execution time limits (typically 150s), causing silent timeouts that leave audit records in a pending state indefinitely.

Mitigation & Contingency

Mitigation: Implement the orchestrator as a background Dart isolate with progress streaming rather than a synchronous Edge Function call. Use chunked processing for the query and mapping phases to reduce peak memory usage. Profile against realistic NHF data volumes in a staging environment.

Contingency: If processing time cannot be reduced below the timeout threshold, implement an asynchronous job model where the export is queued, processed in the background, and the user is notified via push notification when the download is ready — treating it as an eventual rather than synchronous operation.