critical priority high complexity backend pending backend specialist Tier 4

Acceptance Criteria

createIntegrationConfig(orgId, integrationType, configData, credentials) creates a new integration configuration record and stores credentials in the credential vault atomically
readIntegrationConfig(orgId, integrationType) returns the active configuration for the organisation without returning raw credential values (credential vault reference only)
listIntegrationConfigs(orgId) returns all integration configurations for the organisation with status and last-tested timestamps
updateIntegrationConfig(orgId, integrationType, updates) updates configuration fields and optionally rotates credentials in the vault within a single transaction
deleteIntegrationConfig(orgId, integrationType) soft-deletes the config (sets status to 'deleted') and removes credentials from vault — does not hard-delete to preserve audit history
Transactional saves: if credential vault write fails after database config write, the database write is rolled back — no orphaned config records with missing credentials
If database write fails, credential vault write is not attempted — fail-fast order prevents orphaned credentials
Event emission: configuration_created, configuration_updated, configuration_deleted events emitted on Supabase Realtime channel after each successful mutation
Event payloads contain only orgId, integrationType, status, and timestamp — no credential data
All CRUD operations validate that the requesting user's JWT org claim matches the orgId parameter — no cross-org access
Service layer is accessible from both Edge Functions and the UI wizard backend flow
All service methods return typed result objects (not raw database rows) with proper error typing
Unit tests cover all five CRUD operations, transaction rollback scenarios, event emission, and cross-org access rejection

Technical Requirements

frameworks
Dart
Flutter
Supabase Edge Functions (Deno)
Supabase Realtime
apis
Supabase PostgreSQL 15
Supabase Realtime
Supabase Edge Functions REST API
data models
activity
annual_summary
assignment
performance requirements
createIntegrationConfig completes within 3 seconds including credential vault write
readIntegrationConfig and listIntegrationConfigs complete within 500ms
updateIntegrationConfig with credential rotation completes within 4 seconds
Transaction rollback completes within 2 seconds on failure
security requirements
Credential values never returned from any read operation — return vault reference key only
JWT org claim validated against orgId parameter on every service method call
Transactional atomicity prevents orphaned configs with missing credentials or orphaned credentials with missing configs
Soft-delete preserves audit trail — hard-delete prohibited
Realtime event payloads contain zero credential data
Service methods callable only from authenticated Edge Function context — not directly from mobile client
All database operations use Supabase service role within Edge Function — RLS enforced at Edge Function boundary via JWT validation

Execution Context

Execution Tier
Tier 4

Tier 4 - 323 tasks

Can start after Tier 3 completes

Integration Task

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

Implementation Notes

Implement as a Deno TypeScript service class (IntegrationConfigService) inside a Supabase Edge Function module. The most critical design concern is the two-phase transaction: Supabase PostgreSQL supports real transactions via the database, but the credential vault is a separate system. Implement a saga pattern: (1) write config to DB in a transaction, (2) write credential to vault, (3) commit transaction. On vault write failure, explicitly call transaction ROLLBACK.

Use Supabase's supabase-js v2 client with `.rpc()` for database transactions or raw SQL via `pg` client for explicit transaction control. For the credential vault, if it is implemented as an encrypted Supabase table (from task-002), wrap both writes in a single Postgres transaction using a stored procedure — this gives true atomicity without a saga. For event emission, use Supabase Realtime broadcast channel (not database changes) to control the payload shape — this prevents credential fields from accidentally leaking through database change events. Use a typed EventEmitter helper that constructs the safe payload before broadcasting.

The service should depend on the IntegrationConfigRepository (task-002) and CredentialVault interfaces via constructor injection — this makes unit testing straightforward without live database connections.

Testing Requirements

Unit tests (Deno test): createIntegrationConfig happy path with mock repository and mock credential vault, rollback when vault write fails (database row must not exist after rollback), rollback when database write fails (vault write must not have been attempted), readIntegrationConfig returns config without credential values, listIntegrationConfigs returns all active configs for org, updateIntegrationConfig with and without credential rotation, deleteIntegrationConfig soft-deletes and triggers vault credential removal, event emission verified for all three mutation operations, cross-org access rejection for all five methods. Integration tests: full create-read-update-delete cycle against a test Supabase instance. Test coverage target: 95% on service layer logic. All tests must be deterministic — mock Realtime channel to avoid side effects.

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.