-- 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);
