-- Interne Freigaben: Ordner oder Datei an einen anderen Nutzer oder eine Gruppe -- geben, ohne dass die Bytes umziehen. Der Empfänger sieht sie virtuell unter -- „Geteilt mit mir"; auf der Platte bleibt alles beim Eigentümer. -- -- Abweichung vom Projektplan: dort war eine polymorphe Tabelle skizziert -- (subject_type + subject_id als Text/UUID ohne Fremdschlüssel). Hier stattdessen -- vier nullbare Fremdschlüssel mit CHECK-Bedingung. Grund: polymorph kann die -- Datenbank nichts erzwingen – ein gelöschter Nutzer oder Ordner hinterließe -- Einträge, die auf nichts mehr zeigen, und aus so einer Leiche später eine -- Freigabe für einen neu vergebenen Namen zu machen wäre ein Sicherheitsloch. -- Mit echten Fremdschlüsseln räumt ON DELETE CASCADE das von selbst auf. CREATE TABLE acl_entries ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), -- Empfänger: genau eines von beiden. subject_user_id UUID REFERENCES users(id) ON DELETE CASCADE, subject_group_id UUID REFERENCES groups(id) ON DELETE CASCADE, -- Freigegebene Ressource: genau eines von beiden. resource_folder_id UUID REFERENCES folders(id) ON DELETE CASCADE, resource_file_id UUID REFERENCES files(id) ON DELETE CASCADE, permission TEXT NOT NULL CHECK (permission IN ('read', 'write')), -- Wer die Freigabe erteilt hat. SET NULL statt CASCADE: die Freigabe soll -- nicht verschwinden, nur weil das Konto des Erteilers gelöscht wurde. granted_by UUID REFERENCES users(id) ON DELETE SET NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), CONSTRAINT acl_one_subject CHECK (num_nonnulls(subject_user_id, subject_group_id) = 1), CONSTRAINT acl_one_resource CHECK (num_nonnulls(resource_folder_id, resource_file_id) = 1) ); -- Zwei Freigaben derselben Ressource an denselben Empfänger wären mehrdeutig: -- welches Recht gilt dann? Partielle Unique-Indizes, weil NULL in einem -- gewöhnlichen UNIQUE nicht mit sich selbst kollidiert. CREATE UNIQUE INDEX idx_acl_user_folder ON acl_entries (subject_user_id, resource_folder_id) WHERE subject_user_id IS NOT NULL AND resource_folder_id IS NOT NULL; CREATE UNIQUE INDEX idx_acl_user_file ON acl_entries (subject_user_id, resource_file_id) WHERE subject_user_id IS NOT NULL AND resource_file_id IS NOT NULL; CREATE UNIQUE INDEX idx_acl_group_folder ON acl_entries (subject_group_id, resource_folder_id) WHERE subject_group_id IS NOT NULL AND resource_folder_id IS NOT NULL; CREATE UNIQUE INDEX idx_acl_group_file ON acl_entries (subject_group_id, resource_file_id) WHERE subject_group_id IS NOT NULL AND resource_file_id IS NOT NULL; -- Die Zugriffsprüfung läuft bei jedem Request; sie fragt nach Ressource. CREATE INDEX idx_acl_folder ON acl_entries (resource_folder_id) WHERE resource_folder_id IS NOT NULL; CREATE INDEX idx_acl_file ON acl_entries (resource_file_id) WHERE resource_file_id IS NOT NULL; -- „Geteilt mit mir" fragt nach Empfänger. CREATE INDEX idx_acl_subject_user ON acl_entries (subject_user_id) WHERE subject_user_id IS NOT NULL; CREATE INDEX idx_acl_subject_group ON acl_entries (subject_group_id) WHERE subject_group_id IS NOT NULL;