19 KiB
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.
Autoritative Dokumente
@docs/specs/technik-und-architektur.md @docs/specs/fachliche-anforderungen.md
Für die Umsetzung ist zusätzlich immer das aktuell aktive Arbeitspaket unter docs/workpackages/ maßgeblich.
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 Zielarchitekturdocs/specs/fachliche-anforderungen.md= verbindliche fachliche Regelndocs/workpackages/...= verbindlicher Scope, Reihenfolge und Inhalt des aktuell bearbeiteten Arbeitspakets
Bei Konflikten gilt folgende Priorität:
-
Technik- und Architektur-Dokument Verbindliche technische Zielarchitektur. Architekturbrüche sind unzulässig.
-
Fachliche Anforderungen Verbindliche fachliche Regeln und fachliches Zielverhalten.
-
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
- Start über Windows Task Scheduler
- kein Webserver
- kein Applikationsserver
- keine Dauerlauf-Anwendung
- kein interner Scheduler
- Log4j2 für Logging
- SQLite als lokaler Persistenzspeicher
- 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.
- Konkrete Provider-Familie, Base-URL und Modellname sind Konfiguration, keine Architekturentscheidung.
Verbindliche Modulstruktur
pdf-umbenenner-domainpdf-umbenenner-applicationpdf-umbenenner-adapter-in-clipdf-umbenenner-adapter-outpdf-umbenenner-bootstrap
Architekturregeln
- Strikte hexagonale Architektur / Ports and Adapters
- Abhängigkeiten zeigen immer nach innen
- Domain kennt keine Infrastruktur, keine Datenbank, kein Dateisystem und keine HTTP-Kommunikation
- Application orchestriert Use Cases und enthält keine technischen Implementierungsdetails
- Externe Zugriffe erfolgen ausschließlich über Ports
- Konkrete technische Implementierungen sind Adapter
- Adapter dürfen nicht direkt voneinander abhängen
- 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/Filenoch NIO- oder JDBC-Typen - Der
AiNamingPortbleibt 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
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
.pdfangehä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
Die fachliche und technische Basis ist vollständig umgesetzt, dokumentiert, getestet (inkl. PIT-Mutationstests, Smoke-Tests, End-to-End-Tests) und freigegeben.
Der aktive Stand ist die Erweiterung „Zusätzlicher KI-Provider Anthropic Claude über die native Messages API". Sie ist eine bewusst minimale Erweiterung des freigegebenen Basisstands.
Ziel der aktiven Erweiterung
- Der bestehende OpenAI-kompatible KI-Weg bleibt unverändert nutzbar.
- Zusätzlich wird die native Anthropic Messages API als zweite, gleichwertig unterstützte Provider-Familie integriert.
- Genau ein Provider ist pro Lauf aktiv – ausschließlich über Konfiguration ausgewählt.
- Kein automatischer Fallback, keine Parallelnutzung, keine Profilverwaltung.
- Der fachliche KI-Vertrag (
NamingProposalaus Application-/Domain-Sicht) bleibt unverändert. - Bestehende Properties-Dateien aus dem Vorgängerstand werden beim ersten Start kontrolliert in das neue Schema migriert; vorher wird automatisch eine
.bak-Sicherung angelegt. - Architekturgrenzen, Persistenzmodell, Statussemantik, Retry-Semantik, Exit-Code-Verhalten und Logging-Mindestumfang bleiben unverändert; sie werden ausschließlich um den Provider-Identifikator und die Provider-Auswahl ergänzt.
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:
- die Zielkopie erfolgreich geschrieben wurde,
- der finale Zieldateiname bestimmt ist,
- 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_READYohne lesbaren konsistenten Proposal-Versuch = dokumentbezogener technischer Fehler. - Proposal-Versuch mit fachlich unbrauchbarem Titel oder Datum = inkonsistenter Persistenzzustand = dokumentbezogener technischer Fehler.
- Inkonsistente Proposal-Zustände werden nicht stillschweigend geheilt, sondern als technische Dokumentfehler behandelt.
Retry-Semantik
Deterministische Inhaltsfehler
Deterministische Inhaltsfehler sind insbesondere:
- kein brauchbarer Text
- Seitenlimit überschritten
- fachlich unbrauchbarer oder generischer Titel
- vorhandenes, aber unbrauchbares KI-Datum
Regel:
- 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.
- Sie bleiben retryable bis der konfigurierte Grenzwert
max.retries.transienterreicht ist. - Der Fehlversuch, der den Grenzwert erreicht, finalisiert den Dokumentstatus zu
FAILED_FINAL. max.retries.transient= Integer >= 1; der Wert0ist ungültige Startkonfiguration.- Die Klassifikation gilt provider-unabhängig: Technische Fehler aus dem aktiven KI-Provider werden in dieselbe transiente Kategorie eingeordnet wie bisher. Der inaktive Provider wird in keiner Fehlersituation als Backup verwendet.
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.
- Liefert genau ein dokumentbezogenes Ergebnis für Persistenz und Statusfortschreibung.
Skip-Semantik
SUCCESS→ in späteren LäufenSKIPPED_ALREADY_PROCESSEDhistorisieren, keine Zähleränderung.FAILED_FINAL→ in späteren LäufenSKIPPED_FINAL_FAILUREhistorisieren, keine Zähleränderung.FAILED_RETRYABLE,READY_FOR_AI,PROPOSAL_READY→ verarbeitbar.
Logging-Mindestumfang
Folgende Informationen müssen nachvollziehbar geloggt werden:
- Laufstart mit Lauf-ID
- aktiver KI-Provider für den Lauf
- Laufende
- erkannte Quelldatei
- Überspringen bereits erfolgreicher Dateien
- Überspringen final fehlgeschlagener Dateien
- erzeugter Zielname
- Retry-Entscheidung
- Fehler mit Klassifikation
Korrelationsregel
- Vor erfolgreicher Fingerprint-Ermittlung: Korrelation über Lauf-ID und Kandidatenbezug.
- Nach erfolgreicher Fingerprint-Ermittlung: dokumentbezogene Logs enthalten den Fingerprint oder eine eindeutig ableitbare Referenz.
- Keine neue Persistenz-Wahrheit oder zusätzliche Tracking-Ebene.
Sensibilitätsregel für KI-Inhalte
- Vollständige KI-Rohantwort: standardmäßig nicht ins Log, bleibt in SQLite.
- Vollständiges KI-
reasoning: standardmäßig nicht ins Log, bleibt in SQLite. - Freischaltung nur über expliziten booleschen Konfigurationswert.
- Default: sicher / nicht loggen.
- Die Sensibilitätsregel gilt provider-unabhängig.
Verarbeitungsreihenfolge pro Dokument
- Fingerprint berechnen
- Dokument-Stammsatz laden
- Terminale Skip-Fälle entscheiden (
SUCCESS→SKIPPED_ALREADY_PROCESSED,FAILED_FINAL→SKIPPED_FINAL_FAILURE) - Falls nötig: Pfad bis
PROPOSAL_READYdurchlaufen (inkl. KI-Aufruf über den aktiven Provider) - Führenden
PROPOSAL_READY-Versuch laden - Finalen Basis-Dateinamen bilden
- Dubletten-Suffix im Zielordner bestimmen
- Zielkopie schreiben (temporäre Datei + finaler Move/Rename; bei Fehler: genau ein Sofort-Wiederholversuch)
- Retry-Entscheidung ableiten
- Neuen Versuch historisieren, Stammsatz konsistent fortschreiben
Zielkopie-Semantik
- Kopie zunächst in temporäre Zieldatei im Zielkontext
- Finaler Move/Rename auf den geplanten Zieldateinamen
- Quelldatei bleibt immer unverändert
- Bei technischem Schreibfehler: genau ein Sofort-Wiederholversuch (nur Zielkopierpfad)
- Bei Persistenzfehler nach erfolgreicher Zielkopie: kein
SUCCESSsetzen, best-effort Rückbau der Zielkopie, Ergebnis bleibt dokumentbezogener technischer Fehler
Fehlersemantik
- Technische Fehler →
FAILED_RETRYABLE, Transientfehlerzähler +1 - Bei Erreichen von
max.retries.transient→FAILED_FINAL - Kein Abbruch des Batch-Laufs für andere Dokumente
- Keine neue finale Fehlerkategorie
- Vor-Fingerprint-Fehler werden nicht als SQLite-Versuch historisiert
- Provider-spezifische Fehlerausprägungen (HTTP-Fehler, Auth-Fehler, Antwort-Schema-Fehler) werden im jeweiligen Adapter klassifiziert und auf die bestehenden Fehlerkategorien abgebildet. Es entstehen keine neuen Fehlerklassen.
Persistenz
Zwei-Ebenen-Modell bleibt unverändert – 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. Schema-Erweiterungen sind additiv mit definierten Defaultwerten für historische Versuche ohne Provider-Identifikator.
Naming-Regel (verbindlich für alle Arbeitspakete)
In Implementierungen, Kommentaren und JavaDoc dürfen keine Meilenstein- oder Arbeitspaket-Bezeichner erscheinen:
- Verboten:
M1,M2, …,M8 - Verboten:
AP-001,AP-002, …AP-00x - Verboten: Versionsbezeichner wie
V1.0,V1.1in 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 OpenAI-kompatiblen KI-Weg
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 und Tests ergänzt sind, soweit für den Stand sinnvoll
- 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:
- <Dateipfad>
- ...
- Build-Kommando: <verwendetes Kommando>
- Build-Status: ERFOLGREICH / FEHLGESCHLAGEN
- Offene Punkte: keine / <Beschreibung>
- Risiken: keine / <Beschreibung>
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:
.\mvnw.cmd clean verify -pl pdf-umbenenner-domain,pdf-umbenenner-application,pdf-umbenenner-adapter-out,pdf-umbenenner-adapter-in-cli,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
- Exit-Code
0: Lauf technisch ordnungsgemäß ausgeführt, auch wenn einzelne Dateien fachlich oder transient fehlgeschlagen sind - Exit-Code
1: harter Start-/Bootstrap-Fehler - 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– Quellordnertarget.folder– Zielordner (muss vorhanden oder anlegbar sein, Schreibzugriff erforderlich)sqlite.file– SQLite-Datenbankdateiai.provider.active– aktiver KI-Provider (Pflicht; zulässige Werte sind die Bezeichner der unterstützten Provider-Familien)max.retries.transient– max. historisierte transiente Fehlversuche pro Fingerprint (Integer >= 1,0ist ungültig)max.pages– Seitenlimitmax.text.characters– maximale Zeichenzahl für KI-Eingabeprompt.template.file– externe Prompt-Dateilog.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 mit zweckmäßig:
- Modellname
- API-Schlüssel (Umgebungsvariable hat Vorrang)
- Timeout
- Basis-URL (optional, wo betrieblich sinnvoll)
Konkretes Schema (zweckmäßig):
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 (mit flachen Schlüsseln wie api.baseUrl, api.model, api.timeoutSeconds, api.key) werden beim ersten Start erkannt und kontrolliert in das neue Schema überführt.
Verbindlicher Ablauf:
- Legacy-Form erkennen
.bak-Sicherung der Originaldatei anlegen- Inhalt in das neue Schema überführen
- Legacy-Werte landen im Namensraum
openai-compatible ai.provider.activewird aufopenai-compatiblegesetzt
- Legacy-Werte landen im Namensraum
- Datei in-place schreiben
- Datei erneut laden und validieren
- Erst danach den normalen Lauf fortsetzen
Alte und neue Struktur sind kein dauerhaft gleichrangiges Endformat.
Nicht-Ziele / Verbote
- 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 (OpenAI-kompatibel, Anthropic Messages API)
- keine stillen Änderungen am bestehenden OpenAI-kompatiblen KI-Weg
- kein Sofort-Wiederholversuch außerhalb des Zielkopierpfads
- keine Reporting- oder Statistikfunktionen
- keine neue dritte Persistenz-Wahrheitsquelle für Retry-Entscheidungen
- keine neue Fachfunktionalität jenseits des definierten Zielbilds
- kein großflächiges Refactoring ohne nachweisbaren Defektbezug
- keine spekulativen Umbauten ohne konkreten Qualitäts- oder Konsistenzbezug
- keine Vermischung von API-Schlüsseln verschiedener Provider-Familien