Data Layer medium complexity Shared Component backendshared
0
Dependencies
4
Dependents
3
Entities
0
Integrations

Description

Enforces strict per-organization data isolation across all database queries, ensuring that NHF, Blindeforbundet, HLF, and Barnekreftforeningen data never cross-contaminates in aggregation results. Injects org-scoping predicates into every query and validates that returned records belong to the requesting organization.

Feature: Bufdir Data Aggregation

multi-org-data-isolator

Summaries

The Multi-Organization Data Isolator is the fundamental trust boundary that guarantees NHF, Blindeforbundet, HLF, and Barnekreftforeningen can each use the shared platform without any risk of seeing each other's sensitive member, activity, or financial data. A single data leakage incident across organizations could trigger GDPR enforcement actions, destroy inter-organizational trust, and create legal liability. This shared component eliminates that risk at the infrastructure level by ensuring org-scoping is enforced on every database interaction — not left to individual developers to remember on a feature-by-feature basis. It is one of the highest-value risk reduction investments in the entire system.

As a shared component used across both backend and shared execution contexts, the Multi-Organization Data Isolator is a foundational dependency for nearly every data-access component in the system. It is medium complexity but carries outsized delivery risk: if it is incomplete or incorrect, all downstream components that depend on it for correctness cannot be safely tested or shipped. It should be the first data-layer component completed and the most rigorously reviewed. Testing must cover boundary conditions — cross-org queries that should be rejected, missing org context, and session expiry scenarios.

Any interface change will ripple across all consumers, so its API should be locked early in the project lifecycle.

Multi-Org Data Isolator provides two primary integration patterns: query-time scoping via applyOrgScope(query, orgId) which injects WHERE org_id = :orgId predicates into Supabase query builders, and result-time validation via assertOrgIsolation(resultSet, orgId) which iterates the result set and throws if any record's org_id mismatches. getCurrentOrgId() reads from the authenticated Supabase session JWT claims, avoiding any client-supplied org parameter. getOrgScopedSupabaseClient(orgId) returns a Supabase client pre-configured with RLS context for that org, useful for RPC calls where row-level security must be enforced at the connection level. This component has no external dependencies, making it a safe foundation to build on.

It should be treated as immutable once stabilized — modifications require regression testing across all consumers.

Responsibilities

  • Inject organization ID scoping into all data queries
  • Validate that aggregation results contain only the requesting org's data
  • Provide current organization context from authenticated session
  • Prevent cross-org data leakage in multi-tenant queries

Interfaces

getCurrentOrgId()
applyOrgScope(query, orgId)
validateRecordOwnership(record, orgId)
assertOrgIsolation(resultSet, orgId)
getOrgScopedSupabaseClient(orgId)

Related Data Entities (3)

Data entities managed by this component

API Contract

View full contract →
REST /api/v1/org-isolation 7 endpoints
GET /api/v1/org-isolation
GET /api/v1/org-isolation/:id
POST /api/v1/org-isolation
PUT /api/v1/org-isolation/:id
DELETE /api/v1/org-isolation/:id
GET /api/v1/org-isolation/current-org
+1 more