feat(PROJ-56c): Purge-Cron löscht nur explizit markierte Mails
Der automatische Purge-Cron darf nicht allein anhand des abgelaufenen
retain_until löschen — eine Mail muss zusätzlich von einem Admin im UI
zur Löschung markiert worden sein. Dafür: neue Spalten
marked_for_deletion(_by/_at) auf emails, Store.ListExpiredMarkedMailIDs()
(retain_until abgelaufen UND markiert) für den Cron-Pfad, und
Store.SetMarkedForDeletion() zum Setzen/Löschen der Markierung.
Neue Endpoints (domain_admin+, tenant-scoped):
- GET /api/admin/retention/expired Metadaten abgelaufener Mails
(kein Body-Zugriff, SEC-29)
- PUT /api/admin/mails/{id}/mark-deletion Markierung setzen/entfernen,
mit Audit-Log-Eintrag
RetentionTab.tsx zeigt abgelaufene Mails mit Checkbox zum Markieren.
Der bestehende manuelle "Jetzt löschen"-Button (/api/admin/purge) bleibt
unverändert und löscht weiterhin alle abgelaufenen Mails auf einen Klick —
nur der unbeaufsichtigte Cron-Job ist jetzt auf markierte Mails beschränkt.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
586af2478c
commit
b3ff8e6cf9
@@ -12,11 +12,15 @@ import (
|
||||
"archivmail/internal/storage"
|
||||
)
|
||||
|
||||
// runPurge deletes all mails whose retain_until has passed, removes them
|
||||
// from the search index, and writes one audit log entry per deleted mail
|
||||
// (GoBD-Nachvollziehbarkeit). Intended to be cron-driven (PROJ-56c), mirrors
|
||||
// the manual /api/admin/purge endpoint but adds index cleanup + audit trail,
|
||||
// which the plain Store.Purge() helper intentionally does not do.
|
||||
// runPurge deletes mails that are BOTH past retain_until AND explicitly
|
||||
// marked_for_deletion=TRUE by a user in the UI, removes them from the
|
||||
// search index, and writes one audit log entry per deleted mail
|
||||
// (GoBD-Nachvollziehbarkeit). Intended to be cron-driven (PROJ-56c).
|
||||
//
|
||||
// Deliberately NOT the same query as the manual /api/admin/purge endpoint
|
||||
// (Store.Purge, deletes everything past retain_until regardless of marking):
|
||||
// an unattended cron job must never delete mails on date alone — a human
|
||||
// has to have explicitly flagged each one for deletion first.
|
||||
//
|
||||
// Usage: archivmail purge [-config /path/to/config.yml] [-dry-run]
|
||||
func runPurge(args []string) {
|
||||
@@ -48,13 +52,13 @@ func runPurge(args []string) {
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
ids, err := mailStore.ListExpiredMailIDs(ctx)
|
||||
ids, err := mailStore.ListExpiredMarkedMailIDs(ctx)
|
||||
if err != nil {
|
||||
logger.Error("purge: list expired failed", "err", err)
|
||||
logger.Error("purge: list expired+marked failed", "err", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if len(ids) == 0 {
|
||||
logger.Info("purge: nothing to do, no expired mails")
|
||||
logger.Info("purge: nothing to do, no expired+marked mails")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -116,7 +120,7 @@ func runPurge(args []string) {
|
||||
TenantID: tenantID,
|
||||
MailID: id,
|
||||
Success: true,
|
||||
Detail: "automatischer Purge nach Ablauf der Aufbewahrungsfrist (retain_until)",
|
||||
Detail: "Cron-Purge: Aufbewahrungsfrist abgelaufen UND vom Nutzer zur Löschung markiert",
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user