-- PROJ: retention-rules-engine -- Doku-only (siehe README.md in diesem Verzeichnis) — die tatsächliche -- Ausführung passiert idempotent über internal/storage/retention_rules.go -- initRetentionRulesSchema(), aufgerufen aus (*Store).initSchema(). -- -- GoBD-Aufbewahrungsregeln (retention rules / "Disposition Schedules", -- Namens-/Modellreferenz Alfresco, NICHT dessen Architektur): -- * Eine Regel definiert pro Dokumenttyp (oder tenant-weit als Default mit -- doc_type_id IS NULL) WIE LANGE ein Dokument aufbewahrt werden muss und -- ab WELCHEM Stichtag (trigger_type) die Frist zählt. -- * Der Batch-Job ApplyRetentionRules (CLI: `archivdms retention apply`) -- berechnet retain_until und SETZT es auf documents — er löscht NIEMALS -- und verkürzt eine bereits gesetzte Sperre NIE (GoBD: WORM nur -- verlängerbar). Die eigentliche Vernichtung läuft weiter über den -- Papierkorb + Vier-Augen-Workflow (007_trash.sql). -- * trigger_type: -- document_date -> documents.document_date, sonst created_at -- upload_date -> documents.created_at -- fixed_date -> trigger_reference als YYYY-MM-DD (einmaliger Stichtag) -- event -> NICHT auto-berechnet (z.B. Geschäftsjahresende / -- Vertragsende); Dokumente werden übersprungen, künftiger -- Erweiterungspunkt. -- * retain_until = Stichtag + retention_years Jahre + retention_days Tage. -- Für non-event-Regeln muss mindestens eines von years/days > 0 sein -- (im Go-Store validiert, nicht per CHECK). -- * Präzedenz: doc-typ-spezifische Regel schlägt die tenant-weite Default- -- Regel (doc_type_id IS NULL). UNIQUE(tenant_id, doc_type_id) erzwingt -- höchstens eine Regel pro (Mandant, Dokumenttyp), daher keine -- "strictest wins"-Logik nötig. -- * requires_approval_for_destroy / dsgvo_conflict sind informative Flags für -- das spätere Disposition-Frontend; die Vier-Augen-Pflicht selbst wird -- bereits vom Trash-Flow erzwungen. CREATE TABLE IF NOT EXISTS retention_rules ( id BIGSERIAL PRIMARY KEY, tenant_id BIGINT NOT NULL, doc_type_id BIGINT REFERENCES document_types(id) ON DELETE CASCADE, name TEXT NOT NULL, trigger_type TEXT NOT NULL CHECK (trigger_type IN ('document_date','upload_date','fixed_date','event')), trigger_reference TEXT NOT NULL DEFAULT '', retention_years INT, retention_days INT, legal_basis TEXT NOT NULL DEFAULT '', requires_approval_for_destroy BOOLEAN NOT NULL DEFAULT true, dsgvo_conflict BOOLEAN NOT NULL DEFAULT false, active BOOLEAN NOT NULL DEFAULT true, created_by BIGINT, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), UNIQUE(tenant_id, doc_type_id) ); CREATE INDEX IF NOT EXISTS idx_retention_rules_tenant ON retention_rules(tenant_id) WHERE active;