Drei Ebenen
| Ebene | Was | Beispiel | Status |
|---|
| Rollen (Handler) | Wer darf diese Aktion aufrufen | access: { roles: ["Admin"] } | ✅ Gebaut |
| Feld-Access (Spalte) | Wer darf dieses Feld sehen/schreiben | access: { read: ["Admin"] } auf Field | ✅ Gebaut |
| Ownership (Zeile) | Wer darf diese Zeile sehen | access.read auf Entity | → Auth Feature |
Tenant-Isolation ist immer aktiv (WHERE tenantId = …). Ownership ist der feinere Filter innerhalb eines Tenants.
Ownership: Zeilen-Filter
Optional auf der Entity-Definition. Wenn nicht definiert, sieht jeder mit Handler-Zugriff alle Zeilen seines Tenants.
address: { type: "text" },
revenue: { type: "number", access: { read: ["Admin", "Accounting"] } }, // Spalten-Filter
assignedUserId: { type: "number" },
teamId: { type: "number" },
Driver: { where: { assignedUserId: "$user.id" } }, // Nur eigene
Manager: { where: { teamId: "$user.teamId" } }, // Team
Was das Framework macht
| Rolle | Query order.list | Ergebnis |
|---|
| Driver (Max, id=7) | Auto: WHERE tenantId = X AND assignedUserId = 7 | Nur Max’ Orders |
| Manager (Team 1) | Auto: WHERE tenantId = X AND teamId = 1 | Alle Team-1 Orders |
| Admin | Auto: WHERE tenantId = X (kein Ownership-Filter) | Alle Orders |
Gilt automatisch fuer: Queries, CRUD Read, Search, Export. Einmal definieren, ueberall wirksam.
$user Variablen
| Variable | Wert |
|---|
$user.id | User ID aus JWT |
$user.tenantId | Tenant ID aus JWT |
$user.teamId | Team ID (wenn vorhanden) |
$user.roles | Rollen-Array |
Ohne Ownership (Default)
// Kein access.read → jeder mit Handler-Zugriff sieht alle Produkte im Tenant
Boot-Validierung
| Pruefung | Fehler-Beispiel |
|---|
| Referenziertes Feld existiert | access.read.Driver references "assignedUserId" but field does not exist |
$user.* Variable gueltig | "$user.teamId" is not a known PipelineUser property |
| Rolle ohne Rule und nicht “all” | Role "Viewer" has handler access to "order.list" but no ownership rule — add explicit "all" or a where clause |