Tenancy Conventions
PensionPortal.ai is a multi-tenant SaaS platform. Each tenant is a broker firm that manages one or more pension schemes on behalf of employer clients and their members. All data is strictly isolated between tenants.Tenant Model
- A
brokerIdidentifies the top-level tenant. - All resources (schemes, members, contributions, documents) are owned by a broker.
- Employers are clients of a broker. A single employer can have multiple schemes.
Tenant Resolution
The active tenant is resolved server-side from the authenticated session. There is noX-Tenant-ID header or query parameter — the session token carries the tenant context implicitly.
- You cannot access another tenant’s data by passing a different
brokerIdin the request body. - Attempts to do so return
403 Forbidden. - IDs (scheme IDs, member IDs, etc.) are globally unique UUIDs — but ownership is verified on every request.
Resource Ownership Checks
Every API handler that accepts a resource ID performs an ownership check before returning or mutating data:GET /api/schemes/{schemeId}/kfh verifies the scheme belongs to the calling tenant before returning KFH records.
Cross-Tenant Isolation Guarantees
| Layer | Mechanism |
|---|---|
| Database | All queries include a brokerId WHERE clause; no raw SQL |
| Session | brokerId is embedded in the JWT/session at sign-in; cannot be spoofed |
| API | requireTenant() enforces ownership on all resource reads/writes |
| File Storage | Vercel Blob paths are namespaced: /{brokerId}/{schemeId}/... |
| Audit Log | Every action records actorId, brokerId, schemeId for forensic tracing |
Employer and Scheme Scoping
Many endpoints acceptemployerId or schemeId as query parameters for filtering:
404) — not an error — to avoid leaking the existence of other tenants’ resources.
Tenant Provisioning
New tenants are provisioned by aSuperAdmin. The provisioning process:
- Creates the
brokersrecord - Creates the initial
BrokerAdminuser account - Seeds default configuration (email templates, compliance calendar defaults)
- Sends a welcome email via Resend