Multi-tenancy - bitta application bir nechta mijoz, kompaniya yoki organization’ga xizmat qilishi, lekin ularning ma’lumotlari bir-biridan ajratilgan bo‘lishi degani.
SaaS’da tenant odatda bitta mijoz tashkilot bo‘ladi:
Tenant A = Najot Ta'lim
Tenant B = PDP Academy
Tenant C = IT ParkBitta system:
app.company.comlekin ichida har tenant alohida ko‘rinadi:
najot.company.com
pdp.company.com
itpark.company.comBu mavzu quyidagilarni o‘z ichiga oladi: schema-per-tenant vs DB-per-tenant, TenantContext propagation, Dynamic DataSource routing, Hibernate multi-tenancy strategies, va tenant-aware caching.
1. Multi-tenancy nima uchun kerak?
Agar biz SaaS product qilsangiz, har bir mijoz uchun alohida application ko‘tarish qimmat:
client-a-app
client-a-db
client-b-app
client-b-db
client-c-app
client-c-dbBu modelda:
deployment ko‘payadi
monitoring murakkablashadi
upgrade qilish qiyinlashadi
infra xarajat oshadi
bug fix hamma joyga alohida chiqadi
Multi-tenant SaaS’da esa:
bitta app cluster
ko‘p tenant
tenant bo‘yicha data isolation
bitta platform
bitta release pipeline2. Tenant nima?
Tenant - systemdan mustaqil foydalanuvchi tashkilot sifatida foydalanadigan birlik.
Masalan:
Tenant = company
Tenant = school
Tenant = marketplace seller
Tenant = bank branch
Tenant = franchise
Tenant = organizationApplication ichida deyarli hamma narsa tenant bilan bog‘lanadi:
users
orders
payments
products
roles
settings
subscriptions
invoices
audit logs3. Tenant aniqlash usullari
Request kelganda system birinchi bo‘lib so‘raydi:
Bu request qaysi tenantga tegishli?
Tenant quyidagi joylardan olinishi mumkin.
1. Subdomain orqali
najot.myapp.com
pdp.myapp.comBu SaaS’da juda ko‘p ishlatiladi.
Afzallik:
tenant aniq
URL chiroyli
branding uchun qulayKamchilik:
DNS/wildcard certificate kerak
local development biroz murakkab2. Path orqali
/api/tenants/najot/orders
/api/tenants/pdp/ordersAfzallik:
oddiy
test qilish oson
gateway bilan osonKamchilik:
URL har doim tenant bilan ifloslanadi
xavfsizlikda ehtiyot kerak3. Header orqali
X-Tenant-Id: najotAfzallik:
internal API uchun qulay
mobile/backend communication uchun yaxshiKamchilik:
client headerni qalbakilashtirishi mumkin
auth bilan tekshirish shart4. JWT claim orqali
{
"sub": "user-123",
"tenant_id": "najot",
"roles": ["ADMIN"]
}Bu eng xavfsiz variantlardan biri, agar token ishonchli identity provider tomonidan berilgan bo‘lsa.
Spring Security resource server multi-tenancy hujjatida multi-tenant resource server bir nechta bearer token verification strategiyasiga ega bo‘lishi va odatda tenant’ni resolve qilish hamda propagate qilish kerakligi aytiladi. (Home)
4. Eng muhim qoida: tenantni clientdan ko‘r-ko‘rona olmaslik
Yomon:
X-Tenant-Id: pdp
Authorization: user najot tenantiga tegishliAgar system faqat headerga ishonsa, user boshqa tenant ma’lumotiga kira olishi mumkin.
To‘g‘ri yondashuv:
1. User token tekshiriladi
2. Token ichidagi tenant yoki user membership tekshiriladi
3. Requestdagi tenant shu userga ruxsatlimi - tekshiriladi
4. Keyin TenantContext o‘rnatiladiYa’ni:
Tenant resolution - security decision bilan bog‘liq.
5. Multi-tenancy data isolation modellari
Asosiy 3 ta model bor:
1. Shared database + tenant_id column
2. Schema-per-tenant
3. Database-per-tenant6. Shared database + tenant_id column
Bitta database, bitta schema, har table’da tenant_id bor.
orders table
├── id
├── tenant_id
├── customer_id
├── amount
└── statusMisol:
id | tenant_id | amount |
|---|---|---|
1 | najot | 100000 |
2 | pdp | 250000 |
3 | najot | 90000 |
Query:
SELECT *
FROM orders
WHERE tenant_id = 'najot';Afzalliklari
eng sodda
eng arzon
bitta migration
bitta connection pool
analytics/report qilish osonroq
kichik/medium SaaS uchun yaxshiKamchiliklari
data leak xavfi yuqori
har query tenant filter talab qiladi
katta tenant boshqa tenantlarga ta’sir qilishi mumkin
backup/restore tenant bo‘yicha qiyin
compliance talablariga mos kelmasligi mumkinEng katta xavf:
SELECT * FROM orders;Agar tenant_id filter unutilsa, hamma tenant data chiqadi.
7. Shared DB modelda himoya
1. Har table’da tenant_id
CREATE TABLE orders (
id BIGSERIAL PRIMARY KEY,
tenant_id VARCHAR(64) NOT NULL,
amount NUMERIC NOT NULL
);2. Composite index
CREATE INDEX idx_orders_tenant_id_id
ON orders (tenant_id, id);3. Unique constraint tenant bilan
Yomon:
CREATE UNIQUE INDEX ux_users_email
ON users (email);Bu global email unique qiladi.
Yaxshi:
CREATE UNIQUE INDEX ux_users_tenant_email
ON users (tenant_id, email);Chunki turli tenantlarda bir xil email bo‘lishi mumkin yoki bo‘lmasligi biznes qaroriga bog‘liq.
8. Schema-per-tenant
Bitta database, lekin har tenant alohida schema’da.
database: saas_db
schema: tenant_najot
├── orders
├── users
└── payments
schema: tenant_pdp
├── orders
├── users
└── paymentsQuery:
SELECT * FROM tenant_najot.orders;yoki connection uchun current schema o‘rnatiladi.
Afzalliklari
data isolation shared-table modeldan kuchliroq
tenant bo‘yicha backup/restore osonroq
bitta DB server ichida boshqariladi
ba’zi compliance holatlariga mosroqKamchiliklari
migration har schema uchun yuradi
schema soni ko‘payganda boshqarish qiyinlashadi
connection/session current schema to‘g‘ri o‘rnatilishi shart
cross-tenant reporting murakkabroq9. Database-per-tenant
Har tenant uchun alohida database.
tenant_najot_db
tenant_pdp_db
tenant_itpark_dbApplication requestga qarab kerakli database’ga ulanadi.
Afzalliklari
eng kuchli isolation
tenant bo‘yicha backup/restore oson
katta tenantni alohida scale qilish mumkin
compliance uchun yaxshi
noisy neighbor muammosi kamayadiKamchiliklari
eng qimmat
ko‘p DataSource/connection pool kerak
migration murakkab
monitoring murakkab
yangi tenant provisioning murakkab
cross-tenant analytics qiyin10. Model tanlash jadvali
Model | Isolation | Cost | Complexity | Qachon yaxshi |
|---|---|---|---|---|
Shared DB + | Pastroq | Past | Past/O‘rta | Kichik/medium SaaS |
Schema-per-tenant | O‘rta/Yuqori | O‘rta | O‘rta/Yuqori | B2B SaaS, o‘rta isolation |
DB-per-tenant | Yuqori | Yuqori | Yuqori | Enterprise, compliance, yirik tenantlar |
Arxitektor qaror:
Agar tenantlar ko‘p va kichik bo‘lsa → shared DB + tenant_id
Agar B2B va isolation muhim bo‘lsa → schema-per-tenant
Agar enterprise/compliance talab kuchli bo‘lsa → DB-per-tenant11. Hybrid model
Real hayotda ko‘pincha hybrid bo‘ladi:
small tenants → shared database
enterprise tenants → dedicated database
regulated tenants → dedicated clusterMasalan:
Free/Starter plan → shared DB
Business plan → schema-per-tenant
Enterprise/Government → DB-per-tenantBu SaaS monetization bilan ham bog‘liq.
12. TenantContext nima?
TenantContext - hozirgi request qaysi tenantga tegishli ekanini application ichida saqlash usuli.
Imperative Spring MVC’da ko‘p hollarda ThreadLocal ishlatiladi:
public final class TenantContext {
private static final ThreadLocal<String> CURRENT_TENANT = new ThreadLocal<>();
private TenantContext() {}
public static void setTenantId(String tenantId) {
CURRENT_TENANT.set(tenantId);
}
public static String getTenantId() {
return CURRENT_TENANT.get();
}
public static void clear() {
CURRENT_TENANT.remove();
}
}13. Tenant filter
Request boshida tenant aniqlanadi:
@Component
public class TenantFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(
HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain
) throws ServletException, IOException {
try {
String tenantId = resolveTenant(request);
// security check: user shu tenantga tegishlimi?
TenantContext.setTenantId(tenantId);
filterChain.doFilter(request, response);
} finally {
TenantContext.clear();
}
}
private String resolveTenant(HttpServletRequest request) {
return request.getHeader("X-Tenant-Id");
}
}Eng muhim joy:
finally {
TenantContext.clear();
}Agar clear() qilinmasa, thread pool sabab keyingi request eski tenant bilan ishlashi mumkin.
14. Dynamic DataSource Routing
DB-per-tenant yoki ba’zi schema-per-tenant holatlarida requestga qarab DataSource tanlanadi.
Spring’da bu uchun AbstractRoutingDataSource ishlatiladi. Uning determineCurrentLookupKey() metodi odatda thread-bound context’dan lookup key olish uchun implement qilinadi. (Home)
Misol:
public class TenantRoutingDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return TenantContext.getTenantId();
}
}Config:
@Configuration
public class DataSourceConfig {
@Bean
public DataSource dataSource() {
Map<Object, Object> dataSources = new HashMap<>();
dataSources.put("najot", najotDataSource());
dataSources.put("pdp", pdpDataSource());
TenantRoutingDataSource routingDataSource = new TenantRoutingDataSource();
routingDataSource.setTargetDataSources(dataSources);
routingDataSource.setDefaultTargetDataSource(defaultDataSource());
return routingDataSource;
}
}Flow:
Request keldi
↓
TenantFilter tenantId aniqladi
↓
TenantContext.set("najot")
↓
Repository query ishladi
↓
AbstractRoutingDataSource determineCurrentLookupKey()
↓
najot DataSource tanlandi15. Dynamic DataSource’da katta ehtiyot
Muammo 1: Transaction oldin ochilib ketishi
Agar transaction boshlanganda tenant hali set qilinmagan bo‘lsa, noto‘g‘ri database tanlanadi.
To‘g‘ri tartib:
Security filter
Tenant resolution filter
Transaction
RepositoryMuammo 2: Connection pool soni portlab ketadi
Agar 500 tenant va har birida Hikari pool bo‘lsa:
500 tenants × 10 connections = 5000 DB connectionsBu database’ni yiqitishi mumkin.
Yechimlar:
tenantlarni plan bo‘yicha ajratish
lazy DataSource creation
pool size limit
inactive tenant pool close
shared pool strategy
dedicated DB faqat enterprise tenantlargaMuammo 3: Runtime tenant qo‘shish
Yangi tenant ro‘yxatdan o‘tsa, DataSource map yangilanishi kerak.
Oddiy setTargetDataSources static map bilan qiyin bo‘lishi mumkin.
Production’da ko‘pincha:
TenantRegistry
DataSourceProvider
cache with TTL
dynamic pool creation
tenant provisioning workflowkerak bo‘ladi.
16. Hibernate multi-tenancy strategies
Hibernate multi-tenancy uchun asosan quyidagi yondashuvlar ishlatiladi:
DATABASE
SCHEMA
DISCRIMINATOR / tenant_idHibernate hujjatlarida multi-tenancy support second-level cache bilan ishlashi, cache key ichida tenant identifier kodlanishi aytiladi. (docs.hibernate.org)
DATABASE strategy
Har tenant alohida database connection oladi.
tenant_id → databaseYaxshi:
isolation kuchli
enterprise tenantlar uchun yaxshiQiyin:
ko‘p connection pool
migration murakkab
tenant provisioning murakkabSCHEMA strategy
Bitta database, har tenant alohida schema.
tenant_id → schemaImplementation:
MultiTenantConnectionProvider
CurrentTenantIdentifierResolverCurrentTenantIdentifierResolver current tenantni beradi.
DISCRIMINATOR strategy
Bitta table ichida tenant_id column.
tenant_id → row filterBu eng arzon, lekin eng ehtiyot talab qiladigan model.
17. Tenant-aware caching
Cache multi-tenancy’da juda xavfli joy.
Yomon cache key:
@Cacheable(cacheNames = "orders", key = "#orderId")
public Order getOrder(Long orderId) {
...
}Agar orderId = 10 ikki tenantda ham bo‘lsa:
najot order 10
pdp order 10cache noto‘g‘ri tenant data qaytarishi mumkin.
Yaxshi:
@Cacheable(
cacheNames = "orders",
key = "T(com.company.TenantContext).getTenantId() + ':' + #orderId"
)
public Order getOrder(Long orderId) {
...
}Yoki custom KeyGenerator:
@Component("tenantAwareKeyGenerator")
public class TenantAwareKeyGenerator implements KeyGenerator {
@Override
public Object generate(Object target, Method method, Object... params) {
return TenantContext.getTenantId() + ":" +
method.getName() + ":" +
Arrays.deepToString(params);
}
}Usage:
@Cacheable(
cacheNames = "orders",
keyGenerator = "tenantAwareKeyGenerator"
)
public Order getOrder(Long orderId) {
...
}Qoida:
Cache key ichida tenant bo‘lmasa, multi-tenant system’da data leak xavfi bor.
18. Tenant-aware authorization
Multi-tenancy faqat database emas. Authorization ham tenant-aware bo‘lishi kerak.
Masalan user:
Ali → najot tenantida ADMIN
Ali → pdp tenantida VIEWERDemak role global emas, tenantga bog‘langan.
Yomon model:
user_roles:
ali = ADMINYaxshi model:
tenant_user_roles:
ali + najot = ADMIN
ali + pdp = VIEWERSpring Security method-level authorization annotationlar orqali method, class va interface darajasida authorization qo‘llash imkonini beradi. (Home)
Masalan:
@PreAuthorize("@tenantSecurity.canAccessOrder(#orderId, authentication)")
public OrderDto getOrder(Long orderId) {
...
}19. TenantContext propagation: @Async, scheduler, messaging
TenantContext faqat HTTP requestda emas, boshqa joylarda ham kerak bo‘ladi:
@Async
Kafka listener
Rabbit listener
Scheduled job
Domain event listener
WebFlux reactive flow
Batch job@Async muammosi
ThreadLocal boshqa threadda avtomatik o‘tmaydi.
@Async
public void sendEmail() {
TenantContext.getTenantId(); // null bo‘lishi mumkin
}Yechim:
TaskDecorator orqali tenantni ko‘chirishMisol:
public class TenantTaskDecorator implements TaskDecorator {
@Override
public Runnable decorate(Runnable runnable) {
String tenantId = TenantContext.getTenantId();
return () -> {
try {
TenantContext.setTenantId(tenantId);
runnable.run();
} finally {
TenantContext.clear();
}
};
}
}Executor config:
@Bean
public ThreadPoolTaskExecutor applicationTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setTaskDecorator(new TenantTaskDecorator());
return executor;
}20. Reactive WebFlux’da TenantContext
WebFlux’da ThreadLocal xavfli, chunki request bitta thread’da boshlanib boshqa thread’da davom etishi mumkin.
Reactor’da context uchun Context ishlatiladi. Reactor hujjatlarida contextCapture operatori ThreadLocal qiymatlarini subscription vaqtida capture qilib Reactor Context’ga o‘tkazishi mumkinligi aytiladi. (projectreactor.io) Micrometer Context Propagation hujjatida context qiymatlari Reactor context va ThreadLocal orasida ko‘chirilishi mumkinligi ko‘rsatiladi. (Micrometer Documentation)
Reactive yondashuv:
return chain.filter(exchange)
.contextWrite(context -> context.put("tenantId", tenantId));Keyin:
Mono.deferContextual(ctx -> {
String tenantId = ctx.get("tenantId");
return service.process(tenantId);
});Qoida:
Spring MVC → ThreadLocal ishlashi mumkin
Spring WebFlux → Reactor Context ishlatish kerak21. Kafka/Rabbit message’da tenant
Event yoki message yuborilganda tenant ham ketishi kerak.
Yomon:
{
"orderId": 123,
"status": "PAID"
}Yaxshi:
{
"tenantId": "najot",
"orderId": 123,
"status": "PAID"
}Yoki message header:
X-Tenant-Id: najotConsumer:
@KafkaListener(topics = "orders")
public void listen(OrderPaidEvent event) {
try {
TenantContext.setTenantId(event.tenantId());
orderService.handlePaid(event);
} finally {
TenantContext.clear();
}
}Qoida:
Async message’da tenant bo‘lmasa, consumer qaysi tenant database yoki cache bilan ishlashini bilmaydi.
22. Tenant provisioning
SaaS’da yangi tenant yaratish oddiy insert emas. Bu workflow.
Masalan:
1. Tenant record yaratish
2. Plan/subscription tanlash
3. DB/schema yaratish
4. Migration yuritish
5. Default roles yaratish
6. Admin user yaratish
7. Default settings yaratish
8. DNS/subdomain sozlash
9. Welcome email yuborish
10. Tenant status ACTIVE qilishTenant state:
CREATING
MIGRATING
ACTIVE
SUSPENDED
DELETING
FAILEDAgar provisioning o‘rtada yiqilsa, retry va cleanup kerak.
23. Migration strategy
Shared DB
Migration oddiyroq:
Flyway/Liquibase bitta database uchun yuradiSchema-per-tenant
Migration har schema uchun yurishi kerak:
tenant_najot → V1, V2, V3
tenant_pdp → V1, V2, V3
tenant_itpark → V1, V2, V3DB-per-tenant
Migration har database uchun yuradi:
tenant_najot_db
tenant_pdp_db
tenant_itpark_dbBu yerda migration orchestration kerak:
qaysi tenant qaysi versionda?
migration failed bo‘lsa nima bo‘ladi?
rolling migration mumkinmi?
downtime kerakmi?24. Tenant-aware observability
Log, metric va trace tenant-aware bo‘lishi kerak, lekin ehtiyot bilan.
Log:
{
"service": "order-service",
"tenantId": "najot",
"traceId": "abc123",
"message": "Order created"
}Metrics’da esa tenant label ehtiyot talab qiladi.
Yomon:
http_requests_total{tenantId="tenant-123456"}Agar tenantlar juda ko‘p bo‘lsa, metric cardinality portlab ketadi.
Yaxshi:
tenant_tier="enterprise"
region="uz"yoki faqat enterprise tenantlar uchun alohida metric.
Qoida:
Loglarda tenantId foydali. Metrics label’da tenantId ehtiyot bilan ishlatiladi.
25. Tenant-aware rate limiting
SaaS’da har tenantga limit bo‘lishi mumkin:
Free plan: 100 req/min
Business: 1000 req/min
Enterprise: customRate limit key:
tenantId + endpointMasalan:
najot:/api/orders → 1000 req/min
pdp:/api/orders → 100 req/minBu noisy neighbor muammosini kamaytiradi.
26. Tenant-aware feature flags
SaaS’da feature tenant bo‘yicha yoqiladi:
tenant najot → AI_REPORTS enabled
tenant pdp → AI_REPORTS disabled
tenant enterprise-x → BETA_CHECKOUT enabledModel:
tenant_features
├── tenant_id
├── feature_key
└── enabledFeature flag check:
if (featureFlags.isEnabled("AI_REPORTS", TenantContext.getTenantId())) {
// new feature
}27. Tenant configuration
Har tenantda alohida settings bo‘lishi mumkin:
branding
currency
timezone
language
payment provider
notification templates
tax rules
invoice prefix
SLA planBu settings cache qilinadi, lekin cache tenant-aware bo‘lishi shart.
28. Data deletion va compliance
Multi-tenant SaaS’da tenant o‘chirish katta masala.
Shared DB’da:
DELETE FROM orders WHERE tenant_id = 'najot';
DELETE FROM users WHERE tenant_id = 'najot';
DELETE FROM payments WHERE tenant_id = 'najot';Bu xavfli va murakkab.
DB-per-tenant’da:
drop database tenant_najot_dbancha toza, lekin backup retention va audit talablarini hisobga olish kerak.
Arxitektor qaror:
Agar tenant offboarding, compliance, data residency muhim bo‘lsa, DB-per-tenant yoki schema-per-tenant kuchliroq.
29. Data residency
Ba’zi tenantlar data ma’lum regionda turishini talab qiladi:
UZ region
EU region
US regionBu holda tenant registry kerak:
tenant_id → region → cluster/databaseMasalan:
najot → uz-central → db-uz-1
enterprise-eu → eu-west → db-eu-2Request routing:
Gateway tenantni aniqlaydi
tenant regionni topadi
tegishli clusterga yo‘naltiradi30. Real structure: Spring Boot SaaS
com.company.saas
├── tenant
│ ├── Tenant.java
│ ├── TenantRegistry.java
│ ├── TenantContext.java
│ ├── TenantFilter.java
│ └── TenantProvisioningService.java
│
├── order
│ ├── api
│ ├── application
│ ├── domain
│ └── adapter
│
├── payment
│ ├── api
│ ├── application
│ ├── domain
│ └── adapter
│
└── platform
├── security
├── datasource
├── cache
└── observabilitytenant module infrastructure emas, core platform module bo‘ladi.
31. Minimal shared DB implementation
Entity:
@MappedSuperclass
public abstract class TenantAwareEntity {
@Column(name = "tenant_id", nullable = false, updatable = false)
private String tenantId;
@PrePersist
void assignTenant() {
this.tenantId = TenantContext.getTenantId();
}
public String getTenantId() {
return tenantId;
}
}Order:
@Entity
@Table(name = "orders")
public class OrderEntity extends TenantAwareEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private BigDecimal amount;
}Lekin bu yetarli emas. Read querylarda ham tenant filter bo‘lishi kerak.
Repository method:
List<OrderEntity> findByTenantIdAndStatus(String tenantId, OrderStatus status);Yoki specification/global filter yondashuvi ishlatiladi.
32. Eng xavfli xatolar
Xato 1: Tenant filter unutilishi
repository.findById(orderId);Yomon, chunki orderId boshqa tenantga tegishli bo‘lishi mumkin.
Yaxshi:
repository.findByIdAndTenantId(orderId, TenantContext.getTenantId());Xato 2: Cache key’da tenant yo‘q
key = "#id"Yomon.
Yaxshi:
key = "tenantId + ':' + #id"Xato 3: TenantContext clear qilinmaydi
Thread pool sabab bir tenant ikkinchi tenant requestiga sizib o‘tishi mumkin.
Xato 4: Headerga ko‘r-ko‘rona ishonish
X-Tenant-Id har doim token/user membership bilan tekshirilishi kerak.
Xato 5: Migration strategy oldindan o‘ylanmagan
Tenantlar ko‘paygandan keyin schema yoki database migration juda og‘ir bo‘ladi.
Xato 6: Metrics’da tenantId label qilish
Tenantlar ko‘p bo‘lsa, monitoring system cardinality muammosiga tushadi.
33. Arxitektor decision checklist
Multi-tenancy tanlashdan oldin savollar:
Tenantlar soni qancha bo‘ladi?
Har tenant data hajmi qancha?
Enterprise tenant bormi?
Compliance talablari bormi?
Data residency kerakmi?
Tenant bo‘yicha backup/restore kerakmi?
Cross-tenant analytics kerakmi?
Har tenant alohida customization qiladimi?
Rate limit tenant bo‘yicha bo‘ladimi?
Tenant offboarding qanday ishlaydi?34. Qisqa tavsiya
Startup SaaS uchun
Shared DB + tenant_id
strict repository convention
tenant-aware cache
tenant-aware auth
strong testsB2B SaaS uchun
Schema-per-tenant
tenant provisioning workflow
migration orchestration
tenant-aware observabilityEnterprise SaaS uchun
Hybrid model
enterprise tenants → DB-per-tenant
small tenants → shared/schema
data residency
dedicated backup/restore35. Arxitektor xulosasi
Multi-tenancy & SaaS patterns - bu faqat tenant_id column qo‘shish emas.
Bu quyidagi qarorlar majmuasi:
tenant qanday aniqlanadi?
tenant security qanday tekshiriladi?
data isolation qaysi modelda bo‘ladi?
cache tenant-awaremi?
async flow’da tenant yo‘qolmaydimi?
migration qanday yuradi?
tenant provisioning qanday ishlaydi?
observability tenantni ko‘rsatadimi?
enterprise tenantlar qanday ajratiladi?Eng muhim qoida:
Multi-tenant system’da har bir query, cache, message, log, permission va background job tenant kontekstini hisobga olishi kerak.
Qisqa formula:
Tenant resolution
+ Tenant authorization
+ Tenant context propagation
+ Tenant data isolation
+ Tenant-aware cache/security/observability
= Production-ready SaaS architecture