feat(aether): initial commit – self-hosted Cloud, Phasen 1–7
Go-Backend (chi, pgx, golang-migrate) + React/TS-Frontend als PWA. Enthalten: Auth inkl. OIDC, Dateien mit Versionen und Papierkorb, Freigaben (Links + intern), WebDAV, Gruppenordner, Admin/Theming, Volltextsuche mit OCR, eigener PDF-Betrachter und WOPI-Office (Collabora/OnlyOffice). Nicht im Repo: deploy/.env (Sitzungsschlüssel, DB- und Admin-Passwort) sowie alle Daten- und Build-Verzeichnisse – siehe .gitignore. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
commit
31a027c93a
225 files changed
+38042
No files matched your search
@@ -0,0 +1,51 @@
|
||||
-- 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;
|
||||
Reference in new issue
Block a user