Skip to content

Tenant DB Context

Prinzip: Ein Weg

ctx.db ist immer tenant-scoped. Der Entwickler bekommt nie ein ungefiltertes DB-Objekt. Es gibt keinen zweiten Weg.

r.writeHandler("order.create", schema, async (event, ctx) => {
// ctx.db ist tenant-scoped — einziges DB-Objekt das es gibt
await ctx.db.insert(orders).values({ name: "test" });
// → tenantId wird automatisch injiziert
await ctx.db.select().from(orders);
// → WHERE tenantId = 42 automatisch
// Es gibt kein ctx.rawDb, kein ctx.unscopedDb
// Man KANN nicht am Tenant vorbei
});

Wie es funktioniert

Pipeline erstellt pro Request ein tenant-scoped DB-Objekt:

// In der Pipeline — einmal pro Request:
const tenantDb = createTenantDb(db, user.tenantId);
ctx.db = tenantDb;

Jede Operation ist automatisch gefiltert:

OperationWas passiert automatisch
ctx.db.select().from(orders)WHERE tenantId = 42
ctx.db.insert(orders).values(data)tenantId: 42 injiziert
ctx.db.update(orders).set(data)WHERE tenantId = 42
ctx.db.delete(orders)WHERE tenantId = 42

System-Scope: Tenant-uebergreifende Features

Manche Features brauchen Zugriff auf alle Tenants (System Dashboard, Tenant Management). Diese deklarieren r.systemScope():

defineFeature("systemDashboard", (r) => {
r.systemScope(); // ctx.db OHNE Tenant-Filter
r.access({ roles: ["SystemAdmin"] }); // Pflicht bei systemScope
r.queryHandler("dashboard.tenantStats", schema, async (query, ctx) => {
// ctx.db → kein Tenant-Filter, sieht alle Daten
// Entwickler ist selbst verantwortlich fuer korrekte Filterung
const stats = await ctx.db.select().from(tenants);
});
});
Feature-Typctx.dbWer darf
Normal (Default)Tenant-scopedPer Handler Access
System (r.systemScope())UnscopedMuss explizit eingeschraenkt werden

Boot-Validierung

PruefungFehler
r.systemScope() ohne r.access()System-scoped Feature "systemDashboard" requires explicit access restriction
r.systemScope() + access: { roles: ["Driver"] }Warning: System-scoped Feature accessible by non-admin role "Driver"

SYSTEM_USER

Migrations, Tenant-Create, Scheduled Jobs die alle Tenants betreffen — diese laufen mit SYSTEM_USER der keinen Tenant-Filter hat. Das ist nie im Feature-Code sondern im Framework-Core.

Siehe: system-user.md