321 lines
16 KiB
Markdown
321 lines
16 KiB
Markdown
# 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
|
||
@docs/specs/meilensteine.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 Zielarchitektur
|
||
- `docs/specs/fachliche-anforderungen.md` = verbindliche fachliche Regeln
|
||
- `docs/specs/meilensteine.md` = zulässiger Funktionsumfang pro Meilenstein
|
||
- `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**
|
||
Begrenzen den zulässigen Funktionsumfang auf den aktuellen Entwicklungsstand.
|
||
|
||
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
|
||
- Start über Windows Task Scheduler
|
||
- kein Webserver
|
||
- kein Applikationsserver
|
||
- keine Dauerlauf-Anwendung
|
||
- kein interner Scheduler
|
||
- Log4j2 für Logging
|
||
- SQLite als lokaler Persistenzspeicher
|
||
- OpenAI-kompatible HTTP-Schnittstelle für KI-Zugriff
|
||
- API-Provider, Base-URL und Modellname sind **Konfiguration**, keine Architekturentscheidung
|
||
|
||
## Verbindliche Modulstruktur
|
||
- `pdf-umbenenner-domain`
|
||
- `pdf-umbenenner-application`
|
||
- `pdf-umbenenner-adapter-in-cli`
|
||
- `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 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`/`File` noch NIO- oder JDBC-Typen
|
||
|
||
## 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
|
||
|
||
M1 bis M6 sind vollständig abgeschlossen. Der aktive Stand schließt die betriebliche
|
||
Lücke zwischen dem M6-Erfolgspfad und dem final robusten Endstand.
|
||
|
||
### Baseline aus M6
|
||
- Technische Dateinamensbildung im Format `YYYY-MM-DD - Titel.pdf`
|
||
- Dublettenbehandlung im Zielordner: `(1)`, `(2)`, …
|
||
- Physische Zielkopie via temporäre Datei und finalem Move/Rename
|
||
- Schemaevolution M5 → M6 (Zielpfad, Zieldateiname in Stammsatz und Versuchshistorie)
|
||
- Statustransition `PROPOSAL_READY` → `SUCCESS`
|
||
- Zusätzliche Historisierung für Enderfolg und technische Fehler
|
||
- Startvalidierung für Zielordner-Konfiguration (`target.folder`)
|
||
|
||
### Ziel des aktiven Stands
|
||
- Vollständige laufübergreifende Retry-Logik für deterministische Inhaltsfehler und transiente technische Fehler
|
||
- Technischer Sofort-Wiederholversuch ausschließlich für Zielkopierfehler (genau ein zusätzlicher Versuch im selben Lauf)
|
||
- Finalisierung ausgeschöpfter Retry-Rahmen zu `FAILED_FINAL`
|
||
- Vollständige Skip-Semantik: `SUCCESS` und `FAILED_FINAL` werden historisiert übersprungen
|
||
- Logging-Mindestumfang des Endstands vollständig angebunden
|
||
- Sensibilitätsregel für KI-Inhalte im Logging
|
||
- Vervollständigte Startvalidierung und finale Exit-Code-Semantik
|
||
|
||
## 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.
|
||
- 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 (aktiver Stand)
|
||
|
||
### 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.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.
|
||
- Beispiel: `max.retries.transient = 1` → erster transiente Fehlversuch finalisiert sofort.
|
||
|
||
### 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äufen `SKIPPED_ALREADY_PROCESSED` historisieren, keine Zähleränderung.
|
||
- `FAILED_FINAL` → in späteren Läufen `SKIPPED_FINAL_FAILURE` historisieren, keine Zähleränderung.
|
||
- `FAILED_RETRYABLE`, `READY_FOR_AI`, `PROPOSAL_READY` → verarbeitbar.
|
||
|
||
## Logging-Mindestumfang (aktiver Stand)
|
||
|
||
Folgende Informationen müssen nachvollziehbar geloggt werden:
|
||
- Laufstart mit Lauf-ID
|
||
- 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.
|
||
|
||
## Verarbeitungsreihenfolge pro Dokument (aktiver Stand)
|
||
|
||
1. Fingerprint berechnen
|
||
2. Dokument-Stammsatz laden
|
||
3. Terminale Skip-Fälle entscheiden (`SUCCESS` → `SKIPPED_ALREADY_PROCESSED`, `FAILED_FINAL` → `SKIPPED_FINAL_FAILURE`)
|
||
4. Falls nötig: Pfad bis `PROPOSAL_READY` durchlaufen (inkl. KI-Aufruf)
|
||
5. Führenden `PROPOSAL_READY`-Versuch laden
|
||
6. Finalen Basis-Dateinamen bilden
|
||
7. Dubletten-Suffix im Zielordner bestimmen
|
||
8. Zielkopie schreiben (temporäre Datei + finaler Move/Rename; bei Fehler: genau ein Sofort-Wiederholversuch)
|
||
9. Retry-Entscheidung ableiten
|
||
10. 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 `SUCCESS` setzen, best-effort Rückbau der Zielkopie, Ergebnis bleibt dokumentbezogener technischer Fehler
|
||
|
||
## Fehlersemantik (aktiver Stand)
|
||
- 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
|
||
|
||
## Persistenz (aktiver Stand)
|
||
|
||
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
|
||
|
||
**Invariante:** Der führende `PROPOSAL_READY`-Versuch wird nicht überschrieben.
|
||
Jeder Lauf erzeugt einen **zusätzlichen** neuen Versuchseintrag.
|
||
|
||
## Naming-Regel (verbindlich für alle Arbeitspakete)
|
||
In Implementierungen, Kommentaren und JavaDoc dürfen **keine** Meilenstein- oder
|
||
Arbeitspaket-Bezeichner erscheinen:
|
||
|
||
- Verboten: `M1`, `M2`, `M3`, `M4`, `M5`, `M6`, `M7`, `M8`
|
||
- Verboten: `AP-001`, `AP-002`, … `AP-00x`
|
||
|
||
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 Meilenstein** und im **explizit aktiven Arbeitspaket**
|
||
- **Kein Vorgriff** auf spätere Meilensteine oder 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
|
||
|
||
## 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 Meilensteine 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`
|
||
- 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
|
||
- Umgebungsvariable hat Vorrang vor Properties beim API-Key
|
||
- 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
|
||
- `api.baseUrl` – KI-Basis-URL
|
||
- `api.model` – Modellname
|
||
- `api.timeoutSeconds` – Timeout
|
||
- `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)
|
||
- `api.key` – API-Key (Umgebungsvariable hat Vorrang)
|
||
|
||
## 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 stillen Änderungen an Provider-Bindung oder Architekturprinzipien
|
||
- kein Sofort-Wiederholversuch außerhalb des Zielkopierpfads
|
||
- keine Reporting- oder Statistikfunktionen
|
||
- keine neue dritte Persistenz-Wahrheitsquelle für Retry-Entscheidungen
|
||
- kein M8-Gesamtfeinschliff oder großflächiges Refactoring
|