Files
nexarch/archive/docs/RET-02-PRUEFPROTOKOLL.md
T
sysops 2c9a7482b6 feat(archive): RET-02 Aufbewahrungsfristen-Engine
internal/retentionengine: Frist je Aufbewahrungsklasse als natives
Postgres-INTERVAL, Stichtagsberechnung an Postgres delegiert statt
eigener Kalenderrechnung (Schaltjahr/Monatsende-Referenzwerte real
verifiziert: 2024-02-29+1y=2025-02-28, 2026-01-31+1mo=2026-02-28).
Periodischer Job (ListExpiringObjects) beschraenkt sich per DISTINCT ON
auf die juengste Klassenzuordnung je Objekt - sonst wuerden Objekte mit
mehrfach geaenderter Klasse (RET-01-Historisierung) doppelt auftauchen,
real mit einem Zwei-Zuordnungen-Testobjekt bewiesen. Scope bewusst eng
gehalten: keine RET-05-Anbindung, keine Vernichtungslogik - das ist
Ticket-Scope, dependsOn ist nur RET-01.
2026-08-30 01:54:48 +02:00

3.5 KiB
Raw Blame History

RET-02 Prüfprotokoll: Aufbewahrungsfristen-Engine

Voraussetzung RET-01 erledigt, siehe eigenes Protokoll.

Scope-Klarstellung: Dieses Ticket ist die Fristen-BERECHNUNGS-Engine (Frist je Klasse, Stichtagsberechnung, periodischer Ablauf-Job) — dependsOn: ["RET-01"], KEINE Abhängigkeit auf RET-05. Die DMS-/Mail- seitige Registrierung als RET-05-Adapter-Konsument sowie Vernichtungs-Job-Fehlerbehandlung (2xx/Requeue) sind NICHT Teil dieser Kachel — das ist ein späteres, eigenes Ticket (vermutlich im ARC-/DOC--Umfeld). Bewusst nicht mitgebaut, um nicht über den Ticket-Umfang hinaus zu implementieren.

Grundsatzentscheidung: Postgres-INTERVAL statt eigener Kalenderrechnung

retention_class_rules.duration ist ein natives Postgres-INTERVAL (z. B. '10 years', '6 months') — ComputeDueDate delegiert die gesamte Stichtagsberechnung an Postgres selbst (start + duration), statt eine eigene Schaltjahr-/Monatsende-Logik in Go nachzubauen, die von der WHERE-Klausel des periodischen Jobs (dieselbe Arithmetik) abweichen könnte. Referenzwerte für Akzeptanzkriterium 2 real gegen Postgres verifiziert, nicht angenommen: 2024-02-29 + 1 year = 2025-02-28, 2026-01-31 + 1 month = 2026-02-28.

Umsetzung

  • migrations/0004_retention_class_rules.up.sql/.down.sql.
  • internal/retentionengine.ConfigureClassRule — eine Regel je Klasse (UPSERT).
  • internal/retentionengine.ComputeDueDate — delegiert an Postgres.
  • internal/retentionengine.ListExpiringObjects — periodischer Job: DISTINCT ON (retention_object_id) auf die JÜNGSTE Klassenzuordnung beschränkt, sonst würde ein Objekt mit mehrfach geänderter Klasse (RET-01s Historisierung) mehrfach im Ergebnis auftauchen.

Prüfungen

# Prüfung Ergebnis
1 Fristberechnung an Referenzdaten mit bekannten Ablaufdaten geprüft bestandenTestComputeDueDate_KnownReferenceDates: Schaltjahr (29.02.2024 + 1 Jahr → 28.02.2025) und Monatsende (31.01.2026 + 1 Monat → 28.02.2026), beide Werte vorab real gegen Postgres verifiziert
2 Job liefert bei leerem Bestand ein leeres, nicht fehlerhaftes Ergebnis bestandenTestListExpiringObjects_EmptyBacklogReturnsEmptyNotError
3 Mehrfachausführung des Jobs erzeugt keine doppelten Einträge bestandenTestListExpiringObjects_NoDuplicatesAcrossHistoricalClassChanges: Objekt mit ZWEI historischen Klassenzuordnungen (beide abgelaufen), zwei Job-Läufe liefern je genau 1 Eintrag — ohne die DISTINCT ON-Einschränkung wäre es 2 gewesen

Echte Verdrahtung auf 192.168.1.131

  • Migration real gegen dms_tenant_test angewendet — retention_class_rules bestätigt vorhanden neben retention_objects/retention_class_assignments
  • Kein systemd-Timer in diesem Ticket — "periodischer Job" ist die Bibliotheksfunktion ListExpiringObjects; ihr tatsächlicher Aufrufer/Zeitplan (systemd-Timer + Meldeweg für abgelaufene Objekte) ist Aufgabe eines Folgetickets, das auch die Vernichtungslogik selbst bringt (dieses Ticket berechnet nur, wer fällig ist — vernichtet nichts)

Build/Test-Ergebnis (192.168.1.131, make check)

go build ./...  -> clean
go vet ./...    -> clean
golangci-lint run ./...  -> 0 issues
go test ./... -p 1 -count=1  -> 10/10 Pakete mit Tests ok, 0 Fehlschläge

Gesamtergebnis

Bestanden. Alle drei Akzeptanzkriterien und alle drei Pflichtprüfungen real erfüllt — Stichtagsberechnung gegen real verifizierte Postgres-Referenzwerte, Job-Idempotenz gegen ein Objekt mit echter Mehrfach-Historie bewiesen (nicht nur behauptet).