oridecon-tenancy adds first-class multi-tenancy — identifying the current tenant, isolating its data, and propagating its context safely across async calls.
Install it when you need it, not on day one:
uv add oridecon-tenancy# or, from a scaffolded app:oridecon add tenancyConfig lives in application.yaml under tenancy:. Feature types stay in domains/; the tenancy provider is app-root di/ or the module’s provider.py.
For the full configuration reference, see the oridecon-tenancy package docs.
1. Three pillars
Section titled “1. Three pillars”- Resolution — determine which tenant a request belongs to.
- Isolation — separate tenant data (row, schema, or database).
- Enforcement — bind the current context to the resolved tenant and reject requests that violate it.
2. Tenant resolution
Section titled “2. Tenant resolution”Resolution runs at the edge of the request pipeline. Resolvers are tried in order; the first match wins.
| Resolver | Source | Use case |
|---|---|---|
header | X-Tenant-ID header | API integrations, mobile apps |
jwt_claim | a claim in the auth token | OAuth2 / OIDC requests |
subdomain | tenant.app.com | classic SaaS |
path | /api/v1/{tenant}/... | multi-org public portals |
from oridecon import Applicationfrom oridecon.tenancy import TenancyModule, TenancyConfig, ResolutionConfig
app = Application(name="my-saas")app.add_module( TenancyModule.configure( TenancyConfig(resolution=ResolutionConfig(resolvers=["header", "jwt_claim"])) ))Add TenancyModule.configure(...) next to WebModule in create_app(). Pair JWT claims with Authentication.
For tests, TenancyModule.stub() provides an in-memory, header-only setup with no isolation overhead.
3. Context propagation
Section titled “3. Context propagation”Once resolved, a TenantContextMiddleware stores the tenant id in a ContextVar, so it follows your code across await boundaries without being threaded through every function signature. Tenant-aware services and repositories read the current tenant from that context automatically.
See the oridecon-tenancy package docs for the exact context-accessor and tenant-scoping decorator APIs.
4. Data isolation strategies
Section titled “4. Data isolation strategies”| Strategy | How | Trade-off |
|---|---|---|
| Row-level (shared table) | every row carries a tenant_id | cheapest; relies on consistent filtering |
| Schema (shared DB) | one Postgres schema per tenant | stronger isolation, moderate ops overhead |
| Database (separate DBs) | a database per tenant | strongest isolation; highest ops cost |
The isolation strategy is pluggable per tenant via the package’s strategy registry.
5. Enforcement
Section titled “5. Enforcement”Mark routes as tenant-scoped so a request without a resolved, authorized tenant is rejected (401 if no tenant is present, 403 if the user doesn’t belong to it). The tenancy middleware validates the resolved tenant before the handler runs.
Next Steps
Section titled “Next Steps”- Authentication — pairing tenants with JWT claims
- Database & Persistence — tenant-aware repositories
oridecon-tenancypackage — resolvers, isolation, and lifecycle- Project Structure — where generated files land