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

70 lines
3.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 | **bestanden**`TestComputeDueDate_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 | **bestanden**`TestListExpiringObjects_EmptyBacklogReturnsEmptyNotError` |
| 3 | Mehrfachausführung des Jobs erzeugt keine doppelten Einträge | **bestanden**`TestListExpiringObjects_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).