UX-09: Akten-/Vorgangsanzeige im Mail-Kontext #174
Closed
patrick
wants to merge 0 commits from
feature/ux-09-akten-vorgangsanzeige-im-mail-kontext into main
pull from: feature/ux-09-akten-vorgangsanzeige-im-mail-kontext
merge into: scripte:main
scripte:main
scripte:fix/ai-app-write-timeout
scripte:chore/migration-kanban-board
scripte:chore/connect-kanban-board
scripte:chore/workflow-kanban-board
scripte:chore/archive-kanban-board
scripte:chore/mail-kanban-board
scripte:chore/dms-kanban-board
scripte:chore/core-kanban-board
scripte:chore/ai-kanban-board
scripte:chore/ai-kanban-security-folgetickets
scripte:feat/ai-app-deployment
scripte:feat/ai-app-vorschlaege
scripte:feat/ai-cls09-herkunftsmarkierung
scripte:feat/ai-eng09-gemini
scripte:feat/ai-cls08-mehrsprachig
scripte:feat/ai-titel-korrespondent
scripte:feat/dms-backup-s3
scripte:feat/dms-s3-verdrahten
scripte:docs/alfresco-vergleich
scripte:refactor/common-batch-2
scripte:refactor/common-modul-pilot
scripte:fix/dms-httpharden-normalize
scripte:feature/shl-02-pagecontainer-dedup
scripte:test/dedup-fakekek-testutil
scripte:feature/nav-01-mail-postfach-registry-eintrag
scripte:feature/sec-08-09-rbac-cmis-audit
scripte:feature/shl-04-globale-modul-navigation
scripte:chore/mail-kanban-security-folgetickets
scripte:chore/dms-kanban-security-folgetickets
scripte:chore/core-kanban-security-folgetickets
scripte:chore/archive-kanban-security-folgetickets
scripte:chore/workflow-kanban-security-folgetickets
scripte:chore/connect-kanban-security-folgetickets
scripte:feature/qa-08-barrierefreiheits-audit-workflow
scripte:feature/tsk-04-aufgaben-oberflaeche-workflow
scripte:feature/qa-08-barrierefreiheits-audit-connect
scripte:feature/int-18-smtp-gateway-weiterleitung-an-feste-adresse-dms
scripte:docs/rollout-131-vorbereitung
scripte:feature/met-08-facturx-zugferd-szenarien-validator-dms
scripte:feature/qa-15-sicherheitspruefung-gesamtprojekt
scripte:fix/testrun-2026-09-21-dms
scripte:feature/cmp-07-dsgvo-loeschantrag-recht-auf-loeschung
scripte:feature/cmp-06-vier-augen-freigabe-fuer-loeschungen
scripte:feature/cmp-02-dsgvo-datenschutz-berichte
scripte:feature/ret-03-loeschworkflow-und-aufbewahrungssperre-legal-hold
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
E-Mail-Detailansicht zeigt Akte, Vermerke und offene Wiedervorlagen ueber die externe Workflow-Rueckkanal-API (VOR-04), keine Aktendaten in Mail gespeichert. 40/40 Tests gruen (lib/route/component), tsc sauber. Kein Merge, kein Deploy.
🤖 Generated with Claude Code
Such-API mit Ranking (Relevanz, Datum, Anhangstreffer), mandantengetrennt, mit Grundoperatoren (Phrase, Ausschluss). - client.go: Search nutzt jetzt Manticores query_string-Klausel statt match — unterstützt Phrasensuche ("...") und Ausschluss (-wort) nativ, Wert bleibt reiner JSON-String ohne dynamischen Feldnamen. - fieldWeights (statische Konstanten: subject=10, body=3, attachment_text=1) über die Manticore-Option field_weights — Ranking berücksichtigt Anhangstreffer, Result.Score macht es nachvollziehbar. - Bestehenden SRC-01-Injection-Test an die neue query_string-Struktur angepasst (gleiche Funktion weiterentwickelt). Prüfungen (alle real durchgeführt, siehe mail/docs/SRC-03-PRUEFPROTOKOLL.md): 1. TestSearch_TenantIsolation (SRC-01, weiterhin gültig). 2. TestSearch_PhraseAndExclusionOperators: Phrase und Ausschluss liefern real erwartete Teilmengen. 3. TestSearch_PerformanceWithLargeCorpus: Suche über 1000 reale Dokumente in 775,8µs (Ziel 500ms) gegen echtes Manticore auf 192.168.1.131. Zusätzlich TestSearch_RankingReflectsFieldWeightAndIsTraceable für Akzeptanzkriterium 1. Kein Umbau: dedup/indexworker/storage/crypto/encstorage unverändert. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HhgFcLS8tYMhDJpP74C6AQPrüfgate für Archivierung & Suche: verbindliche Kriterien für Verschlüsselung, Speicherpfad-Konventionen und Suchqualität. - qagate/gate.go: RunTestSuites führt go test real über storage/crypto/ encstorage/search aus (inkl. ARC-08-Schlüsselrotation, SRC-10-OCR- Konfidenz). ScanSearchPathForDynamicSQL prüft jede Nicht-Test-Datei in mail/internal/search (außer reindex.go, dokumentierte DDL-Ausnahme) auf tatsächliche fmt.Sprintf(-Aufrufe — verallgemeinert die SRC-01- Prüfung auf den gesamten Suchpfad. GateResult.Report() liefert dokumentierten, zeitgestempelten Bericht. - Echten Fehlalarm gefunden und behoben: Kommentartext in fields.go ("...fmt.Sprintf/strings.Join...") wurde fälschlich als Verstoß erkannt — Suchmuster auf "fmt.Sprintf(" präzisiert. Prüfungen (alle real durchgeführt, siehe mail/docs/QA-03-PRUEFPROTOKOLL.md): 1. TestRun_RealGateAgainstCurrentARC08SRC10State: echter Gate-Lauf, Bericht real "BESTANDEN" mit Zeitstempel. 2. TestScanSearchPathForDynamicSQL_RealSearchPackagePasses + Negativ-/Ausnahmetests: automatisierte Codereview-Stichprobe bestätigt real statischen Query-Builder. 3. Unabhängiger Subagent (frischer Kontext) hat den Gate-Testlauf real erneut ausgeführt und den Suchpfad-Scan mit eigenem grep unabhängig verifiziert — "BESTANDEN, unabhängig bestätigt". Kein Umbau: storage/crypto/encstorage/search unverändert, QA-03 fügt ausschließlich das Gate selbst hinzu. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HhgFcLS8tYMhDJpP74C6AQmailrules.Store (IMP-03) bekommt Update (bislang nur Create/List/ Delete) — gleiches Muster wie Create: Musterprüfung vor dem Schreiben, streng auf tenant_slug+id beschränkt, ErrNotFound bei fremder/nicht existierender ID. Neues Paket mail/internal/mailrulesapi: vier Endpunkte (GET/POST /api/v1/mail/rules, PUT/DELETE /api/v1/mail/rules/{id}), tenant-Query- Parameter Pflicht, gleiche Konvention wie mailapi (INT-01). Akzeptanzkriterium 3 ist strukturell garantiert: mailrulesapi ruft ausschließlich mailrules.Store auf, denselben Store, den IMP-03s Import-Pfad ohnehin verwendet — kein zweiter, paralleler Schreibpfad. Alle drei Pflichtprüfungen mit echten Nachweisen: vollständiger Anlegen/Priorisieren/Einsehen/Löschen-Zyklus über echte HTTP-Requests; eine über die API angelegte Regel wird über genau den Weg gelesen und ausgewertet, den IMP-03s Import-Pfad geht (Store.List -> mailrules.NewEngine -> Evaluate) und liefert das korrekte Klassifizierungsergebnis; Mandant Bs Update-Versuch mit der echten, bekannten ID von Mandant As Regel liefert 404, Mandant As Regel bleibt unverändert. go build/go vet/golangci-lint clean, gesamtes Mail-Modul regressionsfrei getestet — bestehende mailrules-Tests (IMP-03/IMP-09) bleiben nach der Update-Erweiterung unverändert grün.Zwei kleine Nacharbeiten aus dem Testlauf auf 131: - ConfigStore.Save nutzte einen Multi-Statement-Exec (DELETE; INSERT), den pgx im extended protocol ablehnt ("cannot insert multiple commands into a prepared statement") -- jetzt als Transaktion mit zwei Exec-Aufrufen. - Das Test-Setup fuer die tenants-Tabelle in config_store_test.go war schlanker als das in internal/kek/kek_test.go verwendete Vollschema (fehlende Spalten previous_status/deletion_scheduled_at/ retention_block_reason/retention_checked_at). Da beide Pakete im Gesamttestlauf dieselbe Test-Datenbank per CREATE TABLE IF NOT EXISTS teilen, hat das schlankere Schema (wenn zuerst angelegt) den kek-Test TestTenantKEKHandler_AllowsActiveModuleForTenant zum Fehlschlagen gebracht. Jetzt identisches Vollschema wie kek_test.go. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QPsyieCYwvbUBsnN598SbPAUD-02 hat bereits einen Trigger, der UPDATE/DELETE auf audit_events per RAISE EXCEPTION ablehnt (Akzeptanzkriterium 3 aus AUD-07 war damit schon erfuellt). Zwei Luecken blieben: (1) die Anwendungsrolle hatte weiterhin UPDATE/DELETE-Rechte auf DB-Ebene, der Schutz war nur ein Code-Pfad (Trigger), keine fehlenden Rechte; (2) ein abgelehnter Aenderungsversuch wurde nirgends selbst protokolliert. - migrations/0010_audit_events_role_enforcement.{up,down}.sql: Gruppenrolle nexarch_app ohne LOGIN/Passwort, REVOKE ALL + GRANT INSERT, SELECT auf audit_events fuer PUBLIC/nexarch_app; Trigger-Funktion um RAISE WARNING mit Akteur/Session/Client-Kontext ergaenzt, bevor der Versuch weiterhin per RAISE EXCEPTION abgelehnt wird (RAISE WARNING ist nicht transaktional, landet also auch bei Rollback im Postgres-Server-Log). - internal/audit/append_only_test.go: Tests je Akzeptanzkriterium - TestAppendOnly_AppRoleHasNoUpdateOrDeletePrivilege (AC1/Pruefung1, erwartet "permission denied" statt Trigger-Fehler), TestAppendOnly_TamperAttemptIsLogged (AC2/Pruefung2, faengt die RAISE-WARNING-Notice ueber pgx OnNotice ab), TestAppendOnly_NormalWriteAndReadStillWork (AC3/Pruefung3, Regression). Pruefungen auf 192.168.1.131 durchgefuehrt: 1. UPDATE/DELETE mit Anwendungsrolle (Mitglied nexarch_app) -> "permission denied for table audit_events" statt Trigger-Fehler: PASS. 2. Ablehnungsversuch selbst protokolliert (RAISE WARNING mit Akteur/Session/Zeitpunkt, unabhaengig von Transaktions-Rollback) via pgx-Notice-Capture nachgewiesen: PASS. 3. Regression Schreiben/Lesen (Record + CountByTenant, mehrere Eintraege): PASS. Gesamtlauf go test ./... -p 1 -count=1: internal/audit vollstaendig gruen (alle 22 Tests inkl. der 3 neuen). Bestehende, dokumentierte Altlasten unveraendert beobachtet (nicht Bestandteil dieser Kachel): internal/migrate (TestRolloutAll_* reihenfolgeabhaengig), internal/notify (TestDispatcher_EnqueueAndProcess flakt), internal/pentest (TestPentest_KEK_CompromisedMasterKeyCannotDecryptAfterRotation), internal/user (verwaiste test_iam01_users/test_iam01_superadmins-DBs). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QPsyieCYwvbUBsnN598SbPinternal/serviceaccount/anomaly.go: rein additive Ergaenzung zu IAM-09 (serviceaccount.go bleibt unveraendert) — VerifyWithContext ruft Verify unveraendert auf und beobachtet danach Herkunfts-IP und Zugriffsrate eines gueltigen Tokens. Eine bisher nicht beobachtete IP-Range (grob gebuckelt auf /24 bzw. /64) oder ein gegenueber der EWMA-Basislinie stark abweichender Zugriffsratenanstieg (>5x schneller als gewohnt, erst ab 3 Beobachtungen bewertet) erzeugt ein Audit-Event mit metadata.severity=elevated ueber die zentrale AUD-01-Schreibschnittstelle (Akzeptanzkriterium 1 + 2). Optional ist ein CFG-02-Dispatcher anschliessbar (WithNotify) fuer eine Benachrichtigung des Token-Besitzers/Tenant-Admins. Keine automatische Sperre: eine erkannte Anomalie ruft niemals Revoke auf, das Token bleibt gueltig (Akzeptanzkriterium 3) — reines Hinweissignal, wie im Auftrag gefordert (bewusst vermeiden: Keycloak, wo Anomalie-Erkennung nur optionale Zusatzkonfiguration ist). migrations/tenant/0007_api_token_anomaly.{up,down}.sql: zwei neue Tabellen (api_token_ip_ranges, api_token_rate_state), keine Aenderung an api_tokens/ audit_events selbst. Pruefungen (ausgefuehrt auf root@192.168.1.131, go test -p 1 PASS): 1. Zugriff aus neuer IP-Range erzeugt erwarteten Audit-Event — TestVerifyWithContext_NewIPRangeTriggersAuditEvent: erster Zugriff legt Basislinie an (kein Alarm), zweiter Zugriff aus anderer Range erzeugt genau 1 Event mit severity=elevated. PASS. 2. Kuenstlich stark erhoehte Zugriffsrate erzeugt erwarteten Audit-Event — TestVerifyWithContext_RateSpikeTriggersAuditEvent: Basislinie mit ~120ms-Abstand etabliert, Burst-Zugriff ohne Abstand erzeugt genau 1 Raten-Anomalie-Event. PASS. 3. Regressionstest: normale, unauffaellige Nutzung erzeugt keine Falsch-Alarme — TestVerifyWithContext_NormalUsageNoFalseAlarms: 8 Zugriffe gleiche IP-Range, gleichmaessiger Abstand, 0 Events. PASS. Zusaetzlich: TestVerifyWithContext_AnomalyDoesNotRevokeToken belegt Akzeptanzkriterium 3 direkt (Token nach erkannter Anomalie weiterhin gueltig). PASS. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QPsyieCYwvbUBsnN598SbPinternal/documentapi: neue Backend-Voraussetzung, die DOC-01/DOC-04 noch nicht hatten - GET /documents/{id}/content liefert den entschluesselten Originalinhalt der aktuellen Revision, Content-Type ausschliesslich ueber Magic-Bytes, Content-Disposition: inline (kein Download-Zwang), volle HTTP-Range-Unterstuetzung ueber http.ServeContent (Standardbibliothek) - darueber laedt PDF.js grosse Dokumente automatisch seitenweise nach. web/pdf-viewer: Next.js/React/TypeScript, PDF.js ausschliesslich auf Canvas gerendert (kein iframe, siehe "Bekannte Fehler vermeiden"). Worker laeuft aus public/pdf.worker.min.mjs (npm run copy-pdf-worker, Teil von predev/prebuild) - bewusst NICHT ueber ein externes CDN, damit die Anwendung vollstaendig offline/lokal lauffaehig bleibt. lib/viewerState.ts kapselt Seiten-/Zoom-Navigation und Tastaturbedienung als reine, DOM-unabhaengige Funktionen (Akzeptanzkriterium 2), Suche nutzt PDF.js' eigene Textextraktion. Pruefungen: 1. 300-seitiges PDF oeffnet im Zeitbudget - echter pdfjs-dist-Ladetest gegen den echten Backend-Dienst: 247ms (Budget 5000ms) 2. Viewer per Tastatur bedienbar - 15 Vitest-Tests fuer Pfeiltasten/Zoom/ Suche-Fokus, inkl. Ignorieren waehrend im Suchfeld getippt wird 3. Speicherverbrauch im Browser - OFFEN, kein Headless-Browser in dieser Umgebung verfuegbar (gleiche Einschraenkung wie bei ANA-02) SHL-01 (Core-Board, eigener Branch-Strang mit gemeinsamer Basis) sauber gemergt - kein Dateiueberschneidungs-Konflikt (web/shl vs. dms/). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>internal/folderapi: neue Backend-Voraussetzung - GET /folders/{id}/ children (lazy Baum-Ladung), .../breadcrumb (ueber DOC-09s Materialized Path), .../documents (Dokumentenliste, whitelisted Sortierspalten). folder.go ergaenzt ListChildren/Breadcrumb (additiv, keine bestehende Funktion geaendert). web/dms-browser: Next.js/React/TypeScript. Navigationsbaum laedt Kinder lazy je Ebene, Dokumentenliste ist virtualisiert (lib/virtualization.ts, abhaengigkeitsfrei - nur sichtbarer Ausschnitt + Overscan wird gerendert), Mehrfachauswahl (lib/selection.ts: Klick/Strg/Umschalt), Tastatur- navigation im Baum (lib/treeKeyboard.ts). Aktueller Ordner steckt in der URL (Catch-all-Route /browse/[[...path]]) statt nur im React-State - der Browser verwaltet Vor-/Zurueck-Navigation selbst. Echter Bug beim Schreiben der Virtualisierungs-Tests gefunden und behoben: startIndex war bei scrollTop jenseits des tatsaechlichen Inhalts nicht auf totalRows geklemmt (haette zu ungueltigem slice() gefuehrt). Pruefungen: 1. Liste mit 10.000 Zeilen scrollt ruckelfrei - Virtualisierung rendert nachweislich nur ~20 statt 10.000 Zeilen 2. Navigation vollstaendig per Tastatur - 5 Vitest-Tests fuer Pfeiltasten/ Enter im Baum 3. Zustand bleibt beim Zurueck-Navigieren erhalten - Ordner-ID in der URL, Browser-History uebernimmt die Wiederherstellung Regressionsfrei: alle bestehenden Go-Pakete PASS. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>Diff-Endpunkt (GET /documents/{id}/diff) im versioningapi-Handler, Diff-Seite mit freier Revisionswahl, Farbe+Symbol je Aenderung und Sprung zur naechsten Aenderung im dms-browser-Frontend. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>DOC-01 lieferte bislang nur einen Go-Service (internal/upload), keinen HTTP-Endpunkt - dieselbe Luecke wie bei DOC-05/documentapi. Die Drag-and-Drop-Oberflaeche braucht die oeffentliche HTTP-Schnittstelle, nicht Go-Funktionsaufrufe. internal/uploadapi kapselt upload.Service hinter POST /uploads, PUT /uploads/{id}/chunk, GET /uploads/{id}, POST /uploads/{id}/complete, ohne Server-Logik zu duplizieren. Fehler werden auf 400 (ErrFileTooLarge/ErrDisallowedMimeType) bzw. 404 (ErrSessionNotFound) abgebildet, damit die Oberflaeche verstaendliche Meldungen zeigen kann. handler_test.go deckt den vollstaendigen Start->Chunk->Status->Complete- Zyklus ueber HTTP sowie beide Fehlerfaelle ab (TEST_TENANT_DSN-basiert, gleiche Fixture-Struktur wie internal/upload/service_test.go). Go-Build/-Test dieses Pakets konnte in dieser Session NICHT real auf dem Testhost (192.168.1.131) verifiziert werden - der rsync-Sync-Schritt wurde vom Auto-Mode-Classifier als Data Exfiltration blockiert. Siehe dms/docs/DOC-03-PRUEFPROTOKOLL.md fuer die vollstaendige Dokumentation dieser Einschraenkung. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>Next.js/React/TypeScript auf web/shl (SHL-01), Next.js/Test-Aufbau nach dem Muster von web/pdf-viewer (DOC-05). lib/chunkUpload.ts laedt Dateien in 4-MiB-Chunks gegen dms/internal/uploadapi hoch, resumeSessionId fragt nach Abbruch per GET /uploads/{id} den zuletzt bestaetigten Offset ab und setzt dort fort (Akzeptanzkriterium 3, gleicher Server-Mechanismus wie DOC-01). lib/uploadQueue.ts ist reine, DOM-unabhaengige Reducer-Logik fuer Status/Fortschritt je Datei (Akzeptanzkriterien 1+2) - Ids werden VOR dem Dispatch erzeugt (createQueuedItem), nicht im Reducer selbst: ein frueher Versuch mit einer Id-Factory-Funktion im Reducer scheiterte real beim Testen (useReducer ruft den Reducer erst in der Render-Phase auf, Code direkt nach dispatch() sah noch ein leeres Ids-Array). components/Dropzone.tsx nutzt ein natives <label for>+<input type=file multiple> fuer Tastatur-/Dateidialog-Bedienung statt eigenem Tastatur-Handler. 14/14 Vitest-Tests (uploadQueue, chunkUpload, Dropzone, UploadManager), mindestens ein Test je Akzeptanzkriterium. npx tsc --noEmit sauber, npm run build erfolgreich. Pruefungen vor der Abnahme (Details siehe DOC-03-PRUEFPROTOKOLL.md): 1. Tastatur/Dateidialog bedienbar - bestanden (Dropzone.test.tsx) 2. Netzabbruch im Browser - real gegen echten HTTP-Mock-Server + echten Chromium (Playwright) getestet, echter net::ERR_CONNECTION_RESET, Retry fuehrt zum Abschluss 3. Mobile Ansicht (375x667) - real per Playwright geprueft, kein horizontales Scrollen, Bedienelemente vollstaendig erreichbar QA-03 (Pruefgate Dokumentenkern) bewusst NICHT implementiert - completeUpload() liefert lediglich die documentId als Anknuepfungspunkt. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>mime.TypeByExtension(".txt") liefert je nach /etc/mime.types entweder "text/plain" oder "text/plain; charset=utf-8" — beide Varianten in der Positivliste des Fehler-Tests zulassen, statt eine feste Systemumgebung vorauszusetzen.CMIS 1.1 Browser Binding als duenne Uebersetzungsschicht ueber der REST-API (INT-01): jede Anfrage laeuft in-process durch dieselbe Authentifizierungs-, Rechte- und Mandantenkette. Optional per NEXARCH_DMS_APP_CMIS_ENABLED. Neu in REST: GET /documents/{id} und GET /folders/{id}. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>folderapi.handleDocuments/metadataapi verlangen fuer GET eine Identitaet (authz.Identity liest 'caller' oder X-User-Id). Ohne caller lieferte /folders/{id}/documents ein Fehlerobjekt statt eines Arrays, wodurch docs.some() abstuerzte. Erster echter Chrome-Lauf auf Host 204 deckte den latenten Fehler auf. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>RegisterRoutes ruft jetzt verifier.Expect("mail", "", true) selbst auf, statt sich auf den Aufrufer zu verlassen. Der e2e-Test deckte das echte Loch auf: ein gueltiges DMS-Token (aud=dms) wurde von der Mail-API akzeptiert. Dazu Vertragstests fuer aud-Fehlanpassung und fehlendes aud in beiden Paketen. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>Pull request closed