high priority medium complexity testing pending testing specialist Tier 8

Acceptance Criteria

Integration tests use a real Supabase test project (or local Supabase via supabase start) — not mocked database clients
Happy path: a fully valid integration config is saved and can be retrieved from the database with all fields intact
Invalid config (missing required credential scope) is rejected — no database row is written, structured ValidationFailure is returned
Invalid config (missing required field mapping) is rejected — no database row is written, correct field names appear in error list
Duplicate save (same org_id + integration_type) performs upsert correctly — only one record exists, updated_at is refreshed
Connection test invokes the mock adapter's testConnection() and persists last_tested_at and last_test_status to the database
Field mapping update triggers FieldMappingResolver cache invalidation — subsequent reads use the new mapping, not the old cached one
Transactional rollback: if the post-save audit log write fails (simulated), the config row is also rolled back and does not persist
Cross-org isolation: a config saved for org A cannot be retrieved by a session scoped to org B (RLS enforcement)
All integration tests clean up their own test data in tearDown — no test data leaks between runs

Technical Requirements

frameworks
Dart
flutter_test
Supabase Dart SDK (real connection)
supabase_flutter test utilities
apis
Supabase PostgREST (live test instance)
IntegrationConfigValidator (real implementation)
IntegrationConfigService (real implementation)
FieldMappingResolver (real implementation with spy for cache invalidation)
Mock adapter implementations (deterministic test doubles)
data models
IntegrationConfig
FieldMapping
ConfigValidationError
ConnectionTestResult
IntegrationConfigAuditLog
performance requirements
Each integration test must complete within 5 seconds against a local Supabase instance
Full integration test suite must complete within 60 seconds
Test setup (table seeding) must complete within 2 seconds per test
security requirements
Integration tests must connect to a dedicated test Supabase project — never the production project
Test credentials (SUPABASE_TEST_URL, SUPABASE_TEST_ANON_KEY) must be loaded from environment variables or a gitignored .env.test file
RLS tests must use two distinct JWT sessions (org A and org B) — never service-role key for RLS bypass in RLS tests

Execution Context

Execution Tier
Tier 8

Tier 8 - 48 tasks

Can start after Tier 7 completes

Integration Task

Handles integration between different epics or system components. Requires coordination across multiple development streams.

Implementation Notes

Place integration tests in `integration_test/` (not `test/`) to signal they require external dependencies. Use a `TestSupabaseFactory` helper class that reads SUPABASE_TEST_URL and SUPABASE_TEST_ANON_KEY from the environment and creates pre-authenticated clients for org A and org B test sessions. For the transactional rollback test, the cleanest approach is to inject the audit logger as a dependency into IntegrationConfigService (following the pattern established in task-014) and provide a `ThrowingAuditLogger` test double. For RLS cross-org isolation, create two separate `SupabaseClient` instances with different JWT tokens representing org A and org B — use Supabase's `auth.signInWithPassword()` with pre-seeded test users.

Cache invalidation spy: `class SpyFieldMappingResolver implements FieldMappingResolver { int invalidateCalls = 0; @override Future invalidateCache(String orgId, String integrationType) async { invalidateCalls++; } }`. Avoid using `expect()` inside `setUp` — only use it in test bodies so failures are clearly attributed.

Testing Requirements

This task IS the testing work. Use `flutter_test` with a `setUpAll` that initializes the Supabase test client using environment variables. Use a `tearDown` that deletes all rows created by the test using a service-role client (to bypass RLS for cleanup only). Group tests as: 'save flow - valid configs', 'save flow - validation rejection', 'upsert deduplication', 'connection test orchestration', 'field mapping cache invalidation', 'transactional rollback', 'RLS cross-org isolation'.

For the cache invalidation test, use a spy wrapper around FieldMappingResolver that records whether invalidateCache() was called and with which arguments. For the rollback test, inject a failing audit logger that always throws — verify the config table has no new row after the attempted save. Run tests with `flutter test integration_test/config_service_test.dart`. Ensure test environment setup instructions are documented in a comment at the top of the test file.

Component
Integration Configuration Service
service high
Epic Risks (3)
medium impact high prob technical

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.

medium impact high prob dependency

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.

medium impact medium prob scope

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.