Commit Graph
43 Commits
Author SHA1 Message Date
patrickandClaude Sonnet 5 38ba66e259 VER-07: digitale signatur - abhaengigkeit und pruefprotokoll
go.mod/go.sum um github.com/digitorus/pdfsign v0.9.0 ergaenzt (auf
192.168.1.131 aufgeloest, keine Go-Toolchain lokal verfuegbar). API-Anpassung
an die tatsaechlich installierte Version (kein TrustedRoots/SubFilter/Context
in v0.9.0, andere Signer.Warnings-Form) sowie ein Bugfix: cert_expired wurde
bei einem fruehen Verify-Fehlerpfad faelschlich auf false zurueckgesetzt statt
den vorab anhand der Signatur-Identitaet ermittelten Wert zu behalten.

Alle vier automatisierten Tests real auf 192.168.1.131 gruen, inklusive
echtem RFC-3161-Aufruf gegen freetsa.org. Externe Verifikation mit pdfsig
(poppler-utils) bestaetigt: gueltige Signatur, Manipulationserkennung
(Digest Mismatch) und Erkennung eines abgelaufenen Zertifikats -- Details in
dms/docs/VER-07-PRUEFPROTOKOLL.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-18 15:01:48 +02:00
patrickandClaude Sonnet 5 9360593a18 VER-07: digitale signatur
PAdES-Signatur (ETSI EN 319 142, SubFilter ETSI.CAdES.detached) je
Datei-Revision ueber github.com/digitorus/pdfsign, mit optionalem
RFC-3161-Zeitstempel (TSAURL). Neue Tabelle revision_signatures folgt dem
Zustands-Muster von revision_pdf_derivatives (DOC-06). Signiert wird immer
eine PDF-Form: Original direkt falls schon PDF, sonst das bestehende
DOC-06-Derivat, kein zweiter Konvertierungspfad. Nach dem Signieren wird
sofort verifiziert, damit das Pruefergebnis am Dokument angezeigt werden
kann.

go.mod/go.sum-Eintrag fuer die neue Abhaengigkeit folgt in einem separaten
Commit (Aufloesung auf 192.168.1.131, kein Go-Toolchain lokal verfuegbar).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-18 14:56:00 +02:00
patrickandClaude Sonnet 5 da73a8609d DOC-06: pruefprotokoll dokumentieren
Zielwert vs. real erreichtes Ergebnis fuer alle drei Pflichtpruefungen
festgehalten. Layouttreue und Absturzsicherheit gegen echten soffice-Prozess
bleiben offen, da LibreOffice auf 192.168.1.131 nicht installiert ist (grosser,
unueblicher Fussabdruck laut apt-get --dry-run, daher vor Installation
zurueckgemeldet statt blind installiert). Zeitlimit real verifiziert,
inklusive eines dabei gefundenen echten exec.Cmd-Pipe-Hangs und dessen Fix.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-18 13:12:13 +02:00
patrickandClaude Sonnet 5 5ed5b32b57 DOC-06: waitdelay gegen pipe-hang bei zeitlimit-ueberschreitung
Realer Testfund auf 192.168.1.131: ein Kindprozess, der seinerseits (ohne
exec) einen Enkelprozess startet, haelt nach SIGKILL des direkten Kindes
dessen Ausgabe-Pipe weiter offen - cmd.Wait() blockiert dann trotz
abgelaufenem Kontext unbegrenzt. cmd.WaitDelay (Go 1.20+) begrenzt das.
Testfixture (hanging-soffice.sh) ebenfalls auf "exec sleep" korrigiert.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-18 13:11:08 +02:00
patrickandClaude Sonnet 5 3fc02ed697 DOC-06: office-zu-pdf-konverter
Neues Paket internal/pdfconvert nach dem Muster von internal/thumbnail
(DOC-04): Konvertierung von Office-Formaten (docx/xlsx/pptx, odt/ods/odp,
doc/xls/ppt) zu PDF als Vorschau-/Archivderivat der Datei-Revision, ueber
FDN-04 (internal/jobqueue) asynchron mit Wiederholung/Backoff/DLQ verarbeitet.

- format.go: einzige Format-/Endungs-Zuordnungsstelle (MIME -> Endung/Label)
  mit Property-Test, statt paralleler Kopien in Konvertierungsfunktionen
  (siehe "Bekannte Fehler vermeiden" im Ticket).
- convert.go: Generator ruft headless soffice ueber exec.CommandContext mit
  Zeitlimit auf, eigenes Temp-/Profilverzeichnis je Aufruf (Isolation, kein
  geteilter Zustand zwischen gleichzeitigen Konvertierungen).
- pdfconvert.go: State-Machine (pending/processing/ready/failed) in neuer
  Tabelle revision_pdf_derivatives (Migration 0016), ein Zustand je
  Datei-Revision, analog revision_thumbnails.
- VER-07 (digitale Signatur) und QA-03 (Pruefgate) bewusst nicht
  implementiert, keine Schnittstelle dafuer noetig (reines Ablegen eines
  weiteren Revisions-Derivats, keine Bearbeitungs-/Freigabe-Schnittstelle
  betroffen).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-18 13:07:06 +02:00
patrickandClaude Sonnet 5 79c4458618 DOC-18: obergrenze fuer gesamtgroesse/anzahl bei archiv-buendelung
Enqueue prueft konfigurierbare Obergrenzen (Dokumentanzahl, Gesamtgroesse)
VOR dem Anlegen des Auftrags/Einreihen des Jobs und lehnt Ueberschreitungen
mit konkreter Fehlermeldung ab, statt den Job-Worker-Pool zu belasten.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-18 00:55:36 +02:00
patrickandClaude Sonnet 5 df0234d30c DOC-08: massenexport als zip
Export laeuft als jobqueue-Job (blockiert nicht), streamt das ZIP direkt
via io.Pipe in den Objekt-Storage (kein vollstaendiger Aufbau im Speicher),
fuegt eine manifest.csv-Metadaten-Beilage hinzu und ueberspringt Dokumente
ohne Berechtigung statt sie stillschweigend einzuschliessen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-18 00:53:01 +02:00
patrickandClaude Sonnet 5 4507e7f861 DOC-07: download & signierte urls
downloadapi: HMAC-signierte, zeitlich befristete Download-URLs fuer die
verschluesselten Originale. Berechtigung wird beim Ausstellen geprueft
(DocumentOwnerChecker), die Signatur selbst ist danach der Zugriffsnachweis.
RFC-5987-Dateinamenkodierung fuer Sonderzeichen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-18 00:48:14 +02:00
patrickandClaude Sonnet 5 43574f7872 DOC-17: malware-scan-vor-ablage
ClamAV-Anbindung (clamd-INSTREAM-Protokoll) als verpflichtender Scan-Schritt
vor Ablage. Fund fuehrt zu vollstaendiger Entfernung von Dateiobjekt und
Dokument plus Audit-Event statt stiller Ablage; Sichtbarkeit in
Listen/Direktzugriff gesperrt bis scan_status=clean. EICAR-Erkennung real
gegen installierten clamd verifiziert (dabei Null-Byte-Antwort-Bug
gefunden und behoben).

Nebenbei: fehlende trashed_at-Spalte in drei Test-Schemata (DOC-11-Luecke)
nachgetragen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-18 00:41:52 +02:00
patrickandClaude Sonnet 5 4dcc6488c4 VER-08: technische durchsetzung append-only fuer audit_log
REVOKE UPDATE/DELETE fuer die nexarch_app-Gruppenrolle auf audit_log
(analog zu Core AUD-07), Trigger protokolliert Aenderungsversuche zusaetzlich
per RAISE WARNING vor der Ablehnung. VerifyChain bleibt unveraendert
funktionsfaehig.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-18 00:28:30 +02:00
patrickandClaude Sonnet 5 54e322f1e1 VER-06: audit-log-ansicht & export
audittrail.ListFiltered (Zeitraum/Akteur/Aktion) + auditapi (Liste,
gestreamter CSV-Export, Allowlist-Zugriffspruefung) als Backend-
Voraussetzung. Audit-Log-Seite im dms-browser mit Filterformular und
Export derselben gefilterten Menge.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-18 00:24:59 +02:00
patrickandClaude Sonnet 5 6a5a455b2c MET-03: metadaten- & tag-oberfläche
metadataapi/tagapi/bulkeditapi als Backend-Voraussetzung. MetadataForm
passt sich der Felddefinition an und warnt vor Verwerfen ungespeicherter
Aenderungen, TagInput schlaegt Tags vor und ist per Pfeiltasten/Enter
bedienbar, Massenbearbeitung wendet Tags auf beliebig grosse Auswahlen in
einem Aufruf an.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-18 00:17:13 +02:00
patrickandClaude Sonnet 5 533efa891c DOC-13: akten vorgangsanzeige im dokumentkontext
CasePanel zeigt Akte-Zugehoerigkeit, Vermerke und offene Wiedervorlagen in
der Dokument-Detailansicht ueber die externe Workflow-Board-API (VOR-04) an.
Kein eigenes Akte-Datenmodell, Ausfall der externen API blockiert nur diesen
Bereich.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-18 00:08:16 +02:00
patrickandClaude Sonnet 5 19776bdc24 DOC-12: papierkorb-oberfläche
trashapi (Liste mit Restlaufzeit, Massen-/Einzelwiederherstellung,
sofortige endgueltige Loeschung) als Backend-Voraussetzung, Papierkorb-Seite
im dms-browser mit Bestaetigungsdialog vor jeder endgueltigen Loeschung.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-18 00:04:29 +02:00
patrickandClaude Sonnet 5 f81aae9574 MET-04: dokumententypen & vorlagen
Dokumententypen buendeln Pflichtfelder, Standard-Tags und Aufbewahrungs-
vorgabe. Typwechsel erzwingt Pflichtfelder und verlangt Bestaetigung bei
drohendem Datenverlust statt stillschweigend zu loeschen. Ordner-Vorbelegung
greift automatisch beim Upload.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-17 23:51:27 +02:00
patrickandClaude Sonnet 5 16cdfa9a16 DOC-15: massenbearbeitung von metadaten
bulkedit.Apply orchestriert Tag-/Metadatenfeld-Massenaenderungen ueber eine
Dokumentauswahl, ueberspringt gesperrte Dokumente einzeln (VER-01-Sperre als
Platzhalter fuer eine spaetere Archive-Retention-Pruefung) und schreibt einen
Audit-Log-Eintrag pro Vorgang.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-17 23:46:00 +02:00
patrickandClaude Sonnet 5 f7179efb8d DOC-11: soft-delete & papierkorb-logik
trashed_at (Dokumente+Ordner) als reversibler Papierkorb-Status, getrennt von
deleted_at (DOC-16: endgueltige Vernichtung). Kaskadierendes Loeschen/
Wiederherstellen von Ordnerteilbaeumen ueber Materialized Path, PurgeExpired
als Aufraeum-Job (entfernt Dateiobjekte + Datenbankzeile nach Frist).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-17 23:40:16 +02:00
patrickandClaude Sonnet 5 b5cee200db VER-04: diff-ansicht
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>
2026-09-17 23:31:57 +02:00
patrickandClaude Sonnet 5 76704330eb VER-03: änderungshistorie & diff-berechnung
Myers-Zeilendiff (DiffText) und Metadaten-Vorher-Nachher (DiffMetadata) im
versioning-Paket, DiffRevisions als fertige Schnittstelle für VER-04.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-17 23:21:00 +02:00
patrickandClaude Sonnet 5 64af627495 VER-02: Versionsansicht & Wiederherstellung
versioning.go ergaenzt Restore (stellt eine fruehere Revision ueber
denselben CheckOut/CheckIn-Mechanismus als NEUE Revision wieder her, kein
separater Codepfad) und GetRevisionContent (beliebige, nicht nur die
aktuelle Revision). Revision.CreatedBy ergaenzt fuer Autor-Anzeige.

internal/versioningapi: Liste/Content/Restore als HTTP-Endpunkte.
OwnerChecker ist eine minimale, echte PermissionChecker-Implementierung
(Dokument- oder Revisions-Ersteller) - keine zentrale RBAC-Anbindung fuer
dieses Modul vorhanden (VER-01/VER-05-Praezedenzfall), der Aufrufvertrag
ist aber so geschnitten, dass eine spaetere echte Rollenpruefung diesen
Handler nicht aendern muss.

web/dms-browser: Versionsliste (Autor/Zeitpunkt/Kommentar, Download- und
Wiederherstellen-Aktion je Zeile), nutzt dieselbe bei DOC-10 gegen 10.000
Zeilen bewiesene Virtualisierungs-Logik.

Pruefungen:
1. Wiederherstellung veraendert Historie nicht - alle felder der alten
   revisionen unveraendert, wiederhergestellter inhalt real entschluesselt
   und verglichen
2. 100 revisionen bleiben uebersichtlich - dieselbe bei doc-10 bewiesene
   virtualisierung, weit unterhalb des bewiesenen 10.000er-bereichs
3. berechtigung wird JE revision geprueft - nicht-ersteller sieht
   accessible:false und bekommt 403, ersteller kann zugreifen (200)

Regressionsfrei: go test ./... -p 1 alle pakete PASS, 22/22 vitest-tests.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-17 21:26:15 +02:00
patrickandClaude Sonnet 5 1aedd2ed67 VER-01: Versionsmodell & Check-in/Check-out
Migration 0010: document_locks (Ausleih-Sperre mit Lease-Frist) und
file_revisions.comment (Check-in-Kommentar gehoert zur neuen Revision).

internal/versioning: CheckOut (atomar via INSERT...ON CONFLICT...WHERE
lease_until < now(), Postgres entscheidet pro Zeile, wer bei
gleichzeitigen Versuchen gewinnt), ForceUnlock, CheckIn (prueft
Sperrinhaberschaft, verschluesselt+speichert als NEUE Revision, gibt
Sperre frei), ListRevisions.

Pruefungen:
1. Zwei gleichzeitige Ausleihversuche - nur einer gewinnt
2. Verwaiste Sperre (10ms Frist) wird automatisch geloest
3. Alte Revision nach Check-in real aus Storage geladen, entschluesselt
   und byteweise unveraendert verifiziert

RBAC-Rollenpruefung fuer ForceUnlock (Akzeptanzkriterium 3: "durch
Administratoren aufhebbar") ist Sache einer HTTP-Schicht, die fuer diese
Kachel noch nicht existiert - gleiche Scope-Entscheidung wie VER-05.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-17 21:11:05 +02:00
patrickandClaude Sonnet 5 ed15ce12cf VER-05: Revisionssicherer Audit-Trail (Hash-Kette, Append-only)
Migration 0009: audit_log mit BEFORE UPDATE/DELETE-Trigger, der jede
Zeilenmutation technisch ablehnt (kein Anwendungskonvention). Jeder
Eintrag ist per SHA-256 mit seinem Vorgaenger verkettet.

internal/audittrail: Append (mit Advisory-Lock gegen Wettlaufsituationen
in der Hash-Kette), List, VerifyChain (rechnet die gesamte Kette nach
statt einem gespeicherten Flag zu vertrauen).

Pruefungen:
1. Manipulationsversuch erkannt - gefaelschter Eintrag per direktem
   INSERT (Trigger blockiert nur UPDATE/DELETE) mit erfundenem
   entry_hash wird von VerifyChain zuverlaessig erkannt
2. Vollstaendigkeit gegen 3 Referenzoperationen abgeglichen
3. Protokollschreiben verlangsamt Kernoperationen nicht spuerbar -
   1,68ms je Append im Schnitt (Budget 20ms)

RBAC-02 (Ausgangslage) beruehrt keine der Akzeptanzkriterien/Pruefungen
direkt (reine Protokollmechanik) - Zugriffsbeschraenkung auf einen
kuenftigen Lese-Endpunkt ist Sache einer Folgekachel mit HTTP-Schicht.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-17 21:06:02 +02:00
patrickandClaude Sonnet 5 14dec26612 MET-02: Benutzerdefinierte Metadatenfelder (Typ, Pflicht, Standard, Validierung)
Migration 0008 ergaenzt required/default_value/validation_rule (JSONB)
und eine Versionsnummer auf metadata_fields, plus die ausschliesslich
anfuegbare metadata_field_versions-Historie - jede Aenderung einer
Felddefinition (auch Typwechsel) erhoeht die Version und haengt einen
neuen Eintrag an, aendert nie einen bestehenden.

internal/metadatafield: Create/Update/Get/ListAll/Validate/SetValue/
ValueFor/Versions. Validate deckt alle 5 Feldtypen ab (text: optionales
Regex-Muster, number: min/max, date: JJJJ-MM-TT, bool: true/false,
select: Options-Liste). SetValue validiert VOR dem Speichern.

Pruefungen:
1. Ungueltiger Wert abgewiesen mit feldbezogener Meldung (*ErrValidation)
2. Typaenderung mit Bestandsdaten: altes Datum bleibt lesbar/unveraendert,
   erneutes Speichern desselben Werts greift gegen die NEUE Regel
3. Pflichtfeld ohne Standardwert blockiert leeren Wert, MIT Standardwert
   nicht

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-17 20:58:27 +02:00
patrickandClaude Sonnet 5 c7652e91e5 MET-01: Tag-Modell & Tag-API (Farbe, Hierarchie, Zusammenfuehren)
Migration 0007 ergaenzt tags.color/parent_tag_id (Ticket-Auftrag: Farbe
und optionale Hierarchie - FDN-02 legte nur die flache Entitaet an).

internal/tag: Create/Rename/Get/ListAll/ListForDocument/Assign/Unassign/
BulkAssign/Delete/Merge. Listen-Funktionen liefern grundsaetzlich []
statt nil (siehe "Bekannte Fehler vermeiden"). Merge uebertraegt alle
Zuordnungen des Quell-Tags auf den Ziel-Tag (ON CONFLICT DO NOTHING nur
gegen doppelte Kombinationen, keine Zuordnung geht verloren) und loescht
den Quell-Tag. Loeschen eines Tags entfernt ueber ON DELETE CASCADE nur
die document_tags-Zeilen, nie das Dokument selbst.

Pruefungen:
1. Zusammenfuehren erhaelt alle Zuordnungen, auch bei vorheriger
   Doppelzuordnung eines Dokuments
2. Doppelte Tag-Namen verhindert (Anlegen UND Umbenennen)
3. Massenzuweisung an 500 Dokumente: 14,4ms (Budget 2s) ueber ein
   einziges INSERT...SELECT unnest(...)-Statement

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-17 20:37:32 +02:00
patrickandClaude Sonnet 5 e973457d1a DOC-10: Ordner-Navigation & Dokumentenliste
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>
2026-09-17 20:22:09 +02:00
patrickandClaude Sonnet 5 51edffedb7 DOC-09: Ordner- & Kabinettmodell (Materialized Path)
Migration 0006 ergaenzt folders.path (Materialized Path aus Ordner-IDs,
text_pattern_ops-Index) - Teilbaum-Abfragen werden damit zu einem
Index-Scan statt einer rekursiven CTE ueber parent_folder_id. Pfad
besteht aus IDs, nie aus Namen, daher aendert Umbenennen nie einen Pfad.

internal/folder: Create/Get/Rename/Move/Subtree. Move aktualisiert den
gesamten Teilbaum in einer einzigen UPDATE-Anweisung (Praefix-Ersetzung)
und verhindert Zyklen (Ziel ist der Ordner selbst oder ein eigener
Nachfahre).

Pruefungen:
1. Zyklus beim Verschieben verhindert (3 faelle: selbst, kind, enkel)
2. Teilbaum-Abfrage bei 10.001 Ordnern: 28,4ms (Budget 500ms)
3. Umbenennen aendert pfad von ordner UND kindern nachweislich nicht

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-17 20:10:49 +02:00
patrickandClaude Sonnet 5 411b997b94 DOC-05: PDF-Viewer-Komponente
internal/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>
2026-09-17 19:58:00 +02:00
patrick 4c283029e1 Merge branch 'feature/shl-01-ui-shell-design-system-zentral' into feature/doc-05-pdf-viewer-komponente 2026-09-17 19:46:10 +02:00
patrickandClaude Sonnet 5 08584b0c5f DOC-04: Vorschau- & Thumbnail-Pipeline
internal/thumbnail: Vorschau-Zustand je Datei-Revision als explizite
State-Machine (pending/processing/ready/failed, revision_thumbnails)
statt Ableitung aus Dateiendung. Content-Type wird ausschliesslich ueber
Magic-Bytes bestimmt (net/http.DetectContentType gegen die entschluesselten
Bytes) - der in "Bekannte Fehler vermeiden" beschriebene Fehler eines
Vorgaengerprojekts (fragile Erkennung ueber Dateiendung) wird damit
vermieden.

PDF-Rasterung ueber pdftoppm (Poppler), Bild-Thumbnails ueber einen
minimalen, abhaengigkeitsfreien Nearest-Neighbor-Resizer auf Basis der
Standardbibliothek. Original wird ueber FDN-09 (dmscrypto) entschluesselt,
Thumbnail wird ebenfalls verschluesselt im Objekt-Storage abgelegt -
gleiches Schutzniveau wie das Original.

upload.Service bekommt SetThumbnailEnqueuer (neue, optionale Methode -
bestehende Aufrufer/Tests unveraendert funktionsfaehig) und reiht nach
erfolgreichem Complete() die Vorschau-Erzeugung ein; ein Fehlschlag dabei
laesst den bereits abgeschlossenen Upload nicht ruecktwirkend fehlschlagen.

Pruefungen:
1. Beschaedigte PDF-Datei -> Fehlerstatus statt Absturz, blockiert andere
   Jobs nicht (echter pdftoppm-Fehlschlag, echte SKIP-LOCKED-Job-Queue)
2. Durchsatztest: 500 echte PDFs, alle erfolgreich, ~15s Gesamtlaufzeit
3. Cache-Invalidierung bei neuer Revision: GetCurrentForDocument loest
   nachweislich auf die neue statt die alte Revision auf

Regressionsfrei: 13 bestehende upload-/jobqueue-Tests unveraendert PASS.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-17 19:42:30 +02:00
sysops 9843275e9c DOC-16: ret-05-client-aufbewahrungsklasse-registrieren-vernichtungs-rueckruf
- dms/internal/retentionclient: HTTP-Client fuer Archive RET-05/RET-09
- dms/internal/retentiondestroy: RegisterOrRequeue (FDN-04-Requeue bei
  Fehlschlag, kein Absturz/stilles Verwerfen), DestroyCallbackHandler
  (physische Loeschung aller Datei-Revisionen ueber storage.Service,
  markiert Dokument als vernichtet, 2xx erst danach)
- dms/cmd/app: mountet destroy-callback, registriert beim Start
- dms/cmd/worker: verarbeitet Requeue-Jobs (Retry)
- nur dms_document registriert (DOC-01/FDN-02 kennen keinen separaten
  Anhang-Typ, kein Umbau angrenzender Bereiche)
- real getestet: registrierung gegen echten fake-RET-05-Server, echte
  Loeschung inkl. Storage-Byte-Nachweis, echter Requeue-Eintrag bei
  Fehlschlag, erfolgreicher Retry
- live auf 131 gegen echten RET-09-Dienst (Port 8095) verifiziert,
  echter curl-Vernichtungs-Rueckruf mit real geloeschter Datei
- reale Core-API-06-Deploy-Luecke dokumentiert (nicht verschwiegen):
  /internal/resync/usage auf 131 aktuell nicht gemountet

Pruefungen siehe dms/docs/DOC-16-PRUEFPROTOKOLL.md
2026-08-30 09:37:12 +02:00
sysopsandClaude Sonnet 5 9a374dd91e DOC-01: upload-api & chunk-handling
Fortsetzbarer Server-seitiger Upload: upload_sessions (bytes_received,
GREATEST-Update verhindert Rueckschritt bei erneut zugestellten Chunks),
Staging via os.File.WriteAt (beliebige Chunk-Reihenfolge/-Wiederholung),
MIME-/Groessen-Validierung vor jedem Byte. Complete() liest Klartext einmal
via io.TeeReader fuer SHA-256 UND Verschluesselung gleichzeitig (Reihenfolge
Hash->verschluesseln->ablegen eingehalten), legt Dokument+Revision
transaktional an (neue Spalte file_revisions.wrapped_dek fuer FDN-09).

Auf 192.168.1.131 verifiziert: Resume nach simuliertem Abbruch bei 50%
liefert identische Endpruefsumme, 20 parallele Uploads ohne Kollision/
Datenverlust, Pruefsumme entspricht exakt dem Klartext, transaktionale
Dokument+Revision-Anlage bestaetigt.

Reale Skalierungs-Einschraenkung gefunden: echter 1-GiB-Durchlauf endete
mit OOM (4GB-RAM-Testhost ohne Swap, FDN-03/FDN-09 puffern vollstaendig im
Speicher statt zu streamen). Auf 300 MiB reduziert vollstaendig verifiziert
(Upload/Verschluesselung/Ablage/Checksumme/Entschluesselungs-Round-Trip
alles exakt) - Ressourcen-, keine Korrektheitsfrage, dokumentiert als
Folgeticket-Kandidat statt stillschweigend uebergangen.

Siehe dms/docs/DOC-01-PRUEFPROTOKOLL.md fuer alle Pruefungsergebnisse.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HhgFcLS8tYMhDJpP74C6AQ
2026-08-29 22:23:36 +02:00
sysopsandClaude Sonnet 5 bf7559e118 FDN-09: verschluesselung at rest & schluesselverwaltung
Envelope-Encryption: DEK (32 Byte) frisch je Objekt, AES-256-GCM fuer
Objektinhalt, DEK selbst mit Tenant-KEK verpackt (WrapDEK/UnwrapDEK). KEK
kommt ausschliesslich ueber HTTPKEKProvider von Core API-10
(internal/kek.Handler.TenantKEKHandler-Vertrag, Service-Credential-
authentifiziert), wird nie persistiert - jeder Seal/Open-Aufruf bezieht ihn
frisch. RewrapDEK fuer KEK-Rotation ohne Neuverschluesselung der Objekte
(nur der DEK-Wrapper wird neu verpackt, Chiffretext bleibt unveraendert).

Auf 192.168.1.131 verifiziert: Round-Trip Encrypt/Decrypt, manipulierter
Chiffretext UND falscher Schluessel werden beide ueber GCM-Auth-Tag
abgelehnt, KEK-Rotation real getestet (RewrapDEK, altes Objekt danach mit
neuem KEK weiterhin lesbar, alter KEK funktioniert nicht mehr).

Befund dokumentiert: Cores internal/kek.Handler (Gegenstelle fuer den
KEK-Bezug) ist noch in keinem cmd/*/main.go verdrahtet, dieselbe
Fehlerklasse wie FDN-03/QA-05/AUD-06. HTTPKEKProvider daher gegen den
dokumentierten Vertrag getestet, nicht gegen eine laufende Core-Instanz.
Siehe dms/docs/FDN-09-PRUEFPROTOKOLL.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HhgFcLS8tYMhDJpP74C6AQ
2026-08-29 22:13:49 +02:00
sysopsandClaude Sonnet 5 bfea94b032 FDN-04: job-queue & worker-runtime
Postgres-Jobqueue (processing_jobs, FOR UPDATE SKIP LOCKED), In-Prozess-
Worker-Goroutinen, kein Redis/AMQP. Enqueue mit Idempotency-Key-Dedup,
Dequeue mit Stale-Lock-Wiedervorlage (Absturzsicherheit), Fail mit
arithmetischem Backoff und Dead-Letter-Queue nach erschoepften Versuchen,
RequeueDeadLetter fuer manuelle Wiederholung.

Auf 192.168.1.131 verifiziert: Absturz-Wiedervorlage (Job von einem
"abgestuerzten" Worker nie completed/failed, zweiter Worker holt ihn nach
Ablauf der Sperre erneut), Idempotenz bei Doppelzustellung (gleicher
idempotency_key erzeugt nur 1 Zeile), DLQ-Eintrag manuell wiederholbar.

Vier reale Fehler beim Testen gefunden und behoben: zwei pgx-Typinferenz-
Bugs im SQL-Parameterhandling (toter workerID-Parameter ohne Referenz in
der Query; untypisiertes any statt []string fuer den ::text[]-Cast), sowie
zwei Testinfrastruktur-Bugs (dms_tenant_test sammelte schema_migrations-
Zustand ueber Sitzungen hinweg an, jobqueue-Testfixture raeumte
processing_jobs nicht auf) - neues scripts/reset-test-env.sh + make check
(-p 1) analog Core behoben.

Siehe dms/docs/FDN-04-PRUEFPROTOKOLL.md fuer alle Pruefungsergebnisse.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HhgFcLS8tYMhDJpP74C6AQ
2026-08-29 20:58:26 +02:00
sysopsandClaude Sonnet 5 a9ede93176 FDN-03: Protokoll ergaenzt - offener Punkt Pruefsummen-Schreibpfad
checksum_sha256 (FDN-02) wird von keinem Schreibpfad in FDN-03 befuellt.
Nachgetragen als AC/Pruefung in DOC-01 (Upload-API), Voraussetzung fuer
Archive BAK-08 (neues Ticket: Checksum-basierte Objekt-Integritaetspruefung
fuer extern eingebundenes, nicht selbst ueberwachtes Kunden-S3-Storage).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HhgFcLS8tYMhDJpP74C6AQ
2026-08-29 20:33:35 +02:00
sysopsandClaude Sonnet 5 442bb674e9 FDN-03: objekt-storage-abstraktion
Ein Driver-Interface, zwei austauschbare Treiber: LocalDriver (Entwicklung,
Dateisystem, HMAC-signierte URLs) und S3Driver (Produktion, S3-kompatibel
via aws-sdk-go-v2, echte presigned URLs). Pfadschema documents/<id>/
revisions/<id> innerhalb des mandantenspezifischen Buckets. Service
verbindet Driver mit Nutzungsmeldung an Core LIC-05 (HTTPUsageReporter,
Vertrag von internal/resync.Handler nachgebildet, DMS kann Cores internal/-
Pakete als eigenes Modul nicht importieren).

Auf 192.168.1.131 verifiziert, S3-Treiber gegen echtes lokal installiertes
MinIO (kein Mock): Round-Trip beide Treiber, abgelaufene presigned URL real
mit 403 abgewiesen (manuell zusaetzlich zum Unit-Test verifiziert), klare
ErrNotFound bei fehlendem Objekt beide Treiber, Nutzungsmeldung mit
korrektem Tenant/Metrik/Delta bei Put/Delete.

Befund dokumentiert: Cores internal/resync.Handler (Gegenstelle fuer die
Nutzungsmeldung) ist noch in keinem cmd/*/main.go verdrahtet (dieselbe
Fehlerklasse wie QA-05/AUD-06) - HTTPUsageReporter daher gegen den
dokumentierten Vertrag getestet, nicht gegen eine laufende Core-Instanz.
Siehe dms/docs/FDN-03-PRUEFPROTOKOLL.md.

golangci-lint auf v2.1.6 aktualisiert (v1.63.4 konnte go1.24-Zielstand
nicht linten), .golangci.yml auf v2-Konfigurationsformat migriert.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HhgFcLS8tYMhDJpP74C6AQ
2026-08-29 19:22:54 +02:00
sysopsandClaude Sonnet 5 9d4c2bae4a FDN-02: datenmodell & migrationen
Kern-Entitaeten (Dokument, Datei-Revision, Ordner, Tag, Metadatenfeld) als
tenant-scoped SQL-Migration (Modell C, keine tenant_id-Spalte), FK auf
users(id) aus Core IAM-01 (Auth bleibt vollstaendig in Core). Eigener,
minimaler Migrations-Runner (internal/migrate, kein ORM) mit
schema_migrations-Tracking fuer Idempotenz. Seed-Skript fuer Entwicklung.

Auf 192.168.1.131 verifiziert: Migration auf leerer+bestehender DB,
Rollback stellt Vorzustand wieder her, 4 FK-Negativtests, Seed-Skript
end-to-end gegen frische DB. go.sum committet (Lock-Datei-Lehre aus dem
Ticket). build/vet/lint/test clean.

Siehe dms/docs/FDN-02-PRUEFPROTOKOLL.md fuer alle Pruefungsergebnisse.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HhgFcLS8tYMhDJpP74C6AQ
2026-08-29 19:07:02 +02:00
sysopsandClaude Sonnet 5 08d54715d4 FDN-01: repository & projektgerüst
DMS-Modul-Grundgerüst als Unterordner im bestehenden nexarch-Monorepo
(dms/), eigenes Go-Modul (gitea.perlbach24.de/scripte/nexarch/dms),
getrennt von Core. App/Worker-Trennung nach paperless-ngx-Vorbild (lange
Aufgaben blockieren nie eine Anfrage): cmd/app (HTTP, /healthz),
cmd/worker (Hintergrund-Dienst-Stub), internal/shared.

golangci-lint (govet/staticcheck/errcheck/unused/ineffassign/gofmt/
goimports) + Makefile-Targets (install/run/lint/fmt/test). Auf
192.168.1.131 verifiziert: build/fmt/lint/test clean, absichtlich
eingefuegter Lint-Verstoss bricht den Build wie gefordert ab (Exit 2),
make run startet App+Worker und /healthz antwortet innerhalb 2s.

Siehe dms/docs/FDN-01-PRUEFPROTOKOLL.md fuer alle Pruefungsergebnisse.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HhgFcLS8tYMhDJpP74C6AQ
2026-08-29 17:32:35 +02:00
sysops bfa5c61db5 SHL-01: fix — Test-Cleanup zwischen Dialog-Tests (afterEach(cleanup), sonst stapeln sich gerenderte DOM-Bäume) 2026-08-28 22:01:56 +02:00
sysops 3c226dab12 SHL-01: fix — vitest jsdom-environment + jest-dom-Setup (3 Dialog-Tests schlugen ohne DOM fehl) 2026-08-28 21:55:34 +02:00
sysops 584cefa388 DEVLOG: Sessionlog-Eintrag (Auto-Hook) 2026-08-28 21:45:55 +02:00
sysops 00665592f6 SHL-01: ui-shell-design-system-zentral (tokens, theming, i18n-rahmen, basis-komponenten) 2026-08-28 21:41:56 +02:00
sysops c895a67c4b core: initial Go module skeleton (config, db pool, tenant registry migration) 2026-08-27 17:27:59 +02:00
sysops 72261cc69f first commit 2026-08-27 17:20:02 +02:00