B2B Company (Tenant) Mimarisi
Subdomain tabanlı tenant çözümleme, /company paneli rotaları, RBAC ve lokal geliştirme notları.
Achidemy B2B (Business) akışı, her şirketi bir tenant olarak ele alır ve tenant’ı subdomain üzerinden çözer:
- Lokal:
http://quaflow.localhost:8787/en/... - Prod:
https://quaflow.achidemy.net/en/...(örnek tenant subdomain)
Bu sayfada tenant çözümleme, /company paneli, roller ve geliştirme ortamına özgü “wrangler host ezme” probleminin nasıl çözüldüğü anlatılır.
Veritabanı Modeli
Section titled “Veritabanı Modeli”Şirketler (tenant):
- Tablo:
organizations - Önemli alanlar:
subdomain: tenant ana anahtarı (ör.quaflow)allowedDomains: kurumsal e-posta domain whitelist’iseatLimit: koltuk limiti (Stripe quantity)stripeCustomerId,stripeSubscriptionId,isActive
Üyelik/RBAC:
- Tablo:
organization_members - Roller:
owner: şirketi oluşturan kullanıcı (tam yetki)admin: İK/Yönetici (panel erişimi)member: çalışan (panel erişimi yok)
Tenant Çözümleme (Subdomain)
Section titled “Tenant Çözümleme (Subdomain)”Dosya: app/lib/tenant.ts
Tenant çözümleme mantığı:
- Önce dev ortamında “tenant hint” cookie’si varsa onu kullanır (
__tenant_subdomain) - Aksi halde host bilgisi için header’ları tarar:
x-original-hostx-forwarded-hosthost- (varsa)
MF-Original-URLhostname request.urlhostname
Bu çözümleme getTenantByRequest(db, request) içinde organizations.subdomain ile DB’den tenant çekmek için kullanılır.
/company Paneli (Route Guard + RBAC)
Section titled “/company Paneli (Route Guard + RBAC)”Dosyalar:
app/routes/company.tsx(layout + guard)app/routes/company._index.tsx(dashboard)- diğer sayfalar:
company.directory.tsx,company.billing.tsx,company.settings.tsx…
Guard akışı:
- Better Auth session kontrolü (yoksa
/${lang}/login?intent=company) - Tenant çözümleme (yoksa 403)
requireOrgAdmin(db, userId, orgId)ile RBAC (admin veya owner) kontrolü
Lokal Geliştirme: Wrangler 8787 “Host ezme” sorunu
Section titled “Lokal Geliştirme: Wrangler 8787 “Host ezme” sorunu”Wrangler dev bazı ortamlarda Worker’a gelen isteklerde Host header’ını 127.0.0.1 gibi gösterip gerçek subdomain’i iletmez. Bu durumda server-side tenant çözümlemesi bozulur.
Bu repo’da bunun için iki katmanlı bir çözüm var:
- Tenant hint endpoint’i:
GET /api/tenant-hint?host=<hostname> - Root revalidate: Tarayıcı
*.localhostüzerinde çalışıyorsa bu endpoint çağrılır; cookie yazıldıktan sonra root loader revalidate edilir.
Detaylı akış için Yerelde Subdomain/Tenant Geliştirme sayfasına bakın.