← Tenancy

TENANCY FEATURE

Data Isolation

The same repository call returns a different dataset when tenant context changes, without hand-written WHERE clauses in business code.

Switch tenant and the result set changes instantly. The point is not the table itself, but the fact that isolation happens below your business query.

This page demonstrates tenant-scoped persistence as a platform guarantee. Repositories ask for products; the framework decides which tenant slice is allowed to come back.

Switch tenant, keep the same query

The repository method does not change when the tenant changes. Only the active context changes.

Filtering belongs to the platform layer

The tenant WHERE clause is injected by the framework, so business queries are not polluted with isolation boilerplate.

The result should feel obviously different

A convincing demo must show that each tenant sees a distinct slice of data, not just a hidden architecture rule.

17 products for tenant acme

No products yet for this tenant. Run semitexa:demo:seed.

ORM automatic WHERE injection

Add #[TenantScoped(strategy: 'same_storage')] to any model and the framework enforces tenant scoping automatically across reads and writes.

SELECT * FROM demo_products
WHERE tenant_id = ?
LIMIT 5
#[FromTable(name: 'demo_products')]
#[TenantScoped(strategy: 'same_storage')]
final class DemoProductResource
{
    // No manual filtering. No forgotten WHERE clauses.
}

Three isolation strategies

same_storage

Shared table, automatic WHERE tenant_id = ?

connection_switch

Separate database per tenant, connection swapped on context change

separate_schema

Separate schema per tenant, search-path switching

The strategy is per-model, so the same app can mix lightweight shared-table isolation with stricter tenant storage boundaries where needed.