Type to search pages and rules.

Browse pages

Multitenancy

Multitenancy lets independent customer organizations share one deployment while each keeps isolated data and policy. This page states how the product resolves tenant identity from trusted context, isolates each tenant's data and policy across authorization, storage, caches, reactions, jobs, exports, diagnostics, and recovery, and records the operations that cross tenant lines. A project selects it when separate customers require isolated data or policy in one deployment, because a tenant column without these obligations leaks one customer's data to another.

Markdown23 provisions

Stack: any

Layer: application

Activation#

Activation scope: project.

Applicable specification kinds: None.

The project selects tenancy only when independent customer organizations share one deployment and need isolated data or policy. One organization with many users does not select it: tenants are separate customers, not separate logins.

Baseline Relationship#

This extension replaces no baseline provision. It adds tenant obligations the baseline does not state: identity, isolation, tenant scope, and operations across every boundary a tenant touches. For delegation, this extension adds only the cross-tenant form; a delegated or temporary grant inside one tenant follows litespec/core/access#record-a-delegated-grant-inside-one-tenant-as-a-role-assignment.

It switches on no record type: tenant scope applies to records every project requires, such as decisions, audit records, and exports.

Standards#

Record the Tenant Adoption Decision#

ruleruleguidance
litespec/ext/tenancy#record-the-tenant-adoption-decision
Statement

A consumer selecting tenancy MUST record a decision naming tenant source, storage model, isolation guarantee, administrative access, evolution path, and enumeration bound.

Applies toartifact: record:decision

Why

Tenant source, storage model, isolation guarantee, administrative access, and evolution path interact across every boundary, so one decision records them together before code assumes any of them. The enumeration bound caps how many tenant identifiers an all-tenant record lists.

Checka reviewer answers

Reviewed forThe tenant adoption decision under .litespec/intent/decisions/ names source, storage model, isolation guarantee, administrative access, evolution path, and enumeration bound.

Marked guidance: a reviewer answers this question.

Define Tenant Isolation#

ruleruleguidance
litespec/ext/tenancy#define-tenant-isolation
Statement

A multi-tenant decision MUST define shared-table, schema, or database isolation and state its guarantee and operating trade-off.

Applies toartifact: record:decision

Why

Shared tables, separate schemas, and separate databases isolate differently and operate differently: each choice moves work between queries, migrations, backups, and scaling. Naming the model with its guarantee and its operating trade-off tells every later choice which isolation it can rely on.

Checka reviewer answers

Reviewed forThe adoption decision names shared-table, schema, or database isolation with its guarantee and operating trade-off.

Marked guidance: a reviewer answers this question.

Avoid Unplanned Isolation Models#

ruleruleguidance
litespec/ext/tenancy#avoid-unplanned-isolation-models
Statement

A multi-tenant system MUST NOT mix isolation models without a decision and data evolution plan.

Applies toartifact: any

Why

One part of the product on shared tables and another on separate databases answers which rows each tenant sees two ways. Each mixed model needs its own decision with a data evolution plan, or backup, restore, and incident response each guess which guarantee covers which data.

Checka reviewer answers

Reviewed forEach mixed isolation model traces to a decision with a data evolution plan.

Marked guidance: a reviewer answers this question.

Resolve Tenant Identity from Trusted Context#

ruleruleguidance
litespec/ext/tenancy#resolve-tenant-identity-from-trusted-context
Statement

A trusted host boundary MUST resolve tenant identity from verified claims, host mapping, or another authenticated source.

Applies toartifact: any

Why

The tenant decides which data the request may touch, so only a trusted host boundary resolves it: verified claims, host mapping, or another authenticated source. An identity the caller supplies itself is a choice, not a fact.

Checka reviewer answers

Reviewed forEach trusted host boundary resolves the tenant from verified claims, host mapping, or another authenticated source.

Marked guidance: a reviewer answers this question.

Reject Unrestricted Tenant Input#

ruleruleguidance
litespec/ext/tenancy#reject-unrestricted-tenant-input
Statement

A tenant resolver MUST NOT accept an unrestricted tenant ID from request data.

Applies toartifact: any

Why

A tenant ID taken straight from request data lets any caller name any tenant. Rejecting unrestricted input keeps the request from choosing a data boundary outside its authenticated context.

Checka reviewer answers

Reviewed forThe tenant resolver code accepts a tenant identifier only from an authenticated source, never from request data.

Marked guidance: a reviewer answers this question.

Verify Actor and Target Tenancy#

ruleruleguidance
litespec/ext/tenancy#verify-actor-and-target-tenancy
Statement

A protected multi-tenant operation MUST confirm actor and target tenancy, with the needed permission held at the resolved scope and the target belonging to it.

Applies toartifact: command-handler, query-handler

Why

Checking the caller alone leaves the target unchecked: an authorized caller can still name a resource from another tenant. The operation confirms both sides through one chain: the actor holds a role at the resolved scope, the role allows the permission, the use case declares that permission in its grant, and the target belongs to the same scope.

Checka reviewer answers

Reviewed forThe authorization tests fail a protected operation whose actor and target tenants mismatch.

Marked guidance: a reviewer answers this question.

Scope Every Use Case to Its Tenant Reach#

ruleruleguidance
litespec/ext/tenancy#scope-every-use-case-to-its-tenant-reach
Statement

Every use case in a multi-tenant product MUST declare its tenant scope as own, cross, public, or none in access.

Applies toartifact: record:use-case

Why

The tenant scope bounds which tenant data the call may touch: own stays inside the caller tenant, cross reaches across tenants, public works beyond tenant boundaries, and none touches no tenant data. Without the scope, a read inside one tenant and a read across all tenants look the same. litespec/core/access#scope-every-grant-to-its-tenant-reach states the values.

Example

An expense report declares own, a finance search across companies declares cross, a public catalog declares public, and a health check declares none.

Checka reviewer answers

Reviewed forEach use case declares own, cross, public, or none in its access tenant scope.

Marked guidance: a reviewer answers this question.

Isolate Administrative Cross-Tenant Access#

ruleruleguidance
litespec/ext/tenancy#isolate-administrative-cross-tenant-access
Statement

An administrative cross-tenant operation MUST require a permission the actor holds through a role at platform scope, writing an audit record.

Applies toartifact: command-handler, query-handler

Why

Support and operations sometimes reach across tenants, and that exceptional reach needs exceptional control: a permission held through a role at platform scope, with an audit record for every use. Without both, one support login becomes an unscoped key to every customer's data. Grants that let one tenant act for another follow the delegation extension instead.

Checka reviewer answers

Reviewed forEach administrative cross-tenant use case names a platform-scope permission, and the audit trail holds a record for every cross-tenant run.

Marked guidance: a reviewer answers this question.

Use Selected Tenant Storage Support#

ruleruleguidance
litespec/ext/tenancy#use-selected-tenant-storage-support
Statement

A multi-tenant persistence implementation MUST resolve its tenant at session creation through the selected provider's own tenancy support.

Applies toartifact: any

Why

Session creation is the point that matters: a session opened without a tenant serves an unscoped next query. Resolving the tenant then, through the selected provider's own tenancy support, scopes every query the session runs, so no query carries the concern alone. Adding the filter per query instead leaves every new query one omission away from reading across tenants. The baseline provider resolves the tenant from the registered tenancy at session creation; an Entity Framework Core implementation resolves it when the context is created and applies it through a query filter convention.

Checka reviewer answers

Reviewed forThe session-creation code of each provider resolves the tenant through that provider's tenancy support.

Marked guidance: a reviewer answers this question.

Scope Tenant-Owned Records#

ruleruleguidance
litespec/ext/tenancy#scope-tenant-owned-records
Statement

Every tenant-owned document, query, unique constraint, cache key, outbox record, reaction, job, export, and object-storage path MUST include tenant scope.

Applies toartifact: any

Why

Documents, queries, unique constraints, cache keys, outbox records, reactions, jobs, exports, and object-storage paths each form a boundary where tenants meet. Leaving tenant scope out of any one of them discloses or mixes customer data through exactly that gap.

Checka reviewer answers

Reviewed forThe documents, queries, constraints, cache keys, outbox records, reactions, jobs, exports, and storage paths in code each carry tenant scope.

Marked guidance: a reviewer answers this question.

Apply Cross-Tenant Disclosure Policy#

ruleruleguidance
litespec/ext/tenancy#apply-cross-tenant-disclosure-policy
Statement

A cross-tenant resource response MUST use the documented not-found or forbidden policy.

Applies toartifact: command-handler, query-handler

Why

A caller that names another tenant's resource forces an answer: pretend it does not exist, or admit it exists and refuse. The product documents one policy and applies it to every cross-tenant response, so callers cannot probe for resources through inconsistent answers.

Checka reviewer answers

Reviewed forEach cross-tenant response follows the documented not-found or forbidden policy, shown in the API tests.

Marked guidance: a reviewer answers this question.

Protect Tenant Diagnostics#

ruleruleguidance
litespec/ext/tenancy#protect-tenant-diagnostics
Statement

Errors, logs, metrics, and traces MUST NOT reveal another tenant's business identifiers or data.

Applies toartifact: any

Why

Errors, logs, metrics, and traces travel to readers the API never authorized: support screens, dashboards, and log stores shared across tenants. Scrubbing other tenants' identifiers and data from diagnostics keeps the disclosure policy whole past the API boundary.

Checka reviewer answers

Reviewed forThe error, log, metric, and trace outputs hold no other tenant's identifiers or data.

Marked guidance: a reviewer answers this question.

Scope Tenant Operations#

ruleruleguidance
litespec/ext/tenancy#scope-tenant-operations
Statement

Backup, restore, replay, deletion, export, support access, and incident investigation MUST document one-tenant or all-tenant scope.

Applies toartifact: record:runbook

Why

Backup, restore, replay, deletion, export, support access, and incident investigation each touch more data than one normal request. Documenting each as one-tenant or all-tenant tells the operator how much data the run touches before it starts.

Checka reviewer answers

Reviewed forThe backup, restore, replay, deletion, export, support, and investigation procedures each state one-tenant or all-tenant scope.

Marked guidance: a reviewer answers this question.

Record an All-Tenant Operation#

ruleruleguidance
litespec/ext/tenancy#record-an-all-tenant-operation
Statement

An all-tenant operation MUST record actor, operation, reason, tenant count, and reached tenant identifiers up to the adoption decision bound.

Applies toartifact: command-handler, job

Why

A documented scope states what an operation may touch, not what one run touched, and the run is what a tenant asks about after an incident. An all-tenant run is also the one case where no single tenant's audit trail holds the whole event. The OWASP logging guidance treats an administrative action over many subjects as one event to record: actor, operation, reason, tenant count, and reached tenant identifiers up to the adoption decision bound. When the audit extension is selected, the record is an audit record; otherwise it stays a standalone record.

Example

A support export covering every tenant records the operator, the export, the tenant count, and the incident it was run for.

Checka reviewer answers

Reviewed forThe record of each all-tenant run names actor, operation, reason, tenant count, and reached tenant identifiers up to the adoption bound.

Marked guidance: a reviewer answers this question.

Declare Delegation Grants on Both Sides#

ruleruleguidance
litespec/ext/tenancy#declare-delegation-grants-on-both-sides
Statement

A delegation MUST declare the delegator grant naming who may be acted for and the acting grant naming who may act.

Applies toartifact: record:role

Why

Delegation lets one actor act for another, so a grant on one side alone leaves the other side unreviewed. The delegator grant names the role at its scope that may be acted for and the permissions open to delegation; the acting grant names the role permitted to act and the pairing it acts under. litespec/core/access#grant-across-tenants-only-through-declared-delegation requires both declarations.

Example

An assistant acts for a manager only where the manager delegation grant and the assistant acting grant both name the pairing.

Checka reviewer answers

Reviewed forEach delegation declares a delegator grant naming who may be acted for and an acting grant naming who may act.

Marked guidance: a reviewer answers this question.

Scope Delegated Grants to Named Permissions#

ruleruleguidance
litespec/ext/tenancy#scope-delegated-grants-to-named-permissions
Statement

A delegation MUST name the permissions it delegates, never all permissions.

Applies toartifact: record:role

Why

A delegation open to every permission hands the whole tenant to the acting party: one pairing meant for reading reports also moves money. Naming each delegated permission bounds the pairing to what the delegator intended, and each new permission needs its own review in the pull request before the acting party holds it.

Checka reviewer answers

Reviewed forEach delegation names its delegated permissions, with none open to all permissions.

Marked guidance: a reviewer answers this question.

Bound Every Delegation in Time#

ruleruleguidance
litespec/ext/tenancy#bound-every-delegation-in-time
Statement

A delegation MUST carry an expiry or a revocation path.

Applies toartifact: record:role

Why

A grant with no end outlives its reason: the assistant keeps acting after the engagement ends, and nobody reopens the pairing because no date asks for it. An expiry ends the pairing on its date, and a revocation path ends it on demand. Either way, the end is stated beside the grant instead of left for an incident to discover.

Checka reviewer answers

Reviewed forEach delegation carries an expiry or a revocation path.

Marked guidance: a reviewer answers this question.

Audit Actions Taken Under Delegation#

ruleruleguidance
litespec/ext/tenancy#audit-actions-taken-under-delegation
Statement

An action that an actor takes under delegation MUST record the delegation grant used.

Applies toartifact: command-handler, query-handler

Why

An acted-for action without a marker reads exactly like the delegator's own action, so a reviewer cannot tell who actually acted. Recording the delegation grant used puts the acting party on the record beside the delegator. litespec/ext/audit#record-delegated-administrative-access states the same marker for administrative grants.

Checka reviewer answers

Reviewed forEach action under delegation records the delegation grant used.

Marked guidance: a reviewer answers this question.

Prove Delegated Calls with Scenarios#

ruleruleguidance
litespec/ext/tenancy#prove-delegated-calls-with-scenarios
Statement

A delegation MUST prove an allowed call and a refused call with scenarios.

Applies toartifact: record:scenario

Why

A pairing described only in prose hides where its grant stops: the allowed assistant and the uninvited one read alike. A scenario walking an allowed call and a scenario ending a call without delegation in the derived forbidden result pin the boundary as checked facts. litespec/core/access#prove-hierarchies-derived-trust-and-delegation-with-scenarios requires both scenarios.

Checka reviewer answers

Reviewed forEach delegation proves an allowed call and a refused call with scenarios.

Marked guidance: a reviewer answers this question.

Conventions#

Use Typed Tenant Identities#

conventiondefaultguidance
litespec/ext/tenancy#use-typed-tenant-identities
Default

Represent tenant identity with a strongly typed TenantId.

ReplacementA consumer records a tenant-identity convention naming the type its tenant references carry.

Applies toartifact: any

Why

A bare string tenant ID passes anywhere a string passes: into an actor field, an aggregate key, or a log line. A strongly typed TenantId fails compilation at each of those mistakes instead of failing in production.

Checka reviewer answers

Reviewed forTenant references carry the TenantId type, or the tenant-identity convention names another type.

Marked guidance: a reviewer answers this question.

Use One Tenant Accessor#

conventiondefaultguidance
litespec/ext/tenancy#use-one-tenant-accessor
Default

Use one current-tenant accessor at the trusted host boundary.

ReplacementA consumer records a tenant-access convention naming where its readers find the current tenant.

Applies toartifact: any

Why

Every boundary reads the current tenant, and two accessors can disagree about which tenant is current. One accessor at the trusted host boundary gives every reader the same answer from the same trusted source.

Checka reviewer answers

Reviewed forOne current-tenant accessor serves the trusted host boundary, or the tenant-access convention names where readers find the tenant.

Marked guidance: a reviewer answers this question.

Pass Tenant Scope Explicitly#

conventiondefaultguidance
litespec/ext/tenancy#pass-tenant-scope-explicitly
Default

Pass tenant scope through Application messages or trusted ports rather than ambient Domain request state.

ReplacementA consumer records a tenant-scope convention naming how its Domain receives tenant scope.

Applies toartifact: use-case, port

Why

Domain logic that reads the tenant from ambient request state depends on the host to run at all, which complicates tests and reuse. Passing the scope through Application messages or trusted ports keeps the tenant visible in the call and the Domain free of host state.

Checka reviewer answers

Reviewed forDomain code reads no ambient tenant state, or the tenant-scope convention names how the Domain receives scope.

Marked guidance: a reviewer answers this question.

Record Delegation Grants with Roles#

conventiondefaultguidance
litespec/ext/tenancy#record-delegation-grants-with-roles
Default

Record each delegation grant on the role page that holds it.

ReplacementA consumer records a delegation-records convention naming where its delegation grants live.

Applies toartifact: record:role

Why

The grant qualifies the role: the delegator role names who may be acted for, and the acting role names who may act. Recording each grant on its role page keeps the pairing beside the permission it extends, so a review reads both at once.

Checka reviewer answers

Reviewed forEach delegation grant sits on its role page, or the delegation-records convention names where grants live.

Marked guidance: a reviewer answers this question.

Dependencies#

Packages: Tenancy support for Marten ships in the baseline persistence package. A project that isolates tenants with another provider records a decision and pins that provider in the manifest.

Related extensions: The audit extension owns tamper-resistant evidence when an all-tenant run needs an audit record. The plans extension owns entitlements when tenants buy different tiers.

Guides: None.