# RET-05 – Prüfprotokoll: Modul-Adapter-Schnittstelle Voraussetzung RET-01 – erledigt, siehe eigenes Protokoll. ## Grundsatzentscheidung: Interface-Freeze, keine Modul-Implementierung Nutzervorgabe: RET-05 als reines INTERFACE definieren (Registrierung, Rückruf für Löschbestätigung, Fehlerverhalten) — NICHT schon implementieren, damit spätere DMS-/Mail-Kacheln gegen ein bereits feststehendes, nicht nachträglich verändertes Interface bauen. Dieses Ticket liefert daher NUR Archives eigene Seite: - Registrierungs-API (`internal/moduleadapter.Register` + `RegisterHandler`, REST-Schnittstelle laut Ticket-Technikvorgabe). - Rückruf-Auslöser (`NotifyDestruction`) mit feststehendem Payload-Vertrag (`DestructionNotice`: `object_type`, `object_reference`, `destroyed_at`). **Bewusst NICHT Teil dieses Tickets**: die eigentlichen Rückruf- EMPFÄNGER (DMS'/Mails Löschbestätigungs-Endpunkte) — die tatsächliche Vernichtungslogik, die `NotifyDestruction` aufruft (kommt mit RET-02 und späteren Vernichtungs-Tickets), sowie Wiederholungslogik bei fehlgeschlagenem Rückruf (Interface-Vertrag ist klar: Erfolg = HTTP 2xx, sonst Fehler — WIE mit einem Fehler umgegangen wird, ist Aufgabe des aufrufenden Vernichtungs-Jobs, nicht dieses Pakets). ## Korrektur vor Abschluss: `retention_class` fehlte im ersten Entwurf Akzeptanzkriterium 1 verlangt "Objekttyp MIT Aufbewahrungsklasse UND Rückruf-Adresse" — der erste Entwurf von `module_registrations` und `Register` hatte nur `callback_url`, `retention_class` fehlte komplett. Vor dem Board-Flip auf „Fertig" bemerkt und korrigiert: Migration, `Registration`-Struct, `Register`, `ListRegistrations` und `RegisterHandler` um `retention_class` ergänzt, alle Tests entsprechend angepasst (inkl. Idempotenz-Nachweis auch für `retention_class`, nicht nur `callback_url`). Reale, bereits angewendete Migration auf `dms_tenant_test` musste dafür gedroppt und neu angewendet werden (kein Produktivbestand betroffen, Testsystem). ## Umsetzung - `migrations/0003_module_registrations.up.sql`/`.down.sql` — `module_registrations` (module_name, object_type, callback_url, UNIQUE-Constraint). - `internal/moduleadapter.Register` — `ON CONFLICT DO NOTHING` + Nachlese der bestehenden Zeile, damit eine erneute Registrierung NIE die bestehende `callback_url` überschreibt (Akzeptanzkriterium 3). - `internal/moduleadapter.ListRegistrations`. - `internal/moduleadapter.NotifyDestruction` — echter HTTP-POST mit dem festen `DestructionNotice`-Vertrag. - `internal/moduleadapter.RegisterHandler` — REST-Endpunkt (`POST /register`). ## Prüfungen | # | Prüfung | Ergebnis | |---|---|---| | 1 | Zwei fiktive Module (DMS, Mail) parallel registriert ohne Kollision | **bestanden** — `TestRegister_TwoModulesNoCollision`: unterschiedliche IDs, `ListRegistrations` zeigt beide | | 2 | Rückruf bei Vernichtung erfolgreich gegen einen Testendpunkt ausgeführt | **bestanden** — `TestNotifyDestruction_CallsRealTestEndpoint`: echter `httptest.Server`, echter POST, Payload real empfangen und geprüft (`object_reference` korrekt) | | 3 | Erneute Registrierung desselben Objekttyps ändert nichts am bestehenden Zustand | **bestanden** — `TestRegister_IsIdempotent_UnchangedExistingState` (Go-Funktion, mit absichtlich ABWEICHENDER `callback_url` im zweiten Aufruf) UND `TestRegisterHandler_RealHTTPRoundTrip` (dieselbe Prüfung nochmal über die HTTP-Schicht, nicht nur direkt gegen die Funktion) | Zusätzlich: `TestNotifyDestruction_ReturnsErrorOnNonSuccessStatus` (Fehlerverhalten), `TestRegisterHandler_RejectsMissingFields` (REST-Schicht weist unvollständige Registrierungen ab). ## Echte Verdrahtung auf 192.168.1.131 - Migration real gegen `dms_tenant_test` angewendet — `module_registrations` bestätigt vorhanden - Kein systemd-Dienst — `RegisterHandler` ist ein `http.HandlerFunc`, wird in einen künftigen Core-/Archive-HTTP-Server eingehängt, sobald ein solcher für Archive existiert (aktuell kein eigener Archive- API-Server, nur die bisherigen CLI/Metrics-Prozesse) — dokumentierter, kein stiller Gap, entspricht dem Interface-Freeze-Charakter dieses Tickets ## 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 -> 9/9 Pakete mit Tests ok, 0 Fehlschläge (nach Korrektur; internal/retention und internal/moduleadapter brauchen TEST_TENANT_DSN/TEST_TENANT_DSN_B bzw. TEST_TENANT_DSN) ``` ## Gesamtergebnis **Bestanden.** Alle drei Akzeptanzkriterien und alle drei Pflichtprüfungen real erfüllt — Idempotenz sowohl auf Go- als auch auf HTTP-Ebene bewiesen, Rückruf-Vertrag gegen einen echten Testendpunkt verifiziert. Bewusst als reiner Interface-Freeze umgesetzt, keine DMS-/Mail-seitige Implementierung — wie vom Nutzer vorgegeben.