Multi-tenancy jest end-to-end ownership boundary
Kolumna tenant_id jest użyteczna, ale nie stanowi jeszcze multi-tenant architecture. Tenant ownership musi przetrwać każdą ścieżkę produktu: authentication, authorization, database queries, background jobs, files, caches, analytics, billing, integrations, exports i audit. System jest bezpieczny dopiero wtedy, gdy tenant context nie może po cichu zniknąć między tymi warstwami.
Wybierz isolation według ryzyka i operations
| Model | Mocna strona | Trade-off | Typowe zastosowanie |
|---|---|---|---|
| Shared DB / shared schema | Efektywne operations | Wymaga silnej query discipline | Większość B2B SaaS |
| Shared DB / schema per tenant | Większa separacja strukturalna | Rosnąca złożoność migrations | Mniejsza liczba tenantów / special requirements |
| Database per tenant | Mocna infrastructure isolation | Koszt provisioning, migrations i pooling | High-value lub regulated tenants |
| Hybrid | Różne tiers według ryzyka | Większa platform complexity | Enterprise SaaS z opcjami isolation |
Isolation nie jest drabiną dojrzałości, na której database-per-tenant zawsze jest „lepsze”. Wybór wynika z threat model, wymagań kontraktowych, skali, operational tooling i unit economics.
Rozwiązuj tenant context przy trust boundary
Current organization wyprowadzaj z authenticated membership, subdomain/session lub innego zaufanego mechanizmu. Nie autoryzuj dostępu tylko na podstawie organization ID z request body. Serwer powinien potwierdzić membership aktora przed utworzeniem tenant-scoped services.
Dobre rozwiązanie przekazuje typed tenant context przez service boundaries tak, aby repository i domain commands nie mogły działać bez niego. Brak context staje się wtedy błędem implementacji zamiast niewidzialnym ryzykiem data leak.
Propaguj context przez asynchronous work
Queues i schedulery są częstym miejscem utraty granicy. Background job powinien zawierać tenant identity, resource identity oraz initiating actor/run tam, gdzie jest potrzebny, a w chwili execution ponownie walidować current state. Nie polegaj na process-local „current tenant”.
Ta sama zasada dotyczy webhooków. External customer, subscription czy installation mapuj do internal tenant przez server-owned records przed zmianą business state.
Database constraints powinny wzmacniać application boundaries
W shared tables każdy tenant-owned record potrzebuje jednoznacznego ownera oraz indeksów wspierających tenant-scoped access. Composite uniqueness często powinna zawierać tenant ID, aby jeden klient nie rezerwował namespace innego tenanta.
PostgreSQL Row-Level Security może dodać defense in depth dla wybranych tabel. Jest skuteczny, jeśli connection/transaction niezawodnie otrzymuje właściwy tenant context, a privileged roles są świadomie kontrolowane. RLS nie zastępuje poprawnych joins, ownership model ani application authorization.
Traktuj migrations i provisioning jako capabilities produktu
Schema changes dotyczą każdego tenanta. Migrations powinny być backwards compatible tam, gdzie możliwe są rolling deployments, obserwowalne i recoverable. Modele database/schema-per-tenant potrzebują dodatkowo orchestration dla provisioning, version drift i failed upgrades.
Samo tenant creation jest workflow: organization record, default roles, billing customer, feature configuration, storage namespace i integration secrets muszą uzyskać gotowość atomowo albo przez jawny provisioning state.
Kontroluj noisy-neighbor risk
Isolation dotyczy także performance. Stosuj per-tenant quotas lub scheduling tam, gdzie jeden klient może zużyć nieproporcjonalnie dużo queues, AI tokens, exports, storage lub API calls. Tenant identity powinna być obecna w rate limiting i operational telemetry.
Backups, exports i deletion muszą zachować tenant scope
Multi-tenant product prędzej czy później potrzebuje data export, account closure, legal retention albo restore. Te ścieżki projektuj wcześnie. Export nie może polegać na UI filter jako mechanizmie isolation. Deletion powinien jawnie wyliczać tenant-owned domains i integrations, aby orphaned data nie pozostawały bezterminowo.
First-party patterns z vertical SaaS
W Softech stosujemy te granice w multi-location operational software. Rentya rozdziela facility/operator data, users, inventory i booking operations w kontekście SaaS marketplace, a TECHPRES.app łączy customer locations, assets, field measurements i service workflows. Domeny są inne, ale wymóg architektoniczny ten sam: tenant context musi towarzyszyć każdemu operational record i action.
Te wzorce są podstawą naszej pracy nad SaaS development i business systems.
Tenant-isolation test matrix
- Odczyt resource innego tenanta przez guessed ID.
- Write poprawnego resource ID z błędnym organization context.
- Wykonanie starego queued job po usunięciu membership.
- Replay webhooka zmapowanego do innego external customer.
- Dostęp do cached data po zmianie organization.
- Generowanie exports/reports z mixed tenant records.
- Restore lub migration jednego tenanta bez ekspozycji drugiego.
- Privileged support operations z weryfikacją audit evidence.
