-- 261008-mzu — Modul "Nextcloud-Dateien" (Etappe 1). -- -- Zweck: zwei Tabellen und zwei Aufzaehlungen. -- * "NextcloudFilesConfig": Einstellungen der Organisation (Singleton), genau -- eine Nextcloud-Adresse (`baseUrl`, Normalform von normalizeCloudUrl). -- * "NextcloudFilesAccount": das persoenliche Konto eines Benutzers in dieser -- Nextcloud. Gespeichert wird NUR das App-Passwort, AES-256-GCM-verschluesselt -- ueber den CryptoService (`encryptedAppPassword`); das echte Passwort des -- Benutzers wird nie abgelegt. `ncUserId` ist die Kennung in der Nextcloud -- (nicht der eingegebene Anmeldename), `connectedVia` merkt sich den Weg -- (Passwort oder Login Flow v2 fuer Zwei-Faktor-Konten). -- -- Warum das Konto die Adresse mitfuehrt ("baseUrl"): ein App-Passwort gilt nur -- fuer die Nextcloud, die es ausgestellt hat. Es wird nie an einen anderen Host -- geschickt; wechselt die Adresse der Organisation, laufen alle Konten ab -- (status = EXPIRED, oder Konto-baseUrl weicht von der Einstellung ab) und die -- Benutzer verbinden neu. -- -- Der DDL-Teil stammt aus `prisma migrate diff`, damit der Stand ohne Abweichung -- zum Schema passt; die Zeilenschutz-Regeln sind von Hand ergaenzt. -- -- Zeilenschutz (Pflicht — sonst schlaegt rls-coverage.spec.ts fehl): -- "NextcloudFilesConfig" — tenant_isolation_policy nur ueber den Mandanten -- (Verwaltungsdaten der Organisation, wie "DomainsConfig"). -- "NextcloudFilesAccount" — tenant_isolation_policy ueber Mandant UND Benutzer -- (Form aus 20260929140000_reminder): ohne gesetzten Benutzer gilt nur der -- Mandant, mit Benutzer zusaetzlich "userId". Genau das haelt einen Benutzer -- davon ab, je das Konto eines anderen zu lesen. KEINE system_read_policy: -- es gibt keinen Hintergrunddienst, der ueber alle Mandanten liest. -- -- Faellt ein Benutzer weg, faellt sein Konto mit (ON DELETE CASCADE). Das -- App-Passwort bleibt dann in der Nextcloud bestehen (Geraeteliste dort) — das -- ist dokumentiert und fuer Etappe 1 bewusst nicht aufgeraeumt. -- -- Rechte fuer die Anwendungsrolle tessera_app: kommen ueber ALTER DEFAULT -- PRIVILEGES aus 20260909130000_rls_app_role automatisch — 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. -- CreateEnum CREATE TYPE "NextcloudFilesAccountStatus" AS ENUM ('ACTIVE', 'EXPIRED'); -- CreateEnum CREATE TYPE "NextcloudFilesConnectMethod" AS ENUM ('PASSWORD', 'LOGIN_FLOW'); -- CreateTable CREATE TABLE "NextcloudFilesConfig" ( "id" TEXT NOT NULL, "tenantId" TEXT NOT NULL, "baseUrl" TEXT NOT NULL, "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updatedAt" TIMESTAMP(3) NOT NULL, CONSTRAINT "NextcloudFilesConfig_pkey" PRIMARY KEY ("id") ); -- CreateTable CREATE TABLE "NextcloudFilesAccount" ( "id" TEXT NOT NULL, "tenantId" TEXT NOT NULL, "userId" TEXT NOT NULL, "baseUrl" TEXT NOT NULL, "ncUserId" TEXT NOT NULL, "ncDisplayName" TEXT, "encryptedAppPassword" TEXT NOT NULL, "status" "NextcloudFilesAccountStatus" NOT NULL DEFAULT 'ACTIVE', "connectedVia" "NextcloudFilesConnectMethod" NOT NULL, "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updatedAt" TIMESTAMP(3) NOT NULL, CONSTRAINT "NextcloudFilesAccount_pkey" PRIMARY KEY ("id") ); -- CreateIndex CREATE UNIQUE INDEX "NextcloudFilesConfig_tenantId_key" ON "NextcloudFilesConfig"("tenantId"); -- CreateIndex CREATE INDEX "NextcloudFilesConfig_tenantId_idx" ON "NextcloudFilesConfig"("tenantId"); -- CreateIndex CREATE INDEX "NextcloudFilesAccount_tenantId_idx" ON "NextcloudFilesAccount"("tenantId"); -- CreateIndex CREATE UNIQUE INDEX "NextcloudFilesAccount_tenantId_userId_key" ON "NextcloudFilesAccount"("tenantId", "userId"); -- AddForeignKey ALTER TABLE "NextcloudFilesAccount" ADD CONSTRAINT "NextcloudFilesAccount_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; -- Zeilenschutz: nur Mandant (Organisations-Einstellung) ALTER TABLE "NextcloudFilesConfig" ENABLE ROW LEVEL SECURITY; ALTER TABLE "NextcloudFilesConfig" FORCE ROW LEVEL SECURITY; CREATE POLICY tenant_isolation_policy ON "NextcloudFilesConfig" USING ("tenantId" = current_tenant_id()); -- Zeilenschutz: Mandant UND Benutzer (Muster 20260929140000_reminder) ALTER TABLE "NextcloudFilesAccount" ENABLE ROW LEVEL SECURITY; ALTER TABLE "NextcloudFilesAccount" FORCE ROW LEVEL SECURITY; CREATE POLICY tenant_isolation_policy ON "NextcloudFilesAccount" USING ( "tenantId" = current_tenant_id() AND (current_user_id() IS NULL OR "userId" = current_user_id()) );