Skip to content

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.

Şirketler (tenant):

  • Tablo: organizations
  • Önemli alanlar:
    • subdomain: tenant ana anahtarı (ör. quaflow)
    • allowedDomains: kurumsal e-posta domain whitelist’i
    • seatLimit: 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)

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-host
    • x-forwarded-host
    • host
    • (varsa) MF-Original-URL hostname
    • request.url hostname

Bu çözümleme getTenantByRequest(db, request) içinde organizations.subdomain ile DB’den tenant çekmek için kullanılır.

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ışı:

  1. Better Auth session kontrolü (yoksa /${lang}/login?intent=company)
  2. Tenant çözümleme (yoksa 403)
  3. 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:

  1. Tenant hint endpoint’i: GET /api/tenant-hint?host=<hostname>
  2. 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.