Implement row validation in column mapper
epic-bufdir-reporting-export-core-logic-task-005 — Add post-mapping validation logic to BufdirColumnMapper: check for required Bufdir columns, validate data types and value ranges, flag rows with constraint violations, and collect validation errors into a RowValidationReport. Ensure failed rows are quarantined rather than causing full export failure.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 2 - 518 tasks
Can start after Tier 1 completes
Implementation Notes
Extend MapRowsResult as the new return type of mapRows — this is a breaking change to the interface defined in task-001, so update BufdirColumnMapperService accordingly. Validation should run as a second pass after mapping, not interleaved — this keeps mapping logic and validation logic independently testable. Implement _validateMappedRow(MappedRow row, ColumnMappingConfig config) returning List
Date validation: require ISO 8601 format (YYYY-MM-DD) and reject partial dates. Quarantined row should include the partial MappedRow (fields that did pass) for diagnostic purposes in the UI.
Testing Requirements
Unit tests for each ValidationErrorCode scenario: missing required column, type mismatch for string/integer/date/boolean, out-of-range date, empty required string. Test batch with zero quarantined rows returns empty quarantinedRows. Test batch where all rows fail returns validRows empty and quarantinedRows full. Test RowValidationSummary counts match actual list lengths.
Test errorBreakdown counts are accurate for mixed-error batches. Test that quarantined rows preserve sourceActivityId for traceability. Integration test: run full NHF and HLF fixture data sets through mapper + validator end-to-end and assert no unexpected quarantines. Target 95%+ branch coverage on validation logic.
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.