Implement export audit record creation and updates
epic-bufdir-reporting-export-core-logic-task-006 — Implement BufdirExportAuditService backed by the export audit repository. On export initiation, create an immutable audit record with timestamp, organisation ID, period, and user ID. Expose updateStatus to advance through the ExportStatus state machine. Ensure records are never deleted — only appended or status-advanced — to satisfy compliance trail requirements.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 1 - 540 tasks
Can start after Tier 0 completes
Implementation Notes
Place service under lib/features/bufdir_export/infrastructure/audit/bufdir_export_audit_service.dart and repository interface under lib/features/bufdir_export/domain/audit/export_audit_repository.dart. Supabase repository implementation goes under lib/features/bufdir_export/infrastructure/audit/supabase_export_audit_repository.dart. Database table design: bufdir_export_audits with columns (audit_id UUID PK, org_id TEXT NOT NULL, user_id UUID NOT NULL, period_start TIMESTAMPTZ, period_end TIMESTAMPTZ, status TEXT CHECK(status IN ('initiated','in_progress','completed','failed')), initiated_at TIMESTAMPTZ NOT NULL, last_updated_at TIMESTAMPTZ NOT NULL, file_storage_key TEXT, file_name TEXT, file_size_bytes BIGINT, file_checksum TEXT, file_generated_at TIMESTAMPTZ). Use Supabase .update().eq('audit_id', id).select().single() for targeted updates — avoid re-inserting the whole row.
For optimistic concurrency on updateStatus, include .eq('status', currentStatus.toDbString()) in the update filter and throw a ConcurrentModificationException if zero rows affected. Register BufdirExportAuditService as a Riverpod Provider scoped to the feature.
Testing Requirements
Unit tests with mock ExportAuditRepository: test createRecord produces correct initial state, test updateStatus for all valid transitions (initiated→inProgress, inProgress→completed, inProgress→failed), test updateStatus throws InvalidStatusTransitionException for invalid transitions (e.g., completed→initiated). Test attachFileRef succeeds when status=completed, throws when status=inProgress or initiated. Test that no delete method exists on the repository interface (compile-time enforcement). Integration test against Supabase test instance: verify RLS blocks cross-org audit record reads, verify no DELETE privilege on table, verify UTC timestamp storage.
Target 90%+ branch coverage on service implementation.
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.