# CLAUDE.md ## Zweck Dieses Repository implementiert einen lokal gestarteten **PDF-Umbenenner mit KI**. Das Programm liest bereits OCR-verarbeitete, durchsuchbare PDF-Dateien aus einem Quellordner, ermittelt daraus einen normierten Dateinamen und legt **eine Kopie** der Datei im Zielordner ab. Die Quelldatei bleibt unverändert. Ab V2.0 wird die Anwendung um eine **lokale JavaFX-Desktop-GUI** erweitert. Die GUI ist der neue Standardstart. Der bestehende headless Batch-Betrieb bleibt über `--headless` vollständig erhalten. ## Autoritative Dokumente @docs/specs/technik-und-architektur.md @docs/specs/fachliche-anforderungen.md @docs/specs/meilensteine-v2_0.md Für die Umsetzung ist zusätzlich immer das aktuell aktive Arbeitspaket unter `docs/workpackages/` maßgeblich. Dateinamensschema: `M9 - Arbeitspakete.md`, `M10 - Arbeitspakete.md`, … `M13 - Arbeitspakete.md` Nicht raten, wenn Dokumente fehlen, unklar sind oder sich widersprechen. ## Priorisierung der Regeln Die Dokumente haben folgende feste Bedeutung: - `docs/specs/technik-und-architektur.md` = verbindliche technische Zielarchitektur - `docs/specs/fachliche-anforderungen.md` = verbindliche fachliche Regeln - `docs/specs/meilensteine-v2_0.md` = verbindliche V2.0-Zieldefinition und Meilensteinabgrenzung - `docs/workpackages/...` = verbindlicher Scope, Reihenfolge und Inhalt des aktuell bearbeiteten Arbeitspakets Bei Konflikten gilt folgende Priorität: 1. **Technik- und Architektur-Dokument** Verbindliche technische Zielarchitektur. Architekturbrüche sind unzulässig. 2. **Fachliche Anforderungen** Verbindliche fachliche Regeln und fachliches Zielverhalten. 3. **Meilensteine V2.0** Verbindliche Zieldefinition, Abgrenzungen und Leitplanken für den V2.0-Ausbau. 4. **Arbeitspakete** Definieren den konkret erlaubten Umsetzungsumfang des aktuellen Schritts. Wenn Dokumente fehlen, unklar sind oder sich widersprechen, nicht raten und keine stillen Annahmen treffen. ## Unverrückbare Technikvorgaben - Java 21 - Maven Multi-Module - ausführbares Standalone-JAR (ein gemeinsames JAR für GUI und headless) - **GUI ist der neue Standardstart** (ab V2.0) - `--headless` startet weiterhin den bestehenden Batch-/Scheduler-Betrieb - `--config ` steht für GUI und headless zur Verfügung - kein Webserver - kein Applikationsserver - keine Dauerlauf-Anwendung - kein interner Scheduler - keine EXE, kein Installer - Log4j2 für Logging - SQLite als lokaler Persistenzspeicher - JavaFX wird mit dem JAR ausgeliefert (kein separates JavaFX-Setup) - GUI offiziell nur für Windows; headless bleibt für Windows Server / Task Scheduler geeignet - gemappte Laufwerke wie `S:\` oder `H:\` sind ausdrücklich zu unterstützen - KI-Anbindung über genau **eine** der beiden unterstützten Provider-Familien: - **OpenAI-kompatible HTTP-Schnittstelle** (Chat-Completions-Stil) - **native Anthropic Messages API** (Claude-Modelle) - Pro Lauf ist genau ein Provider aktiv. Kein Fallback, keine Parallelnutzung. - `.properties` bleibt die einzige Konfigurationswahrheit - Konkrete Provider-Familie, Base-URL und Modellname sind **Konfiguration**, keine Architekturentscheidung. ## Verbindliche Modulstruktur (ab V2.0) - `pdf-umbenenner-domain` - `pdf-umbenenner-application` - `pdf-umbenenner-adapter-in-cli` - `pdf-umbenenner-adapter-in-gui` - `pdf-umbenenner-adapter-out` - `pdf-umbenenner-bootstrap` ## Architekturregeln - Strikte **hexagonale Architektur / Ports and Adapters** - Abhängigkeiten zeigen immer **nach innen** - Domain kennt **keine** Infrastruktur, keine Datenbank, kein Dateisystem, keine HTTP-Kommunikation und **kein JavaFX** - Application enthält keine technischen Implementierungsdetails und **keine JavaFX-Typen** - Externe Zugriffe erfolgen ausschließlich über **Ports** - Konkrete technische Implementierungen sind **Adapter** - Adapter dürfen nicht direkt voneinander abhängen - Die GUI ist ein **Inbound-Adapter** (`pdf-umbenenner-adapter-in-gui`) – sie wird **nicht** in Bootstrap vermischt - Bootstrap bleibt verantwortlich für: Startmoduswahl, Konfigurationsauflösung, Objektgraph, kontrollierten Start des passenden Adapters, Exit-Code-Ableitung bei harten Startfehlern - GUI-Code und JavaFX dürfen im **headless Pfad** nicht unnötig früh initialisiert oder geladen werden - Keine Vermischung von Dateisystem, PDF-Auslese, SQLite, KI-HTTP, Konfiguration, Logging, Benennungslogik und Retry-Entscheidungen - Logging ist technische Infrastruktur, kein fachlicher Port - Port-Verträge enthalten weder `Path`/`File` noch NIO- oder JDBC-Typen - Der `AiNamingPort` bleibt provider-neutral; provider-spezifische Typen, Header, URLs und Antwortstrukturen leben ausschließlich in der jeweiligen Adapter-Out-Implementierung - Es gibt keine gemeinsame „abstrakte KI-Adapter"-Zwischenschicht zwischen Port und konkreten Adaptern - Die Bootstrap-Schicht wählt die **eine** aktive `AiNamingPort`-Implementierung anhand der Konfiguration aus ## GUI-Leitplanken (verbindlich für alle V2.0-Arbeitspakete) ### Threadingmodell - Jede potenziell blockierende Operation (Modellabruf, technische Tests, Pfad-/Dateisystemprüfungen, SQLite-Prüfungen, Lesen/Schreiben der `.properties`) läuft auf einem **Hintergrund-Worker-Thread** - UI-Updates erfolgen ausschließlich über den **JavaFX Application Thread** (`Platform.runLater`) - Die GUI darf während laufender Hintergrund-Operationen **nicht einfrieren** ### GUI-Teststrategie - **View-Modelle und Application-nahe GUI-Logik** werden mit JUnit unit-getestet; Fokus auf Zustandsübergängen, Validierungsregeln und Datenflüssen – nicht auf Rendering - **GUI-Smoke-Tests** laufen unter **headless JavaFX (Monocle)** in der Maven-Test-Phase - Kein TestFX, kein weiteres GUI-Testframework über Monocle hinaus ### GUI-Logging - Der GUI-Adapter nutzt denselben Log4j2-Stack wie der headless Pfad - Logformat und Log-Verzeichnis bleiben gegenüber dem headless Betrieb unverändert - Mindesteinträge für GUI-nahe Ereignisse: Start- und Beendigungsereignisse der GUI, Modellabruf-Versuche (Provider, Erfolg/Misserfolg, **ohne API-Key**), Dateischreibvorgänge inkl. Zielpfad, Ergebnisse der Aktionen `Validieren` und `Technische Tests ausführen`, sowie alle schreibenden Korrekturen ### `--config`-Semantik - Zeigt `--config ` im **GUI-Start** auf eine nicht existente Datei: Fehlermeldung, danach verhält sich die GUI so, als wäre `--config` nicht angegeben worden - Zeigt `--config ` im **headless Start** auf eine nicht existente Datei: **harter Startfehler**, kein stiller Fallback ## JavaDoc-Standard (verbindlich für alle V2.0-Arbeitspakete) Für jede **neu hinzugefügte** oder **substanziell geänderte** öffentliche Klasse, öffentliche Methode und jedes neue Java-Package gilt: - **Klassen-JavaDoc**: Zweck, Verantwortung und Abgrenzung der Klasse - **Methoden-JavaDoc**: Zweck, Parameter, Rückgabewert und dokumentierte Ausnahmen - **`package-info.java`**: pro neuem Package, mit Kurzbeschreibung der Paketverantwortung Ein Arbeitspaket ist erst fertig, wenn die betroffenen öffentlichen Klassen und Methoden dem JavaDoc-Standard entsprechen. ## Globale fachliche Leitplanken - Zielformat: `YYYY-MM-DD - Titel.pdf` - Bei Namenskollisionen: `YYYY-MM-DD - Titel(1).pdf`, `YYYY-MM-DD - Titel(2).pdf`, ... - Die **20 Zeichen** gelten nur für den **Basistitel**; das Dubletten-Suffix zählt nicht mit - Das Dubletten-Suffix wird unmittelbar vor `.pdf` angehängt - Titel sind **deutsch**, verständlich, eindeutig und enthalten keine Sonderzeichen außer Leerzeichen - Eigennamen bleiben unverändert - Datumsermittlung mit Priorität aus den fachlichen Anforderungen; wenn kein belastbares Datum eindeutig ableitbar ist, ist das **aktuelle Datum** als Fallback erlaubt - Mehrdeutige Dokumente liefern **kein** unsicheres Ergebnis, sondern einen Fehler - Erfolgreich verarbeitete Dateien werden nicht erneut verarbeitet - Retryable fehlgeschlagene Dateien dürfen in späteren Läufen erneut verarbeitet werden - Final fehlgeschlagene Dateien werden in späteren Läufen übersprungen - Identifikation erfolgt **nicht** über Dateinamen - Quelldateien werden **nie** überschrieben, verändert, verschoben oder gelöscht ## Aktiver Implementierungsstand V1.1 ist vollständig umgesetzt, dokumentiert, getestet und freigegeben. Der aktive Entwicklungsstand ist **V2.0**. Ziel ist der Ausbau um eine lokale JavaFX-Desktop-GUI als neuen Standardstart, ohne die bestehende Architektur, das Standalone-JAR-Betriebsmodell oder den headless Scheduler-Betrieb aufzugeben. Die fachliche Kernverarbeitung des PDF-Umbenenners bleibt in V2.0 unverändert. ## Statussemantik | Status | Bedeutung | |---|---| | `READY_FOR_AI` | Verarbeitbar, KI-Pfad noch nicht durchlaufen | | `FAILED_RETRYABLE` | Verarbeitbar, transient fehlgeschlagen | | `PROPOSAL_READY` | Eingangszustand für Dateinamensbildung und Zielkopie | | `SUCCESS` | Terminaler Enderfolg – nur nach Zielkopie und konsistenter Persistenz zulässig | | `FAILED_FINAL` | Terminal, wird nicht erneut fachlich verarbeitet | | `SKIPPED_ALREADY_PROCESSED` | Historisierter Skip für SUCCESS-Dokumente | | `SKIPPED_FINAL_FAILURE` | Historisierter Skip für FAILED_FINAL-Dokumente | ### SUCCESS-Bedingung (verbindlich) `SUCCESS` darf erst gesetzt werden, wenn: 1. die Zielkopie erfolgreich geschrieben wurde, 2. der finale Zieldateiname bestimmt ist, 3. die Persistenz konsistent fortgeschrieben wurde. ### Führende Quelle des Benennungsvorschlags (verbindlich) - Die führende Quelle für Datum, Datumsquelle, validierten Titel und Reasoning ist der **neueste Versuchshistorieneintrag mit Status `PROPOSAL_READY`** - Kein Rekonstruieren aus dem Dokument-Stammsatz - Kein neuer KI-Aufruf, wenn bereits ein nutzbarer `PROPOSAL_READY`-Versuch vorliegt - Status `PROPOSAL_READY` ohne lesbaren konsistenten Proposal-Versuch = dokumentbezogener technischer Fehler - Inkonsistente Proposal-Zustände werden **nicht stillschweigend geheilt**, sondern als technische Dokumentfehler behandelt ## Retry-Semantik ### Deterministische Inhaltsfehler - **erster** historisierter deterministischer Inhaltsfehler → `FAILED_RETRYABLE` - **zweiter** historisierter deterministischer Inhaltsfehler → `FAILED_FINAL` ### Transiente technische Fehler - Transiente Fehler laufen über den Transientfehlerzähler im Dokument-Stammsatz - Retryable bis der konfigurierte Grenzwert `max.retries.transient` erreicht ist - Der Fehlversuch, der den Grenzwert **erreicht**, finalisiert den Dokumentstatus zu `FAILED_FINAL` - `max.retries.transient` = **Integer >= 1**; der Wert `0` ist ungültige Startkonfiguration ### Technischer Sofort-Wiederholversuch - **Genau ein** zusätzlicher technischer Schreibversuch innerhalb desselben Dokumentlaufs - **Ausschließlich** für Fehler beim physischen Zielkopierpfad - Kein erneuter KI-Aufruf, keine erneute Fachableitung - Zählt **nicht** zum laufübergreifenden Transientfehlerzähler ## Exit-Codes (verbindlich) - **`0`**: normale erfolgreiche Beendigung eines headless Laufs sowie für das reguläre Beenden der GUI - **`1`**: harte Start-, Bootstrap-, Verdrahtungs-, Konfigurations- oder Initialisierungsfehler, einschließlich ungültiger CLI-Verwendung, nicht existenter `--config`-Datei im headless Start und GUI-Startfehlern vor erfolgreicher Anzeige der Oberfläche - Dokumentbezogene Verarbeitungsfehler im headless Lauf ändern dieses Exit-Code-Modell nicht ## Persistenz Zwei-Ebenen-Modell – keine dritte Wahrheitsquelle. **Dokument-Stammsatz** enthält u.a.: - letzten Zielpfad, letzten Zieldateinamen - Inhaltsfehler- und Transientfehlerzähler - Gesamtstatus **Versuchshistorie** enthält u.a.: - finalen Zieldateinamen - Fehlerklasse, Fehlermeldung, Retryable-Flag - **Provider-Identifikator des aktiven KI-Providers für den Versuch** **Invariante:** Der führende `PROPOSAL_READY`-Versuch wird nicht überschrieben. Jeder Lauf erzeugt einen **zusätzlichen** neuen Versuchseintrag. **Rückwärtsverträglichkeit:** Bestehende Datenbestände bleiben lesbar, fortschreibbar und korrekt interpretierbar. ## Naming-Regel (verbindlich für alle Arbeitspakete) In Implementierungen, Kommentaren und JavaDoc dürfen **keine** Meilenstein- oder Arbeitspaket-Bezeichner erscheinen: - Verboten: `M1`, `M2`, …, `M13` - Verboten: `AP-001`, `AP-002`, … `AP-0xx` - Verboten: Versionsbezeichner wie `V1.0`, `V1.1`, `V2.0` in Code/JavaDoc Stattdessen werden **zeitlose technische Bezeichnungen** verwendet. Bestehende Kommentare mit solchen Bezeichnern, die durch eigene Änderungen berührt werden, sind zu ersetzen. ## Arbeitsweise - Arbeite immer nur im **explizit aktiven Arbeitspaket** - **Kein Vorgriff** auf spätere Arbeitspakete - Änderungen klein, fokussiert und architekturtreu halten - Keine unnötigen Umbenennungen, keine großflächigen Refactorings ohne Not - Vor Änderungen zuerst die betroffenen Dateien und Abhängigkeiten verstehen - **Keine Annahmen über Dateipfade.** Typen und Klassen werden per Suche nach Typname gefunden, nicht über vermutete Pfade. - Keine Vermutungen: Bei echter Unklarheit oder Dokumentkonflikten knapp nachfragen oder den Konflikt benennen - Keine stillen Änderungen am bestehenden headless Batch-Betrieb - GUI-Code darf den headless Pfad nicht unnötig früh initialisieren ## Definition of Done pro Arbeitspaket Ein Arbeitspaket ist erst fertig, wenn: - der Zielumfang des aktuellen Arbeitspakets vollständig umgesetzt ist - der Stand konsistent, fehlerfrei und buildbar ist - Implementierung, Konfiguration, JavaDoc (inkl. `package-info.java` für neue Packages) und Tests ergänzt sind - der JavaDoc-Standard für alle neu hinzugefügten oder substanziell geänderten öffentlichen Klassen und Methoden eingehalten wurde - keine Inhalte späterer Arbeitspakete vorweggenommen wurden - der Zwischenstand in sich geschlossen und übergabefähig ist ## Pflicht-Output-Format nach jedem Arbeitspaket ``` - Scope erfüllt: ja/nein - Geänderte Dateien: - - ... - Build-Kommando: - Build-Status: ERFOLGREICH / FEHLGESCHLAGEN - Offene Punkte: keine / - Risiken: keine / ``` ## Qualitäts- und Prüfreihenfolge - Nur den für das aktuelle Arbeitspaket nötigen Scope ändern - Nach Änderungen den kleinsten sinnvollen Build-/Test-Umfang ausführen - Build-Validierung vom Parent-Root (Beispiel für vollständigen Reactor-Build ab V2.0): `.\mvnw.cmd clean verify -pl pdf-umbenenner-domain,pdf-umbenenner-application,pdf-umbenenner-adapter-out,pdf-umbenenner-adapter-in-cli,pdf-umbenenner-adapter-in-gui,pdf-umbenenner-bootstrap --also-make` - Schlägt der Build fehl: Fehler beheben, erneut bauen, erst dann weiter - Vor Abschluss sicherstellen, dass der relevante Maven-Reactor-Stand fehlerfrei ist - Fehler nicht kaschieren; Ursachen sauber beheben oder offen benennen ## Wichtige Betriebsregeln - Ungültige Startkonfiguration verhindert den Verarbeitungslauf und führt zu Exit-Code `1` - Eine ungültige oder fehlende Provider-Auswahl ist eine ungültige Startkonfiguration - Run-Lock verhindert parallele Instanzen; wenn bereits eine Instanz läuft, beendet sich die neue Instanz sofort - API-Schlüssel: pro Provider eine eigene Umgebungsvariable, Vorrang vor Properties derselben Provider-Familie. Schlüssel verschiedener Provider werden niemals vermischt. - Dokumentbezogene Fehler führen **nicht** zu Exit-Code `1` ## Konfigurationsparameter Verbindlich zweckmäßige Parameter: - `source.folder` – Quellordner - `target.folder` – Zielordner (muss vorhanden oder anlegbar sein, Schreibzugriff erforderlich) - `sqlite.file` – SQLite-Datenbankdatei - `ai.provider.active` – aktiver KI-Provider (Pflicht) - `max.retries.transient` – max. historisierte transiente Fehlversuche pro Fingerprint (**Integer >= 1**, `0` ist ungültig) - `max.pages` – Seitenlimit - `max.text.characters` – maximale Zeichenzahl für KI-Eingabe - `prompt.template.file` – externe Prompt-Datei - `log.ai.sensitive` – sensible KI-Logausgabe freischalten (Boolean, Default: `false`) - `runtime.lock.file` – Lock-Datei (optional) - `log.directory` – Log-Verzeichnis (optional) Pro Provider-Familie existiert ein eigener Parameter-Namensraum: ```properties ai.provider.active=openai-compatible ai.provider.openai-compatible.baseUrl=... ai.provider.openai-compatible.model=... ai.provider.openai-compatible.timeoutSeconds=... ai.provider.openai-compatible.apiKey=... ai.provider.claude.baseUrl=... ai.provider.claude.model=... ai.provider.claude.timeoutSeconds=... ai.provider.claude.apiKey=... ``` ### Migration historischer Konfiguration Bestehende Properties-Dateien des Vorgängerstands (flache Schlüssel wie `api.baseUrl`, `api.model`, `api.timeoutSeconds`, `api.key`) werden beim ersten Start erkannt und kontrolliert in das neue Schema überführt. Verbindlicher Ablauf: 1. Legacy-Form erkennen 2. **`.bak`-Sicherung** der Originaldatei anlegen 3. Inhalt in das neue Schema überführen (Legacy-Werte → Namensraum `openai-compatible`, `ai.provider.active=openai-compatible`) 4. Datei in-place schreiben 5. Datei erneut laden und validieren 6. Erst danach den normalen Lauf fortsetzen ## Nicht-Ziele / Verbote - kein manueller Verarbeitungslauf aus der GUI (erst V2.1+) - kein DB-/Historien-Tab in der GUI (erst V2.x+) - kein Kosten-Tracking (erst V2.x+) - kein echter Mini-KI-Testaufruf mit fachlicher Antwortauswertung - keine EXE, kein Installer - kein Web-UI - keine REST-API zur Bedienung - keine OCR innerhalb der Java-Anwendung - keine DMS-Funktionalität - kein menschlicher Review-Workflow in der Anwendung - keine interne Scheduler-Logik - keine Architekturbrüche - keine neuen Bibliotheken oder Frameworks ohne klare Notwendigkeit und Begründung - **keine** automatische Fallback-Umschaltung zwischen KI-Providern - **keine** parallele Nutzung mehrerer KI-Provider in einem Lauf - **keine** Profilverwaltung mit mehreren Konfigurationen je Provider-Familie - **keine** Provider-Familien jenseits der explizit unterstützten - kein neues Konfigurationsformat - keine Änderung der fachlichen Kernverarbeitung des PDF-Umbenenners - keine Änderung der bestehenden Status-, Retry- oder Persistenz-Wahrheit - keine stillen Änderungen am bestehenden headless Batch-Betrieb - kein Sofort-Wiederholversuch außerhalb des Zielkopierpfads - keine spekulativen Umbauten ohne konkreten Qualitäts- oder Konsistenzbezug - kein großflächiges Refactoring ohne nachweisbaren Defektbezug