Data · infrastructure/db

Production-ready adapter

Prisma,
with guardrails.

The classic multi-tenant bug is a query that forgets its organizationId and quietly serves another customer’s rows. UseDeploy wraps the Prisma client in a tenant guard that turns that mistake into an exception at execution time — not a data breach in production.

Two clients: guarded by default

Repositories get the guarded client. Any read or mutation on a tenant-scoped model whose where clause does not constrain organizationId throws TenantScopeViolationError. A separate, explicitly-named system client exists for the legitimate cross-tenant paths (workers, token lookups, GDPR export) so every bypass is greppable.

prisma-client.ts
 1  export const getPrismaClient = (): PrismaClient => {
 2    if (!guardedClient) {
 3      guardedClient = applyTenantGuard(getBaseClient());
 4    }
 5    return guardedClient;
 6  };
 7  
 8  // Unguarded, explicit, greppable — for workers / token lookups only:
 9  export const getSystemPrismaClient = () => getBaseClient();

Why it matters

Fails loudly, not silently

Forgetting the org scope in new code throws on first execution instead of leaking cross-tenant rows — the failure mode you want.

Explicit model list

TENANT_SCOPED_MODELS enumerates every org-owned model. Adding a new one to the schema means adding it here — a deliberate, reviewable step.

One connection pool

The guarded and system clients share the base client’s pool, so the guard costs no extra connections.

Pooler-friendly

DIRECT_URL is supported for Supabase pgbouncer and similar poolers, where migrations need a direct connection.

Configuration reference

Environment variables

  • DATABASE_URLrequired

    Postgres connection string

  • DIRECT_URLoptional

    direct connection when DATABASE_URL is a pooler

Where it lives

  • apps/server/src/infrastructure/db/prisma-client.ts
  • apps/server/src/infrastructure/db/tenant-guard.ts

Multi-tenant data that fails safe.

Build on a Prisma client that turns a forgotten org scope into an exception, not a leak.