-- 260929-dzu — Eigene Module fuer jeden Benutzer: persoenliche Eintraege. -- -- Zweck: jeder Benutzer darf eigene Seitenleisten-Eintraege anlegen, die nur -- er selbst sieht. Die Spalte "ownerUserId" unterscheidet: NULL = gemeinsamer -- Eintrag (vom Administrator, fuer alle sichtbar, bisheriges Verhalten), -- gesetzt = persoenlicher Eintrag dieses Benutzers. Faellt der Benutzer weg, -- fallen seine Eintraege mit (ON DELETE CASCADE). Bestehende Zeilen bleiben -- gemeinsam (NULL). -- -- Zeilenschutz: Muster "SearchProvider" (20260911120000_rls_user_dimension_ -- personal_tables) — Spalte mit NULL = gemeinsame Zeile. Die eine Regel -- "tenant_isolation_policy" (aus 20260929120000, ohne Benutzerdimension) wird -- durch vier nach Befehl getrennte Regeln ersetzt (Praezedenz 260910-jab (3)): -- ein einzelner USING-Ausdruck, der die gemeinsame Zeile zum Lesen einschliesst, -- wuerde sie sonst auch zum Aendern/Entfernen freigeben. -- SELECT: Mandant UND (kein Benutzer gesetzt ODER gemeinsame Zeile ODER -- eigene Zeile). -- INSERT/UPDATE/DELETE: Mandant UND (kein Benutzer gesetzt ODER eigene -- Zeile). Ein Benutzerkontext kann gemeinsame Zeilen also NICHT -- schreiben; der Administrator-Weg fuer gemeinsame Eintraege bindet -- deshalb ohne Benutzer (`forTenant(prisma, tenantId)`), die -- Rollenpruefung liegt im Controller/Dienst. -- Die Regelnamen sind neu (vier statt eine), rls-coverage.spec.ts fordert nur -- mindestens eine Regel je Tabelle mit eingeschaltetem RLS. -- -- Rechte fuer tessera_app kommen ueber ALTER DEFAULT PRIVILEGES aus -- 20260909130000_rls_app_role — hier nichts zu tun. -- -- WICHTIG: wie alle RLS-Regeln dieses Schemas wirken diese erst, wenn die -- Anwendung als Rolle ohne Umgehungsrecht verbindet (Schalter heute AUS, siehe -- docs/mandantentrennung-datenbankrolle.md). Bis dahin tragen die -- Anwendungspruefungen im Dienst den Schutz allein. ALTER TABLE "CustomModule" ADD COLUMN "ownerUserId" TEXT; CREATE INDEX "CustomModule_tenantId_ownerUserId_idx" ON "CustomModule"("tenantId", "ownerUserId"); ALTER TABLE "CustomModule" ADD CONSTRAINT "CustomModule_ownerUserId_fkey" FOREIGN KEY ("ownerUserId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; DROP POLICY tenant_isolation_policy ON "CustomModule"; CREATE POLICY tenant_user_read_policy ON "CustomModule" FOR SELECT USING ( "tenantId" = current_tenant_id() AND ( current_user_id() IS NULL OR "ownerUserId" IS NULL OR "ownerUserId" = current_user_id() ) ); CREATE POLICY tenant_user_insert_policy ON "CustomModule" FOR INSERT WITH CHECK ( "tenantId" = current_tenant_id() AND (current_user_id() IS NULL OR "ownerUserId" = current_user_id()) ); CREATE POLICY tenant_user_update_policy ON "CustomModule" FOR UPDATE USING ( "tenantId" = current_tenant_id() AND (current_user_id() IS NULL OR "ownerUserId" = current_user_id()) ) WITH CHECK ( "tenantId" = current_tenant_id() AND (current_user_id() IS NULL OR "ownerUserId" = current_user_id()) ); CREATE POLICY tenant_user_delete_policy ON "CustomModule" FOR DELETE USING ( "tenantId" = current_tenant_id() AND (current_user_id() IS NULL OR "ownerUserId" = current_user_id()) );