critical priority low complexity backend pending backend specialist Tier 0

Acceptance Criteria

ExportStatus is a Dart enum with exactly four values: initiated, inProgress, completed, failed — each with a display label getter
ExportAuditRecord is an immutable class with: auditId (String UUID), orgId (String), userId (String), reportingPeriod (DateTimeRange), status (ExportStatus), initiatedAt (DateTime), lastUpdatedAt (DateTime), and fileRef (ExportFileRef?)
ExportFileRef value object contains: storageKey (String), fileName (String), fileSizeBytes (int), generatedAt (DateTime), and checksumSha256 (String)
ExportStatus state machine is enforced: initiated → inProgress → completed or failed; any other transition throws InvalidStatusTransitionException
Abstract ExportAuditService interface exposes: Future<ExportAuditRecord> createRecord(CreateAuditRecordParams params), Future<ExportAuditRecord> updateStatus(String auditId, ExportStatus newStatus), Future<ExportAuditRecord> attachFileRef(String auditId, ExportFileRef fileRef)
createRecord produces an audit record with status=initiated and immutable initiatedAt timestamp
attachFileRef only permitted when status is completed — throws if called in other states
All types reside in the domain layer with no infrastructure dependencies
InvalidStatusTransitionException includes fromStatus, toStatus, and auditId fields for diagnostics

Technical Requirements

frameworks
Dart (pure domain layer)
data models
ExportAuditRecord
ExportStatus
ExportFileRef
CreateAuditRecordParams
performance requirements
ExportAuditRecord instances must be lightweight — no embedded large blobs
security requirements
userId must be stored but never logged in plain-text error messages
checksumSha256 on ExportFileRef ensures file integrity for compliance audit trail
auditId must be a UUID v4 to prevent sequential enumeration

Execution Context

Execution Tier
Tier 0

Tier 0 - 440 tasks

Implementation Notes

Place under lib/features/bufdir_export/domain/audit/. Enforce state machine in the domain model itself rather than in the service implementation — ExportAuditRecord.advanceStatus(ExportStatus next) should throw InvalidStatusTransitionException inline. This prevents infrastructure implementations from bypassing the state machine. Use DateTime.toUtc() for all timestamps to avoid timezone issues in compliance records.

DateTimeRange (from Flutter's material package) may be replaced with a custom ReportingPeriod value object (startDate, endDate as DateTime) if Flutter dependency is undesirable in the domain layer — prefer the custom type. CreateAuditRecordParams should be a simple value object, not a map, to keep the interface type-safe.

Testing Requirements

Unit tests covering: valid and invalid ExportStatus state machine transitions (all 12 possible from/to combinations), ExportAuditRecord construction, copyWith immutability, ExportFileRef checksum field presence enforcement. Test that attachFileRef throws when status != completed. Test CreateAuditRecordParams validation (non-empty orgId, non-null period). Target 100% branch coverage on state machine logic.

Component
Export Audit Log Service
service medium
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.