docs: GoBD-Checklist auf aktuellen Stand bringen (PROJ-52, PROJ-56c)
Punkt 1 (Vollständigkeit) war noch als "Teilweise" markiert, obwohl PROJ-52 (Reconciliation-Report) das inzwischen abdeckt. Punkt 7 (Löschsperre) beschrieb noch den alten Purge() ohne Markierungspflicht; ergänzt um PROJ-56c Cron-Purge, der nur retain_until < NOW() UND marked_for_deletion löscht.
This commit is contained in:
@@ -31,13 +31,13 @@ Integritätsprüfung per SHA-256 (PROJ-18), Export in EML/MBOX/ZIP/CSV (PROJ-12,
|
|||||||
|
|
||||||
| # | Anforderung | Status | Begründung / Codeverweis | Empfehlung |
|
| # | Anforderung | Status | Begründung / Codeverweis | Empfehlung |
|
||||||
|---|---|---|---|---|
|
|---|---|---|---|---|
|
||||||
| 1 | **Vollständigkeit** – 100% Ein-/Ausgang archiviert | ⚠️ Teilweise | SMTP-BCC-Journal (PROJ-4), IMAP/POP3-Import (PROJ-3/14), EML/MBOX-Import (PROJ-2). SMTP-Daemon (`internal/smtpd/smtpd.go`) gibt bei Storage-Fehler `452` zurück → MTA-Retry, kein Verlust beim Empfang. Kein zentraler "Vollständigkeits-Reconciliation"-Mechanismus zwischen Mailserver-Log und Archiv. | Prüfung/Abgleich-Report (z.B. erwartete vs. archivierte Anzahl pro Tag) als neues Feature vorschlagen. |
|
| 1 | **Vollständigkeit** – 100% Ein-/Ausgang archiviert | ✅ Erfüllt | SMTP-BCC-Journal (PROJ-4), IMAP/POP3-Import (PROJ-3/14), EML/MBOX-Import (PROJ-2). SMTP-Daemon (`internal/smtpd/smtpd.go`) gibt bei Storage-Fehler `452` zurück → MTA-Retry, kein Verlust beim Empfang. Vollständigkeits-Reconciliation (PROJ-52, deployt 2026-07-04): täglicher Cron-Report `internal/reconciliation/` zählt archivierte Mails je Quelle, Alert bei >50% Abweichung vom 7-Tage-Schnitt, Audit-Eintrag `reconciliation_anomaly`. | – |
|
||||||
| 2 | **Frühzeitigkeit** – Archivierung bei Eingang/Ausgang | ✅ Erfüllt | SMTP-BCC-Journaling (PROJ-4) archiviert synchron beim Empfang/Versand; IMAP-Cron-Sync (PROJ-8) ergänzt. `internal/storage/storage.go:343 Save()` läuft direkt im Empfangspfad. | – |
|
| 2 | **Frühzeitigkeit** – Archivierung bei Eingang/Ausgang | ✅ Erfüllt | SMTP-BCC-Journaling (PROJ-4) archiviert synchron beim Empfang/Versand; IMAP-Cron-Sync (PROJ-8) ergänzt. `internal/storage/storage.go:343 Save()` läuft direkt im Empfangspfad. | – |
|
||||||
| 3 | **Unveränderbarkeit / Formaterhalt** | ✅ Erfüllt | `Save()` speichert Original-RFC2822-Bytes (ggf. gzip-komprimiert, PROJ-36) ohne inhaltliche Konvertierung; `Load()`/`maybeDecompress()` liefert Original zurück. Export liefert EML 1:1 (PROJ-12, `internal/api/export.go`). Kein Schreibzugriff/UPDATE auf gespeicherte Mail-Dateien im Code gefunden. | – |
|
| 3 | **Unveränderbarkeit / Formaterhalt** | ✅ Erfüllt | `Save()` speichert Original-RFC2822-Bytes (ggf. gzip-komprimiert, PROJ-36) ohne inhaltliche Konvertierung; `Load()`/`maybeDecompress()` liefert Original zurück. Export liefert EML 1:1 (PROJ-12, `internal/api/export.go`). Kein Schreibzugriff/UPDATE auf gespeicherte Mail-Dateien im Code gefunden. | – |
|
||||||
| 4 | **Zugriffsschutz** | ✅ Erfüllt | JWT-Auth (httpOnly Cookie), bcrypt Cost 12 (PROJ-1). Rollenmodell `user`/`auditor`/`admin` strikt getrennt; `admin` hat explizit KEINEN Mail-Zugriff. Tenant-Isolation via `tenantAccessAllowed()` (`internal/api/import_handlers.go:22`). | – |
|
| 4 | **Zugriffsschutz** | ✅ Erfüllt | JWT-Auth (httpOnly Cookie), bcrypt Cost 12 (PROJ-1). Rollenmodell `user`/`auditor`/`admin` strikt getrennt; `admin` hat explizit KEINEN Mail-Zugriff. Tenant-Isolation via `tenantAccessAllowed()` (`internal/api/import_handlers.go:22`). | – |
|
||||||
| 5 | **Wiederauffindbarkeit / Volltextsuche** | ✅ Erfüllt | Manticore-RT-Index (PROJ-30), Volltextsuche inkl. Anhänge via OCR (PROJ-35/44), Filter nach Datum/Absender/etc. (PROJ-6). | – |
|
| 5 | **Wiederauffindbarkeit / Volltextsuche** | ✅ Erfüllt | Manticore-RT-Index (PROJ-30), Volltextsuche inkl. Anhänge via OCR (PROJ-35/44), Filter nach Datum/Absender/etc. (PROJ-6). | – |
|
||||||
| 6 | **Aufbewahrungsfristen (konfigurierbar je Dokumentenart, i.d.R. 6–10 Jahre)** | ⚠️ Teilweise | `RetentionDays` global (`config/config.go:74`) und pro Tenant (`config/config.go:122`, Spalte `tenants.retention_days`) konfigurierbar — aber als EINZELNER Wert für alle Mails, keine Differenzierung nach Dokumentenart (Geschäftsbrief 6J / Rechnung 10J / Vertrag dauerhaft). `0` = kein Lock ist als Default zulässig (kein erzwungenes Minimum). | Spec-Erweiterung: Mindestwert (z.B. Warnung/Block unter 2190 Tagen) und/oder Kategorisierung nach Mail-Typ (PROJ-43 Archivierungsregeln könnte hierfür genutzt werden). |
|
| 6 | **Aufbewahrungsfristen (konfigurierbar je Dokumentenart, i.d.R. 6–10 Jahre)** | ⚠️ Teilweise | `RetentionDays` global (`config/config.go:74`) und pro Tenant (`config/config.go:122`, Spalte `tenants.retention_days`) konfigurierbar — aber als EINZELNER Wert für alle Mails, keine Differenzierung nach Dokumentenart (Geschäftsbrief 6J / Rechnung 10J / Vertrag dauerhaft). `0` = kein Lock ist als Default zulässig (kein erzwungenes Minimum). | Spec-Erweiterung: Mindestwert (z.B. Warnung/Block unter 2190 Tagen) und/oder Kategorisierung nach Mail-Typ (PROJ-43 Archivierungsregeln könnte hierfür genutzt werden). |
|
||||||
| 7 | **Löschsperre** | ✅ Erfüllt | PROJ-34 implementiert: `emails.retain_until`, `ErrRetentionLock` (`internal/storage/storage.go:27,659-667`), `Delete()` verweigert Löschung vor Fristablauf, `Purge()` löscht nur abgelaufene Mails (`storage.go:710-718`). | – |
|
| 7 | **Löschsperre** | ✅ Erfüllt | PROJ-34 implementiert: `emails.retain_until`, `ErrRetentionLock` (`internal/storage/storage.go:27,659-667`), `Delete()` verweigert Löschung vor Fristablauf. Zusätzlich Cron-Purge (PROJ-56c, `cmd/archivmail/cmd_purge.go`, nachts 03:40 via `/etc/cron.d/archivmail`): löscht NUR Mails die BEIDE Bedingungen erfüllen — `retain_until < NOW()` UND vom Nutzer explizit `marked_for_deletion=TRUE` gesetzt (`ListExpiredMarkedMailIDs`, `internal/storage/mark_deletion.go:127-148`). Reiner Fristablauf ohne manuelle Markierung löscht nichts automatisch (Vier-Augen-Prinzip: Frist + Mensch). Der manuelle Admin-Button (`Store.Purge()`, `POST /api/admin/purge`) löscht dagegen alles abgelaufene ohne Markierungspflicht — bewusst getrennte, absichtlich unterschiedliche Semantik für Cron vs. manuelle Aktion. | – |
|
||||||
| 8 | **Protokollierung/Audit-Log unveränderlich** | ❌ Fehlt | `internal/audit/audit.go:64-75` erstellt `audit_log`-Tabelle OHNE Trigger/Rule gegen `UPDATE`/`DELETE` (PROJ-11 AC: "kein UPDATE/DELETE durch Admin oder Anwendung möglich" — NICHT umgesetzt). Die geforderte append-only JSON-Lines-Datei (`/var/log/archivmail/audit.log`) existiert nicht im Code — nur `New(dsn, logDir, logger)` mit Kommentar "logDir is reserved for future". Audit-Events (Login, Suche, Export, Import) werden korrekt geschrieben, aber Unveränderbarkeit ist nicht garantiert. | PROJ-11 nachbessern: (a) PostgreSQL-Trigger/REVOKE UPDATE/DELETE auf `audit_log`, (b) append-only Flat-File-Logger implementieren. Hohe Priorität für GoBD-Prüfungen. |
|
| 8 | **Protokollierung/Audit-Log unveränderlich** | ❌ Fehlt | `internal/audit/audit.go:64-75` erstellt `audit_log`-Tabelle OHNE Trigger/Rule gegen `UPDATE`/`DELETE` (PROJ-11 AC: "kein UPDATE/DELETE durch Admin oder Anwendung möglich" — NICHT umgesetzt). Die geforderte append-only JSON-Lines-Datei (`/var/log/archivmail/audit.log`) existiert nicht im Code — nur `New(dsn, logDir, logger)` mit Kommentar "logDir is reserved for future". Audit-Events (Login, Suche, Export, Import) werden korrekt geschrieben, aber Unveränderbarkeit ist nicht garantiert. | PROJ-11 nachbessern: (a) PostgreSQL-Trigger/REVOKE UPDATE/DELETE auf `audit_log`, (b) append-only Flat-File-Logger implementieren. Hohe Priorität für GoBD-Prüfungen. |
|
||||||
| 9 | **Nachprüfbarkeit durch Dritte / GDPdU-Export** | ✅ Erfüllt | Export-Funktionen: Einzel-EML/PDF, ZIP-Massenexport mit `manifest.csv` (PROJ-12, `internal/api/export.go`), eDiscovery-ZIP mit `metadata.csv` + README (PROJ-39, `internal/api/ediscovery.go`), CLI-Export inkl. Tenant-Voll-Export (PROJ-15, PROJ-47, `cmd/archivmail/cmd_export.go`), Audit-Log-CSV-Export für Auditoren. | Optional: PROJ-47 (In Review) fertigstellen/QA. |
|
| 9 | **Nachprüfbarkeit durch Dritte / GDPdU-Export** | ✅ Erfüllt | Export-Funktionen: Einzel-EML/PDF, ZIP-Massenexport mit `manifest.csv` (PROJ-12, `internal/api/export.go`), eDiscovery-ZIP mit `metadata.csv` + README (PROJ-39, `internal/api/ediscovery.go`), CLI-Export inkl. Tenant-Voll-Export (PROJ-15, PROJ-47, `cmd/archivmail/cmd_export.go`), Audit-Log-CSV-Export für Auditoren. | Optional: PROJ-47 (In Review) fertigstellen/QA. |
|
||||||
| 10 | **Migrationssicherheit** | ⚠️ Teilweise | Migrationstools vorhanden (PROJ-19 Mailpiler-Import, PROJ-30 Xapian→Manticore), `initSchema`/idempotente `ALTER TABLE ... ADD COLUMN IF NOT EXISTS` Pattern durchgängig genutzt (z.B. `storage.go:99-100`). Kein dokumentierter "Compliance-Erhalt-Check" nach Migration (z.B. automatischer Verify-Lauf nach Schema-Änderung). | Migrations-Runbook + Post-Migration-Integritätscheck (kann PROJ-18-Job nach Migration triggern) dokumentieren. |
|
| 10 | **Migrationssicherheit** | ⚠️ Teilweise | Migrationstools vorhanden (PROJ-19 Mailpiler-Import, PROJ-30 Xapian→Manticore), `initSchema`/idempotente `ALTER TABLE ... ADD COLUMN IF NOT EXISTS` Pattern durchgängig genutzt (z.B. `storage.go:99-100`). Kein dokumentierter "Compliance-Erhalt-Check" nach Migration (z.B. automatischer Verify-Lauf nach Schema-Änderung). | Migrations-Runbook + Post-Migration-Integritätscheck (kann PROJ-18-Job nach Migration triggern) dokumentieren. |
|
||||||
|
|||||||
Reference in New Issue
Block a user