Перейти до основного вмісту

Multi-tenant architecture

UCRM is multi-tenant at the database layer via Postgres Row-Level Security (RLS). Every tenant-scoped table has an RLS policy that filters by current_setting('app.tenant_id') — set per-request from the authenticated session. Cross-tenant data leakage is impossible without explicit SET ROLE to a privileged role (used only by webhook routing helpers + admin platform tools).

What's tenant-isolated

Every domain table:

  • players + player_wallets + player_tier_history + kyc_history
  • segments + messaging_providers + message_templates
  • campaigns + campaign_variants + message_sends
  • journeys + journey_runs + journey_node_runs
  • bonus_templates + bonus_grants + wagering_events + bonus_campaigns
  • vip_tiers
  • currencies + fx_rates
  • audit_logs
  • adapter_configs

Cross-tenant tables (no RLS):

  • tenants (the SSOT for tenant rows)
  • users + tenant_memberships (auth wiring)
  • webhook_events_processed (idempotency ledger — pre-auth dedupe)
  • __ucrm_migrations (schema version)

How requests are scoped

  1. Admin user authenticates via Clerk → middleware resolves (user_id, tenant_id) from the tenant_memberships row.
  2. The request handler wraps DB access in withTenant(tenantId, async (tx) => …), which BEGIN + SET LOCAL ROLE ucrm_app + SET LOCAL app.tenant_id = $tenant.
  3. Every query inside the closure is RLS-filtered automatically.

For server-to-server endpoints (/v1/internal/*), the caller passes tenant_id in the body + the handler uses withTenant(body.tenant_id, …). The internal-secret middleware authenticates that the caller is a legit UCRM service.

Why this matters

  • No accidental cross-tenant exposure — even a SQL injection that bypassed Drizzle wouldn't leak data outside the tenant context.
  • Per-tenant disaster recovery — drop a single tenant via DELETE FROM tenants WHERE id = ? cascades through every domain table.
  • Self-host friendly — operators can run UCRM with one tenant + still benefit from the isolation pattern (futureproofing for resellers / white-label).