Skip to content

4. Multi-Tenancy & Configuration

How tenants are isolated, provisioned, configured, and retired — the multi-tenancy model every entity inherits.

4.1 Overview

The platform is multi-tenant by design. Every resource — user, device, consent record, audit event, OAuth client, KYC session — belongs to exactly one tenant. This section defines the isolation model, tenant lifecycle, and cross-tenant rules. Entity schemas (tenant, user, device, …) are defined in §5 Data Model.

4.2 Data Isolation Model

Isolation Requirements:

Requirement Description
Tenant-scoped data Every data entity includes a tenant_id field. All queries are scoped to the requesting tenant.
No cross-tenant data access A tenant's API credentials can never read, modify, or search data belonging to another tenant. This includes palm identification — 1:N search scopes to the tenant's enrolled templates only.
Tenant-scoped authentication OAuth client credentials are bound to exactly one tenant. The tenant_id is embedded in the access token and validated on every request.
Tenant-scoped devices All devices (personal scanner, pos, gate, kiosk) are registered to a specific tenant. The device certificate's SAN URI identifies both the device_id and tenant_id.
Platform-level visibility Only Platform Admins can view data across multiple tenants (for operational monitoring, not business operations). All such access is audit-logged.

Enforcement Points:

Layer Mechanism
API Gateway tenant_id extracted from token/cert, injected into request context
Middleware tenant_middleware.py validates tenant_id on every request, rejects if missing or mismatched
Domain Services All repository queries include tenant_id as a mandatory filter
Database Row-level filtering on tenant_id (implementation may use RLS or application-level enforcement)

4.3 Tenant Lifecycle

Tenant States:

State Description Data Access API Access
provisioning Being set up, not yet active Write-only (setup) Disabled
active Fully operational Full Enabled
suspended Temporarily disabled (non-payment, security incident, policy violation) Read-only Disabled (returns HTTP 403, tenant_suspended)
deactivating Marked for deletion, grace period active Read-only Disabled
deleted All data permanently removed None None

Lifecycle Flow:

provisioning → active ⇄ suspended
               deactivating → deleted

4.4 Tenant Provisioning

Process:

  1. Platform Admin creates tenant via Web Console (or platform API)
  2. Platform generates tenant_id (slug format, e.g., link-wallet, investglass)
  3. Admin configures initial settings (auth methods, KYC provider, palm vendor — as defined in Section 4.5)
  4. Platform creates first Tenant Admin account (email + temporary password)
  5. Tenant status moves to active

Tenant entity schema: see §5.2.

4.5 Tenant Settings

Each tenant configures capabilities individually. All settings have sensible defaults. There are no preset tenant types — each tenant is configured individually.

User ID handling is per-request: POST /v1/users accepts an optional user_id — if provided, the platform maps it; if omitted, the platform generates one. Auth signup flows (OTP, password, social) always generate platform-managed IDs.

Setting Description Default
auth_methods Enabled auth methods ["otp", "password", "google", "apple"]
kyc_required Require KYC false
kyc_provider KYC provider null
kyc_level Required KYC level null
kyc_required_for_enrollment KYC before palm false
kyc_required_for_transactions Require KYC for certain transactions / limits — [POST-MVP], §7 false
palm_provider Palm verification vendor biowave
palm_match_policy How vendor scores map to match decision (all_thresholds / majority / any) — see Section 8.4 all_thresholds
palm_duplicate_check_enabled Run pre-enrollment similarity check to detect duplicate biometrics — see Section 8.10 false
palm_duplicate_action Action on duplicate detection (reject / flag) reject
require_email_verified Require email verification before palm enrollment false
require_mobile_verified Require mobile verification before palm enrollment false
consent_required Require consent false
data_subject_rights_enabled Enable DSR false
audit_enabled Enable audit logging true

Post-MVP configuration

SMS provider configuration (sms_provider, sender_id) is post-MVP. KYC settings (kyc_*) are configurable now, but KYC integration is [POST-MVP] — see §7.

4.6 Example Configurations

Tenant Auth KYC KYC Provider Palm Vendor
Link Holdings (one tenant — Wallet, Access + sub-products are products within it) All Per-product (Wallet: full / Nafath; Access: none) Nafath X-Telcom BioWave Pass
Link Social All Optional (basic) Onfido X-Telcom BioWave Pass
InvestGlass Not enabled Not enabled - X-Telcom BioWave Pass
PartnerBank OTP Required (full) Nafath X-Telcom BioWave Pass
HealthApp All Required (full) Onfido X-Telcom BioWave Pass

Link's own products share one tenant

Link Wallet, Link Access, and the Access sub-products (Schools, Building, Immigration) are products inside a single Link Holdings tenant, not separate tenants. They share one user directory (mobile = key) and one palm namespace — so a palm enrolled at a Wallet POS is recognized at an Access gate (enroll once, used everywhere). Each product is told apart by its own OAuth client (§6.4), linked service (§10), and device bindings (§9.3). Product-specific policy (e.g. KYC enforcement) is the product's responsibility — the platform surfaces KYC status but does not enforce it (§13.2). External integrators (InvestGlass, PartnerBank, HealthApp, …) stay separate, fully isolated tenants.

4.7 Cross-Tenant Rules

  1. No cross-tenant queries. API calls cannot specify a different tenant_id than the one in their credential. There is no "impersonation" or "on behalf of" mechanism.
  2. No cross-tenant user sharing. A user belongs to exactly one tenant. Distinct integrators are distinct tenants — if the same person uses Link Holdings products and Link Social, they are separate user records in separate tenants. (Link's own first-party products — Wallet, Access + sub-products — are not distinct tenants; they share one Link Holdings tenant, hence one user record + one palm enrollment per person. See §4.6.)
  3. No cross-tenant palm matching. 1:N identification searches only within the requesting tenant's enrolled templates. A palm enrolled in Tenant A will not match in Tenant B. (Within the Link Holdings tenant, Wallet and Access share the namespace by design — that is one tenant, not cross-tenant.)

Tenant isolation on X-Telcom BioWave Pass. The vendor's API has a single global user_id namespace with no tenant scoping, so the platform segments it itself: every user_id sent to the vendor is prefixed with <tenant_slug>__ (e.g. link-holdings__user_456) and stripped on response. Cross-tenant matches become structurally impossible, while within-tenant sharing (Wallet ↔ Access) comes for free — no separate cross-tenant identity layer is needed. See identity-platform-diagrams.md Section 1.3. 4. Platform Admin cross-tenant visibility. Platform Admins can view aggregated metrics across tenants and access individual tenant consoles for support purposes. All such access is audit-logged. 5. Webhook isolation. Each tenant configures its own webhook endpoints. Events from one tenant are never delivered to another tenant's endpoints.

4.8 Tenant Suspension & Deletion

Suspension: - Triggered by Platform Admin (non-payment, security incident, policy violation) - All API calls for the tenant return HTTP 403 with error code tenant_suspended - Data remains intact and readable (Web Console access for Tenant Admin is read-only) - Reactivation by Platform Admin restores full access

Deletion: - Initiated by Platform Admin, subject to a configurable grace period (default: 30 days) - During grace period, tenant is in deactivating state — data is read-only, API access disabled - After grace period: all user data, palm templates (via vendor delete API), OAuth clients, device certificates, audit logs, and consent records are permanently removed - Deletion is irreversible - Audit log of the deletion itself is retained at the platform level (not tenant level) for compliance