Git-Repository für bestehenden archivdms-Code initialisiert, Branch-/Commit-Konvention (feature/<ticket>-<slug>-Branches, Ticket-Prefix in Commit-Nachricht) etabliert.
79 lines
3.8 KiB
SQL
79 lines
3.8 KiB
SQL
-- PROJ: permission-model-group-acl
|
|
-- Doku-only (siehe README.md in diesem Verzeichnis) — die tatsächliche
|
|
-- Ausführung passiert idempotent über internal/storage/permissions.go
|
|
-- initPermissionsSchema(), aufgerufen aus (*Store).New().
|
|
--
|
|
-- Berechtigungsmodell (gruppenaufgelöste, geschichtete Dokument-ACL):
|
|
-- Zugriff wird NIE direkt pro User vergeben, sondern über permission_groups.
|
|
-- Auflösung über drei Ebenen, spezifischer schlägt allgemeiner:
|
|
-- 1. document_grants (pro Dokument, 'deny' entfernt eine Gruppe komplett)
|
|
-- 2. tag_grants (über die Tags des Dokuments)
|
|
-- 3. document_type_grants (über documents.doc_type_id)
|
|
-- Ergebnis wird von RecomputeVisibility() nach document_visibility
|
|
-- materialisiert (DELETE+INSERT je Dokument in einer Transaktion).
|
|
--
|
|
-- Rollen bleiben Außengrenze: superadmin sieht alles tenant-übergreifend,
|
|
-- domain_admin sieht per Default alles im eigenen Tenant (bypasst ACL), nur
|
|
-- Rolle 'user' wird in ListDocuments gegen document_visibility gefiltert.
|
|
--
|
|
-- RecomputeVisibility MUSS neu laufen, wenn sich Grants, die Tags eines
|
|
-- Dokuments (AttachTag/DetachTag) oder der Dokumenttyp (SetDocumentDocType)
|
|
-- ändern — diese Aufrufe sind im Go-Code angehängt.
|
|
|
|
-- Hinweis: tenant_id / user_id / granted_by tragen bewusst KEINE FK auf
|
|
-- tenants(id) bzw. users(id) — konsistent mit documents/taxonomy (plain BIGINT
|
|
-- tenant_id) und weil tenants/users von anderen Stores NACH storage.New()
|
|
-- angelegt werden (Reihenfolge in cmd/archivdms/main.go). Tenant-Ownership wird
|
|
-- applikationsseitig geprüft (permissions.go).
|
|
CREATE TABLE IF NOT EXISTS permission_groups (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
tenant_id BIGINT NOT NULL,
|
|
name TEXT NOT NULL,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
UNIQUE (tenant_id, name)
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS permission_group_members (
|
|
group_id BIGINT NOT NULL REFERENCES permission_groups(id) ON DELETE CASCADE,
|
|
user_id BIGINT NOT NULL,
|
|
PRIMARY KEY (group_id, user_id)
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS document_type_grants (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
tenant_id BIGINT NOT NULL,
|
|
doc_type_id BIGINT NOT NULL REFERENCES document_types(id) ON DELETE CASCADE,
|
|
group_id BIGINT NOT NULL REFERENCES permission_groups(id) ON DELETE CASCADE,
|
|
access TEXT NOT NULL DEFAULT 'read' CHECK (access IN ('read','write')),
|
|
UNIQUE (doc_type_id, group_id)
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS tag_grants (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
tenant_id BIGINT NOT NULL,
|
|
tag_id BIGINT NOT NULL REFERENCES tags(id) ON DELETE CASCADE,
|
|
group_id BIGINT NOT NULL REFERENCES permission_groups(id) ON DELETE CASCADE,
|
|
access TEXT NOT NULL DEFAULT 'read' CHECK (access IN ('read','write')),
|
|
UNIQUE (tag_id, group_id)
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS document_grants (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
tenant_id BIGINT NOT NULL,
|
|
document_id BIGINT NOT NULL REFERENCES documents(id) ON DELETE CASCADE,
|
|
group_id BIGINT NOT NULL REFERENCES permission_groups(id) ON DELETE CASCADE,
|
|
access TEXT NOT NULL CHECK (access IN ('read','write','deny')),
|
|
granted_by BIGINT NOT NULL,
|
|
granted_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
UNIQUE (document_id, group_id)
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS document_visibility (
|
|
document_id BIGINT NOT NULL REFERENCES documents(id) ON DELETE CASCADE,
|
|
group_id BIGINT NOT NULL REFERENCES permission_groups(id) ON DELETE CASCADE,
|
|
access TEXT NOT NULL CHECK (access IN ('read','write')),
|
|
PRIMARY KEY (document_id, group_id)
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_doc_visibility_group ON document_visibility(group_id, document_id);
|
|
CREATE INDEX IF NOT EXISTS idx_pgm_user ON permission_group_members(user_id, group_id);
|