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:
4.4 Tenant Provisioning¶
Process:
- Platform Admin creates tenant via Web Console (or platform API)
- Platform generates
tenant_id(slug format, e.g.,link-wallet,investglass) - Admin configures initial settings (auth methods, KYC provider, palm vendor — as defined in Section 4.5)
- Platform creates first Tenant Admin account (email + temporary password)
- 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¶
- No cross-tenant queries. API calls cannot specify a different
tenant_idthan the one in their credential. There is no "impersonation" or "on behalf of" mechanism. - 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.)
- 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_idnamespace with no tenant scoping, so the platform segments it itself: everyuser_idsent 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. Seeidentity-platform-diagrams.mdSection 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