Implement validator integration in Config Service save flow
epic-external-system-integration-configuration-core-services-task-014 — Wire the IntegrationConfigValidator into the Integration Config Service save and update flows. Ensures all configurations are validated before persistence, validation errors are returned as structured domain errors (not exceptions), and partial saves are prevented on validation failure. Covers all validation rules: credential completeness, field mapping coverage, and sync schedule validity.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 6 - 158 tasks
Can start after Tier 5 completes
Handles integration between different epics or system components. Requires coordination across multiple development streams.
Implementation Notes
Model the return type using a sealed class pattern: `sealed class ConfigSaveResult {}` with subclasses `ConfigSaveSuccess(IntegrationConfig config)` and `ConfigSaveFailure(List
If the validator itself throws (e.g., network error fetching adapter capabilities), catch it and surface as a `ConfigSaveFailure` with a single error of errorCode='VALIDATION_UNAVAILABLE' rather than propagating the exception. For the BLoC layer, ConfigSaveFailure should map to a state that populates field-level error hints on the setup wizard form — ensure the ConfigValidationError.fieldPath values match the form field identifiers used in the wizard UI.
Testing Requirements
Unit tests covering the save flow integration: (1) valid config passes validation and is persisted — Supabase client insert/upsert is called exactly once, (2) config failing credential validation returns ValidationFailure with errorCode='CREDENTIAL_INCOMPLETE' and Supabase client is never called, (3) config failing field mapping returns ValidationFailure with errorCode='MAPPING_INCOMPLETE' listing missing fields, (4) config failing sync schedule returns ValidationFailure with errorCode='INVALID_SCHEDULE', (5) multiple validation errors are all returned together (not fail-fast), (6) validator throwing unexpectedly is wrapped and re-surfaced as a domain error not a raw exception, (7) update flow applies same validation as save flow. Use a mock IntegrationConfigValidator that returns configurable results. Verify the Supabase mock's insert was called 0 times on any validation failure.
Each of the five external systems (Xledger, Dynamics, Cornerstone, Consio, Bufdir) has a different authentication flow, field schema, and error format. Forcing them into a uniform adapter interface may require compromises that result in leaky abstractions or make the adapter contract too complex to maintain.
Mitigation & Contingency
Mitigation: Design the IntegrationAdapter interface with a loose invoke() payload rather than a typed one, allowing each adapter to declare its own input/output schema. Use integration type metadata in the registry to document per-adapter quirks. Build Xledger first as the most documented API, then adapt the interface based on learnings.
Contingency: If the uniform interface cannot accommodate all five systems, split into two interface tiers: a simple polling/export adapter and a richer bidirectional adapter, with the registry declaring which tier each system implements.
Development and testing of the Cornerstone and Consio adapters depends on NHF providing sandbox API access. If credentials or documentation are delayed, these adapters cannot be validated, blocking the epic's acceptance criteria.
Mitigation & Contingency
Mitigation: Implement Xledger and Dynamics adapters first (better-documented, sandbox available). Create a mock adapter for Cornerstone/Consio using recorded API responses for CI testing. Proactively request sandbox access from NHF at project kickoff.
Contingency: Ship the epic with Cornerstone/Consio adapters in a 'stub' state (connectivity test returns a simulated success, invoke() is not production-wired) and gate the NHF integration behind a feature flag until real API access is obtained.
Real-world field mappings may include nested transformations, conditional logic, and data type coercions (e.g., Norwegian date formats, currency rounding rules) that the Field Mapping Resolver's initial design does not accommodate, requiring scope expansion mid-epic.
Mitigation & Contingency
Mitigation: Gather actual field mapping examples from Blindeforbundet (Xledger) and HLF (Dynamics) before designing the resolver. Identify the most complex transformation required and ensure the resolver design handles it. Limit Phase 1 to direct field renaming and format conversion only.
Contingency: If complex transformations are required, implement a simple expression evaluator (e.g., JSONata or a custom mini-DSL) as an extension point in the resolver, delivering basic mappings first and complex ones in a follow-up task.