Files
nexarch/docs/INT-12-PRUEFPROTOKOLL.md
patrickandClaude Sonnet 5 358964415c
CI / Web-Barrierefreiheitspruefung (axe, Tastatur, Reflow, Textabstaende) (push) Canceled after 0s
CI / Web-Barrierefreiheitspruefung (axe, Tastatur, Reflow, Textabstaende) (pull_request) Canceled after 0s
CI / Web (dms-browser) (push) Canceled after 0s
CI / Core-Modul (Build/Vet/Test) (pull_request) Canceled after 0s
CI / DMS Security-Test-Gate (AC5, Merge-Gate) (pull_request) Canceled after 0s
CI / Connect Security-Test-Gate (QA-01 AC4, Merge-Gate) (pull_request) Canceled after 0s
AI-Pflichttest-Gate / pflichttest-gate (pull_request) Canceled after 0s
CI / Core-Modul (Build/Vet/Test) (push) Canceled after 0s
CI / DMS Security-Test-Gate (AC5, Merge-Gate) (push) Canceled after 0s
CI / Connect Security-Test-Gate (QA-01 AC4, Merge-Gate) (push) Canceled after 0s
CI / DMS-Modul Supply-Chain-Scan (govulncheck) (push) Canceled after 0s
CI / Web (pdf-viewer) (push) Canceled after 0s
CI / Web (shl) (push) Canceled after 0s
CI / DMS-Modul Supply-Chain-Scan (govulncheck) (pull_request) Canceled after 0s
CI / Web (dms-browser) (pull_request) Canceled after 0s
CI / Web (pdf-viewer) (pull_request) Canceled after 0s
CI / Web (shl) (pull_request) Canceled after 0s
Supply-Chain-Scan (Go) / govulncheck (push) Canceled after 0s
Core-Schnittstellen-Vertragstests / contract-tests (pull_request) Canceled after 0s
Supply-Chain-Scan (Go) / govulncheck (pull_request) Canceled after 0s
Supply-Chain-Scan (npm) / npm-audit (pull_request) Canceled after 0s
Core-Pflichttest-Gate / pflichttest-gate (pull_request) Canceled after 0s
RBAC-Rollenhierarchie-Pflichtgate / rbac-policy-invariant (pull_request) Canceled after 0s
CI / DMS-Modul (Lint/Build/Test/Coverage/Artefakt) (push) Canceled after 0s
CI / DMS-Modul (Lint/Build/Test/Coverage/Artefakt) (pull_request) Canceled after 0s
INT-12: AI-Anbindung Objekttyp-Registrierung (Kopplung AI GOV-01)
DMS registriert den Dokument-Objekttyp inkl. KI-relevanter Felder (Volltext,
Metadaten) beim Start automatisch bei AI GOV-01 - ueber eine neue HTTP-
Schnittstelle (ai/internal/moduletypeapi), da DMS ein getrenntes Go-Modul
ist und GOV-01s Go-Paket nicht importieren kann. Registrierung ist optional
(fehlt die AI-Basis-URL, startet DMS unveraendert) und fail-open (ein
unerreichbarer AI-Dienst blockiert den DMS-Start nie).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-10-15 20:54:31 +00:00

87 lines
8.8 KiB
Markdown

# Prüfprotokoll INT-12 — AI-Anbindung: Objekttyp-Registrierung (Kopplung AI GOV-01)
Datum: 2026-10-15
Host: 192.168.1.204 (Wegwerf-Arbeitsverzeichnis)
Branch: `feature/int-12-ai-anbindung-objekttyp-registrierung-kopplung-ai-gov-01`
## Ausgangslage
- **DOC-01** (`dms/internal/upload`) liefert Upload/Chunk-Handling, aus dem die KI-relevanten Dokumentfelder stammen (Volltext aus OCR/SRC-05, Kernmetadaten aus MET-02/DOC-01).
- **GOV-01** (`ai/internal/moduletype`) existierte bereits als reines Go-Paket mit `Registry.Register`, `Get`, `ListByModule` gegen die Tabelle `module_objecttypes`, inkl. Tenant-Verifikation gegen Core TEN-01 (GOV-07, fail-closed) über das `TenantVerifier`-Interface.
- Es gab **keinen HTTP-Endpunkt** für diese Registrierung — DMS ist ein physisch getrenntes Go-Modul (`gitea.perlbach24.de/scripte/nexarch/dms`) und kann `ai/internal/moduletype` nicht importieren. Diese Lücke musste als Teil von INT-12 geschlossen werden (minimal, im bestehenden Baustil von `extractapi`/`residencyapi`).
## Umsetzung
### AI-Modul (ai/)
- Neu: `ai/internal/moduletypeapi` — HTTP-Bindung für `moduletype.Registry`:
- `POST /module-objecttypes` (Service-Token-Pflicht über `X-Service-Token`, fail closed wie extractapi/residencyapi).
- Antwort `403` bei `moduletype.ErrUnknownTenant` (GOV-07), `400` bei sonstigen Validierungsfehlern, `200` bei Erfolg.
- `ai/cmd/ai-app/main.go`: neue Konfiguration `NEXARCH_AI_APP_CORE_BASE_URL` / `NEXARCH_AI_APP_CORE_SERVICE_TOKEN`. Der Endpunkt wird **nur verdrahtet, wenn eine Core-Basis-URL konfiguriert ist** — ohne Tenant-Verifikationsmöglichkeit bleibt die Registrierungsroute unverdrahtet statt eine Registrierung ohne GOV-07-Prüfung zuzulassen (fail-closed-Grundsatz von GOV-01/GOV-07 bleibt gewahrt).
### DMS-Modul (dms/)
- Neu: `dms/internal/moduletypeclient` — schlanker HTTP-Client (Muster wie `dms/internal/retentionclient` für Archive RET-05/DOC-16):
- `Register(ctx, tenantSlug, objectType, fields)` → `POST {baseURL}/module-objecttypes` mit `X-Service-Token`.
- `DocumentFields()` liefert die KI-relevanten Felder des Objekttyps `document`: `fulltext`, `title`, `filename`, `mime_type`, `created_at`, `tags`.
- `dms/cmd/app/main.go`: neue Funktion `setupAIObjectTypeRegistration()`, aufgerufen beim Start aus `main()`:
- **AK2 (optional/kein Fehler ohne AI-Modul):** fehlt `NEXARCH_DMS_APP_AI_BASE_URL` (stellvertretend für "AI-Modul/Core-LIC-02 nicht aktiviert" — Ops setzt diese URL nur, wenn das AI-Modul lizenziert/aktiv ist, analog zum bestehenden RET-05/DOC-16-Muster in derselben Datei), wird die Registrierung übersprungen, nur eine Logzeile, kein Fehler, kein `log.Fatal`.
- **AK3 (fail open bei Registrierungsfehlern):** jeder Fehler aus `Register` (Transport, Timeout, Nicht-200) wird nur geloggt (`log.Printf`), die Funktion kehrt zurück, `main()` läuft unverändert weiter — kein `log.Fatal`, kein Blockieren.
- **AK1:** bei erfolgreicher Konfiguration wird der Objekttyp `document` mit den KI-relevanten Feldern automatisch beim Start registriert.
### Bewusst nicht umgesetzt (Scope-Entscheidung)
- Keine Deregistrierungs-/Lösch-Schnittstelle: Die Akzeptanzkriterien von INT-12 fordern nur die Registrierung beim Start; der Ticket-Hinweis zu "Löschfehler dürfen anders behandelt werden" beschreibt nur eine Abgrenzung zur Fail-Open-Regel, verlangt aber keine Deregistrierungsfunktion. Um nicht über das Ticket hinaus zu bauen, wurde keine Delete-Route/-Client ergänzt.
- Kein eigener HTTP-Client für Core LIC-02 (Feature-Flag-Abfrage) auf DMS-Seite: Ein solcher modulübergreifender Flag-Abfrage-Client existiert im Code noch nirgends (auch nicht in anderen separaten Go-Modulen wie `mail`/`connect`/`workflow`). Stattdessen wird das etablierte, bereits im Code vorhandene Muster (RET-05/DOC-16 in `dms/cmd/app/main.go`) übernommen: Aktivierung/Deaktivierung wird über das Vorhandensein der Basis-URL-Umgebungsvariable abgebildet, die Ops nur setzt, wenn das Modul lizenziert ist. Diese Design-Entscheidung ist dokumentiert, falls ein künftiges Ticket einen generischen LIC-02-HTTP-Client für module-übergreifende Flag-Abfragen einführt.
## Automatisierte Tests (real ausgeführt)
Testdatenbank (Wegwerf, eigens angelegt, nicht `dms_dev`/`archivdms`):
- Rolle/DB `int12_ai_test` (Postgres 17, lokal auf 204).
### AK1 — Registrierung erscheint bei AI
- `ai/internal/moduletypeapi/moduletypeapi_test.go::TestHandleRegister_ValidRequest_Registered` — POST gegen echten `httptest`-Server + echte Postgres-DB, Nachweis per `Registry.Get`.
- `dms/internal/moduletypeclient/moduletypeclient_test.go::TestRegister_SendsExpectedPayloadAndAuth` — Client sendet korrektes Payload/Token.
- **Realer End-to-End-Nachweis (Prüfung 1, siehe unten):** echter `ai-app`-Prozess + echter DMS-Client-Aufruf, Ergebnis per direkter SQL-Abfrage verifiziert.
### AK2 — AI-Modul nicht aktiviert → DMS startet unverändert
- `dms/cmd/app/aiobjecttype_test.go::TestSetupAIObjectTypeRegistration_NoBaseURL_SkipsWithoutPanic` — keine `NEXARCH_DMS_APP_AI_BASE_URL`, Aufruf kehrt ohne Fehler zurück.
- `TestSetupAIObjectTypeRegistration_NoTenantSlug_SkipsWithoutPanic` — zusätzliche Absicherung (fehlender Tenant-Kontext).
### AK3 — Registrierungsfehler blockieren DMS-Start nie
- `dms/cmd/app/aiobjecttype_test.go::TestSetupAIObjectTypeRegistration_UnreachableEndpoint_DoesNotBlock` — Basis-URL zeigt auf geschlossenen Port (`127.0.0.1:1`), Aufruf kehrt kontrolliert mit Logzeile zurück statt zu blockieren/abzustürzen.
- `dms/internal/moduletypeclient/moduletypeclient_test.go::TestRegister_UnreachableEndpoint_IsError` / `TestRegister_NonOKStatus_IsError` — Client liefert Fehler statt stillschweigend zu akzeptieren (Aufrufer entscheidet über Fail-Open).
- `ai/internal/moduletypeapi/moduletypeapi_test.go::TestHandleRegister_MissingServiceToken_Rejected`, `TestHandleRegister_UnknownTenant_Rejected` — AI-seitiges fail-closed bei Auth/Tenant bleibt erhalten.
Alle genannten Tests real ausgeführt und grün:
```
ok ai/internal/moduletypeapi 0.539s (3 Tests)
ok ai/internal/moduletype (unverändert grün)
ok ai/cmd/ai-app (unverändert grün)
ok dms/internal/moduletypeclient (3 Tests)
ok dms/cmd/app (alle Tests inkl. 3 neue INT-12-Tests)
```
Vollständiger `go test ./...` des `ai`-Moduls (alle ~50 Pakete) ebenfalls grün mit `TEST_TENANT_DSN` gegen `int12_ai_test`.
## Prüfungen vor Abnahme (real durchgeführt, nicht nur behauptet)
### Prüfung 1 — Registrierung gegen echte, laufende AI-Testinstanz
1. Migrationen auf `int12_ai_test` angewendet (`ai/internal/migrate`, 16 Migrationen inkl. `module_objecttypes`).
2. Core-TEN-01-Stub gestartet (`127.0.0.1:19901`): `GET /tenants/mandant-int12` → 200, alles andere → 404 (einfacher, legitimer Stub für die fremde, bereits eigenständig vertragsgetestete Core-Schnittstelle — kein DB-Mocking).
3. Echter `ai-app`-Prozess gestartet (`go build` → Binary, `127.0.0.1:19902`), verbunden mit `int12_ai_test` und dem Core-Stub, `NEXARCH_AI_APP_CORE_BASE_URL` gesetzt → Route `/module-objecttypes` ist verdrahtet.
4. Echter DMS-Client (`moduletypeclient.Register`) rief `http://127.0.0.1:19902/module-objecttypes` auf → Antwort `200 ok`.
5. Direkte SQL-Abfrage gegen `int12_ai_test`:
```
select tenant_slug, module_name, object_type, fields from module_objecttypes where tenant_slug='mandant-int12';
```
Ergebnis: ein Datensatz `dms/document` mit allen 6 KI-relevanten Feldern (`fulltext`, `title`, `filename`, `mime_type`, `created_at`, `tags`) — Objekttyp ist nachweislich bei AI registriert.
6. Alle Testprozesse (ai-app, Core-Stub) anschließend beendet (`pkill`), keine Leichen.
### Prüfung 2 — AI-Modul-Flag deaktiviert
- `TestSetupAIObjectTypeRegistration_NoBaseURL_SkipsWithoutPanic`: `NEXARCH_DMS_APP_AI_BASE_URL` leer → `setupAIObjectTypeRegistration()` kehrt sofort zurück, nur eine Logzeile ("deaktiviert"), kein Fehler, kein Prozessabbruch. Entspricht dem Normalbetrieb ohne AI-Modul.
### Prüfung 3 — AI-Endpunkt nicht erreichbar bei Registrierung
- `TestSetupAIObjectTypeRegistration_UnreachableEndpoint_DoesNotBlock`: `NEXARCH_DMS_APP_AI_BASE_URL=http://127.0.0.1:1` (verbindungsrefused) → `Register` liefert Fehler, `setupAIObjectTypeRegistration()` loggt ihn und kehrt zurück, `main()` würde unverändert weiterlaufen (kein `log.Fatal` im Pfad). Client-seitig zusätzlich durch `TestRegister_UnreachableEndpoint_IsError` abgesichert (Timeout über `context.WithTimeout(10s)` in `setupAIObjectTypeRegistration`, kein endloses Warten).
## Aufräumen
- Testprozesse (ai-app-Binary, Core-Stub) beendet.
- Temporäre `cmd/int12-*-tmp`-Verzeichnisse (Migrations-Runner, E2E-Runner) nach Gebrauch wieder gelöscht.
- Postgres-Rolle/DB `int12_ai_test` bleibt auf 204 als Wegwerf-Testartefakt stehen (keine Kollision mit `dms_dev`/`archivdms`), kann bei Bedarf gelöscht werden: `DROP DATABASE int12_ai_test; DROP ROLE int12_ai_test;`