Implement orchestrator step sequencing
epic-bufdir-reporting-export-core-logic-task-008 — Implement BufdirExportOrchestratorService that coordinates the end-to-end export pipeline in order: (1) create audit record, (2) query activities via BufdirActivityQueryService, (3) map columns via BufdirColumnMapper, (4) generate file via Excel/CSV generator, (5) bundle attachments if required, (6) store file and update audit record with file reference, (7) return ExportResult with download artifact. All steps must update the audit record status on entry and exit.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 3 - 413 tasks
Can start after Tier 2 completes
Implementation Notes
Structure the orchestrator as a sequence of private async methods (_createAudit, _queryActivities, _mapColumns, _generateFile, _bundleAttachments, _storeAndFinalize) each called in order from a single public runExport method. Wrap each private method call in a try/catch that calls _markFailed(auditId, e.toString()) before rethrowing — this keeps the happy-path code linear and readable. Use Dart's sealed classes (Dart 3+) for ExportResult to force exhaustive handling at the call site. Run _generateFile inside compute() passing a plain data record (avoid passing closures).
The BufdirExportOrchestratorService should be registered as a Riverpod AsyncNotifierProvider so the UI can watch export progress via audit record polling. Keep the orchestrator thin: it should contain sequencing logic only, never business rules about columns or activity filtering.
Testing Requirements
Unit tests (flutter_test): use mock implementations of BufdirActivityQueryService, BufdirColumnMapper, file generator, and BufdirExportAuditService to verify correct step sequencing via call-order assertions. Test the zero-row path returns ExportSuccess with rowCount=0 and null downloadUrl. Test that audit status transitions occur in the correct order using a recorded fake. Test that includeAttachments=false skips the bundling step entirely.
Integration test (Supabase local emulator): run a full pipeline against real Supabase tables with seed data for NHF, Blindeforbundet, and HLF to confirm the audit record reaches 'completed' status and the signed URL is accessible. Target ≥85% line coverage on the orchestrator class.
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.
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.