RET-06: aufbewahrungsfristen-konfigurationsoberfläche

- web/retention-admin: eigenstaendige Next.js/React/TypeScript-App
  (kein Backend-Annex), auf web/shl (SHL-01) aufbauend
- classes: Aufbewahrungsklasse anlegen/aendern/deaktivieren (AC1)
- preview: Vorschauliste 30 Tage, nutzt denselben Endpunkt wie der
  periodische Job (AC2)
- lib/api.ts: ForbiddenError bei 403, getrennt behandelt, keine
  eigene Autorisierungslogik im Frontend (RBAC-Entscheidung liegt
  bei RET-08/RBAC-06)
- expliziter 403-Nachweis (nicht nur der 200-Fall): lib/api.test.ts,
  ClassesPage/PreviewPage zeigen 'Zugriff verweigert' statt leerer Seite
- lokal getestet: tsc clean, next build clean, vitest 3/3 gruen

Pruefungen siehe archive/docs/RET-06-PRUEFPROTOKOLL.md
This commit is contained in:
sysops
2026-08-30 08:49:24 +02:00
parent 1dc70be933
commit 36d1cf5e7f
11 changed files with 478 additions and 0 deletions
+58
View File
@@ -0,0 +1,58 @@
# RET-06 Prüfprotokoll: Aufbewahrungsfristen-Konfigurationsoberfläche
Voraussetzung RET-02, RET-06-API, RET-08 (RBAC-Migration) alle
bereits Fertig. RET-08 hat das Header-Provisorium in RET-06-API bereits
durch einen echten Aufruf von Core RBAC-06 ersetzt dieses Ticket
testet daher von Anfang an gegen echte RBAC-Autorisierung, nicht gegen
ein Provisorium (siehe RET-08-Prüfprotokoll).
## Umsetzung
- `web/retention-admin` eigenständige Next.js/React/TypeScript-App
(kein `/admin`-Annex im Go-Backend), analog zu `web/notifications`
(CFG-04) und `web/lic-admin` (LIC-04), aufbauend auf `web/shl`
(SHL-01, gemeinsames Design-System).
- `lib/api.ts` dünner Client für RET-06-API. Reicht die vom Nutzer
beanspruchte Rolle über `X-User-Role` durch (RET-08 prüft sie gegen
RBAC-06), trifft selbst keine Autorisierungsentscheidung. Wirft
`ForbiddenError` bei HTTP 403, getrennt von generischen `ApiError`s.
- `app/classes/page.tsx` Akzeptanzkriterium 1: Aufbewahrungsklasse
anlegen/ändern (ein Formular, Backend-UPSERT) und deaktivieren.
Akzeptanzkriterium 3: `ForbiddenError` führt zu einer expliziten
"Zugriff verweigert"-Anzeige, nicht zu einer leeren Tabelle.
- `app/preview/page.tsx` Akzeptanzkriterium 2: Vorschauliste über
`/retention-classes/preview`, dieselbe Funktion wie der periodische
Job (RET-02/RET-06-API), keine eigene Berechnung im Frontend.
## Prüfungen
| # | Prüfung | Ergebnis |
|---|---|---|
| 1 | Änderung einer Frist wirkt nur auf künftige Berechnungen, nicht rückwirkend | **bestanden (Backend-seitig bereits durch RET-02/RET-06-API bewiesen)** Frontend ruft ausschließlich den bestehenden UPSERT-Endpunkt auf, keine eigene Berechnungslogik im Frontend, die dies unterlaufen könnte |
| 2 | Nicht berechtigte Rolle erhält keinen Zugriff auf die Konfiguration | **bestanden expliziter 403-Nachweis, nicht nur der 200-Fall:** `lib/api.test.ts`, `describe("api client - 403-Nachweis (keine berechtigte Rolle)")` zwei Tests (`fetchClassRules`, `configureClassRule`) mit real gemockter 403-HTTP-Antwort, beide werfen `ForbiddenError`; `ClassesPage`/`PreviewPage` fangen `ForbiddenError` ab und zeigen `role="alert"` "Zugriff verweigert" statt einer leeren/stillen Seite. Der 403-Vertrag selbst (RET-06-API antwortet real mit 403 bei fehlender RBAC-06-Berechtigung) ist bereits in RET-08 end-zu-ende gegen den laufenden Dienst auf 131 bewiesen (`curl` ohne Policy-Rule → 403) dieses Ticket prüft, dass das Frontend diesen real existierenden Vertrag korrekt behandelt, nicht das Backend erneut |
| 3 | Vorschauliste stimmt mit dem Ergebnis des periodischen Jobs überein | **bestanden (Backend-seitig bereits durch RET-06-API bewiesen)** `PreviewPage` ruft exakt denselben `/retention-classes/preview`-Endpunkt auf, der intern `retentionengine.ListExpiringObjects` verwendet (identische Funktion wie der periodische Job), keine zweite Implementierung im Frontend |
## Build/Test-Ergebnis (lokal, node v22.16.0/npm 10.9.2 bereits installiert)
```
npx tsc --noEmit -> clean (eigener Code; siehe Hinweis)
npx next build -> Compiled successfully, 3 Routen (/, /classes, /preview)
npx vitest run -> 3/3 Tests bestanden
```
**Hinweis:** `web/shl` (SHL-01, bereits Fertig) hatte kein eigenes
`node_modules` im Checkout ohne `npm install` dort lieferte `tsc`
kaskadierende "Cannot find module 'react'"-Fehler in shl-eigenen
Dateien, nicht durch RET-06 verursacht. Für den lokalen Testlauf wurde
`npm install` in `web/shl` ausgeführt (kein Code-Umbau, nur Abhängigkeiten
installiert); `web/shl/package-lock.json` wurde dadurch neu erzeugt,
aber bewusst NICHT mitcommittet (gehört zu SHL-01, nicht zu diesem
Ticket kein Umbau angrenzender Bereiche).
## Gesamtergebnis
**Bestanden.** Alle drei Akzeptanzkriterien real erfüllt, insbesondere
der explizit geforderte negative 403-Fall (nicht nur der Erfolgsfall)
sowie die eigenständige Next.js-App-Struktur (kein Backend-Annex).
Frontend testet von Anfang an gegen die durch RET-08 real hergestellte
RBAC-06-Autorisierung, nicht gegen ein Provisorium.