Files
pdf-umbenenner/docs/specs/V2_9_-_Spezifikation.md

379 lines
18 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# V2.9 Integrierte PDF-Vorschau und Dateinamen-Bearbeitung
**Status:** Freigegeben
**Erstellt:** 2026-04-24
**Überarbeitet:** 2026-04-24 (nach zwei ChatGPT-Reviews, finale Version)
**Autor:** Marcus (mit Claude als Mentor)
---
## Ziel
V2.9 erweitert den Tab „Verarbeitungslauf" um zwei eng verzahnte Funktionen:
1. **Integrierte PDF-Vorschau** beim Anklicken einer Zeile wird die erste Seite der
Quelldatei direkt im Detailbereich rechts gerendert (kein separates Fenster, kein
zusätzlicher Klick)
2. **Editierbarer Dateiname** der von der KI vorgeschlagene Dateiname kann direkt
in der GUI korrigiert werden, bevor er als endgültig gilt
Beide Funktionen zusammen ermöglichen einen natürlichen Review-Zyklus:
**KI benennt → Benutzer schaut rein → Benutzer korrigiert bei Bedarf → fertig.**
---
## Hintergrund
### Bisheriger Zustand
- Der Detailbereich rechts zeigt nur KI-Begründung als TextArea
- Ob der vorgeschlagene Dateiname sinnvoll ist, kann der Benutzer nur anhand des
KI-Reasonings beurteilen den tatsächlichen Dokumentinhalt sieht er nicht
- Der generierte Dateiname ist nach dem Lauf nicht mehr veränderbar
- Die Spike-Implementierung (PDFViewFX + jai-imageio-jpeg2000 für JBIG2-Unterstützung)
hat die technische Machbarkeit bereits bestätigt; der Spike-Code wird im Rahmen
von V2.9 durch produktionsreifen Code ersetzt
### Motivation
- Benutzer sollen schnell beurteilen können, ob der KI-Dateiname passt,
ohne ein externes Programm öffnen zu müssen
- Korrekturen sollen direkt in der Anwendung möglich sein für nicht-technische
Benutzer (z. B. Familienmitglieder) ist das eine wesentliche UX-Verbesserung
- Die Anwendung wird vom reinen Batch-Prozessor zum assistierten
Dokumenten-Review-Werkzeug weiterentwickelt
---
## Zielbild
Nach Abschluss von V2.9 kann der Benutzer:
1. Eine Zeile in der Ergebnisliste anklicken
2. Sofort die erste Seite der zugehörigen **Quelldatei** als Vorschau sehen
ohne weiteren Klick, direkt im Detailbereich
3. Weitere Seiten bei Bedarf **auf Anfrage** laden (Lazy Rendering)
4. Den vorgeschlagenen Dateinamen **direkt in der GUI bearbeiten** und speichern
5. Den headless-Betrieb unverändert nutzen V2.9 betrifft ausschließlich die GUI
---
## Layout-Änderung im Tab „Verarbeitungslauf"
### Bisheriges Layout
```
[ Fortschrittsbalken ]
[ Ergebnistabelle (~75% Breite) | KI-Begründung (~25%) ]
[ Buttons ]
[ Statuszeile ]
```
### Neues Layout
```
[ Fortschrittsbalken ]
[ Ergebnistabelle (~60% Breite) | Detailbereich (~40% Breite) ]
[ | KI-Begründung ]
[ | Dateiname (editierbar) ]
[ | PDF-Vorschau (Seite X/Y) ]
[ Buttons ]
[ Statuszeile ]
```
- Tabelle und Detailbereich sind durch einen **verschiebbaren Splitter** (SplitPane)
getrennt der Benutzer kann das Verhältnis anpassen
- Standard-Split: 60% Tabelle / 40% Detailbereich
- Der Detailbereich ist vertikal aufgebaut: KI-Begründung oben (kompakt),
darunter Dateiname-Feld, darunter PDF-Vorschau (nimmt verfügbaren Restplatz)
- Die PDF-Vorschau rendert die erste Seite **„fit to width"** Seitenverhältnis wird
beibehalten, die Seite füllt die verfügbare Panelbreite aus
---
## Fachliche Anforderungen
### PDF-Vorschau
#### Grundverhalten
- Beim Anklicken einer Zeile in der Ergebnisliste wird **automatisch** Seite 1 der
zugehörigen **Quelldatei** gerendert und im Vorschaubereich angezeigt
- Das Rendering erfolgt **asynchron im Hintergrund** die GUI bleibt während des
Ladens reaktionsfähig
- Während des Renderings wird ein **Ladeindikator** (z. B. ProgressIndicator) angezeigt
- Die Vorschau zeigt immer die **Quelldatei**, nicht die umbenannte Zieldatei
#### Lazy Rendering und Seitennavigation
- Beim ersten Anklicken einer Zeile wird **ausschließlich Seite 1** gerendert
- Unterhalb der Vorschau wird die aktuelle Seite sowie die Gesamtseitenzahl
angezeigt: „Seite 1 / 12"
- Navigation:
- Button **„Nächste Seite"** lädt und rendert die jeweils nächste Seite on-demand
- Button **„Vorherige Seite"** lädt die vorherige Seite
- Bereits gerenderte Seiten werden **gecacht** ein erneuter Wechsel auf eine
bereits gerenderte Seite erfordert kein erneutes Rendering
- Der Cache wird geleert wenn eine andere Zeile angeklickt wird
- Die Navigations-Buttons sind bei Seite 1 (Zurück) bzw. letzter Seite (Weiter)
deaktiviert
#### Abbruchverhalten bei schnellem Wechsel (Latest Preview Request Wins)
- Es gilt das Prinzip **„latest preview request wins"**: Wenn während eines laufenden
Renderings eine neue Vorschau-Anforderung eingeht sei es durch Selektionswechsel
oder durch Seitennavigation innerhalb derselben PDF wird das laufende Rendering
abgebrochen bzw. sein Ergebnis verworfen
- Nur das Ergebnis der zuletzt angeforderten Vorschau darf im Vorschaubereich landen
- Veraltete Render-Ergebnisse werden niemals angezeigt
#### Fehlerfälle PDF-Vorschau
| Situation | Verhalten |
|---|---|
| Quelldatei nicht mehr vorhanden | Meldung im Vorschaubereich: „Quelldatei nicht gefunden" |
| PDF nicht lesbar / korrupt | Meldung im Vorschaubereich: „PDF konnte nicht geöffnet werden" |
| PDF passwortgeschützt / verschlüsselt | Meldung im Vorschaubereich: „PDF ist passwortgeschützt und kann nicht angezeigt werden" |
| JBIG2-Bilder nicht vollständig dekodierbar | Seite wird teilweise gerendert; kein Fehler-Abbruch; kein Hinweis nötig |
| Kein Eintrag selektiert | Vorschaubereich zeigt neutralen Platzhaltertext |
#### Technische Grundlage
- Bibliothek: `com.dlsc.pdfviewfx:pdfviewfx` (bereits im Spike erfolgreich getestet)
- Zusatzabhängigkeit für JBIG2 und erweiterte Bildformate:
`com.github.jai-imageio:jai-imageio-jpeg2000` (bereits im Spike ergänzt)
- Der Spike-Code (`PdfViewerSpike.java`, Spike-Button in `GuiBatchRunTab`) wird
vollständig entfernt und durch die produktive Implementierung ersetzt
- Rendering läuft in einem dedizierten Background-Thread (nicht im JavaFX
Application Thread)
---
### Editierbarer Dateiname
#### Zustandsmodell
Der Dateiname-Bereich kennt drei klar getrennte Zustände:
| Zustand | Beschreibung |
|---|---|
| **KI-Vorschlag** | Der von der KI ursprünglich generierte Name unveränderlich in der DB gespeichert; dient als Referenz für „Zurücksetzen auf KI-Vorschlag" |
| **Letzter gespeicherter Name** | Der zuletzt per „Dateiname übernehmen" bestätigte Name (= aktueller FS- und DB-Stand); ist nach dem Batch-Lauf zunächst identisch mit dem KI-Vorschlag |
| **Aktuelle Eingabe** | Der aktuell im Textfeld eingetippte, noch nicht gespeicherte Wert |
**Anzeige-Regel:** Im Textfeld wird beim Selektieren einer Zeile immer der
**letzte gespeicherte Name** angezeigt nicht der KI-Vorschlag.
Wurde noch nie manuell gespeichert, sind beide identisch.
**Dirty-State-Regel:** Dirty-State besteht wenn die **aktuelle Eingabe** vom
**letzten gespeicherten Namen** abweicht. Der KI-Vorschlag ist keine Dirty-Basis.
#### Anzeige
- Unterhalb der KI-Begründung und oberhalb der PDF-Vorschau befindet sich ein
Bereich „Dateiname"
- Der Dateiname wird in einem **editierbaren Textfeld** (TextField) angezeigt
- Das Textfeld zeigt den **letzten gespeicherten Namen** ohne Dateierweiterung
(`.pdf` wird separat als nicht editierbares Label daneben angezeigt)
- Solange kein Eintrag selektiert ist, ist das Textfeld leer und deaktiviert
- Wenn das Textfeld vom letzten gespeicherten Namen abweicht (**Dirty State**),
wird dies durch eine visuelle Markierung am Textfeld angezeigt (z. B. farbiger Rand)
#### Tastatur- und Schaltflächen-Verhalten
| Aktion | Verhalten |
|---|---|
| **Enter** im Textfeld | Löst „Dateiname übernehmen" aus (sofern Validierung grün) |
| **Escape** im Textfeld | Verwirft aktuelle Eingabe; stellt **letzten gespeicherten Namen** wieder her |
| **„Dateiname übernehmen"** | Startet die atomare Speicher-Transaktion |
| **„Zurücksetzen auf KI-Vorschlag"** | Setzt das Textfeld auf den ursprünglichen KI-Vorschlag zurück (kein Speichern nur Textfeld-Inhalt) |
Hinweis: „Zurücksetzen auf KI-Vorschlag" und Escape haben **unterschiedliche Semantik**:
Escape = zurück zum letzten gespeicherten Stand; „Zurücksetzen" = zurück zum KI-Ursprung.
#### Speichern-Transaktion (Alles oder Nichts)
Das Speichern eines geänderten Dateinamens ist eine **atomare Operation** bestehend
aus zwei Persistenzschritten:
1. Zieldatei im Dateisystem umbenennen
2. Eintrag in der SQLite-DB aktualisieren
**Schlägt Schritt 1 oder 2 fehl, wird die gesamte Aktion abgebrochen:**
- Bereits durchgeführte Teilschritte werden zurückgerollt
- Dateisystem und DB bleiben im vorherigen Zustand
- Eine Fehlermeldung im Statusbereich informiert den Benutzer
- Das Textfeld behält den eingegebenen Wert der Benutzer kann es erneut versuchen
Nach erfolgreicher Transaktion (Projektionsschritt, nicht Teil der Transaktion):
- Tabellenspalte „Neuer Dateiname" wird aktualisiert
- Erfolgsmeldung im Statusbereich
Mögliche Fehlerursachen für Schritt 1: Datei-Lock durch andere Prozesse (Scanner, AV),
fehlende Schreibrechte, Read-only-Dateisystem, Netzlaufwerk nicht erreichbar.
#### Konfliktsemantik bei vorhandenem Zieldateinamen
Existiert im Zielordner bereits eine Datei mit dem neu eingegebenen Namen,
wird anhand des **Fingerprints** (SHA-256 des Dateiinhalts) entschieden:
| Situation | Verhalten |
|---|---|
| **Gleicher Fingerprint** | Dateien sind inhaltlich identisch → keine Aktion; Meldung im Statusbereich: „Identische Datei bereits vorhanden keine Umbenennung nötig"; weder FS noch DB werden geändert |
| **Unterschiedlicher Fingerprint** | Warnung im Statusbereich; Dateiname im FS erhält automatisch ein Suffix `(1)`, `(2)` usw.; DB wird mit dem tatsächlichen neuen Namen inkl. Suffix aktualisiert |
#### Validierung des Dateinamens
Folgende Prüfungen erfolgen **live während der Eingabe**:
| Prüfung | Verhalten bei Verletzung |
|---|---|
| Dateiname ist leer oder nur Leerzeichen | Speichern-Button deaktiviert, Hinweistext unterhalb des Feldes |
| Führende oder abschließende Leerzeichen | Speichern-Button deaktiviert, Hinweistext |
| Unerlaubte Zeichen (`\ / : * ? " < > \|`) | Speichern-Button deaktiviert, Hinweistext |
| Reservierte Windows-Namen (`CON`, `PRN`, `AUX`, `NUL`, `COM1``COM9`, `LPT1``LPT9`) | Speichern-Button deaktiviert, Hinweistext |
| Dateiname endet auf Punkt | Speichern-Button deaktiviert, Hinweistext |
| Dateiname + Zielpfad + `.pdf` überschreitet 259 Zeichen | Speichern-Button deaktiviert, Hinweistext |
Die 259-Zeichen-Grenze ist eine **bewusste Produktregel** für maximale
Windows-Kompatibilität (Windows MAX_PATH = 260 Zeichen inkl. Null-Terminator).
#### Zustände des Dateiname-Bereichs
| Zeilenstatus | Verhalten |
|---|---|
| Kein Eintrag selektiert | Textfeld leer, deaktiviert |
| Eintrag mit Status `DONE` (erfolgreich) | Textfeld editierbar, letzter gespeicherter Name vorausgefüllt |
| Eintrag mit Status `FAILED_*` | Textfeld leer, deaktiviert (kein Dateiname vorhanden) |
| Eintrag mit Status `SKIPPED` | Textfeld deaktiviert |
| Lauf aktiv | Textfeld deaktiviert, alle Buttons deaktiviert |
#### Verhalten bei fehlender Zieldatei
Ist die Zieldatei zum Zeitpunkt des Speicherns nicht mehr im Zielordner vorhanden:
- Schritt 1 der Transaktion schlägt fehl
- Gemäß Alles-oder-Nichts-Prinzip: DB wird **nicht** aktualisiert
- Fehlermeldung im Statusbereich: „Zieldatei nicht gefunden Umbenennung nicht möglich"
- Das Textfeld behält den eingegebenen Wert
#### Verhalten bei ungespeicherten Änderungen (Dirty State)
Ein Hinweisdialog erscheint, wenn der Benutzer mit aktivem Dirty-State eine der
folgenden Aktionen ausführt:
- Eine andere Zeile in der Ergebnistabelle anklicken
- Den Tab wechseln (Konfiguration ↔ Verarbeitungslauf)
- Die Anwendung schließen
- Einen neuen Lauf starten
Dialog-Text: „Der Dateiname wurde geändert aber nicht gespeichert. Änderungen verwerfen?"
Optionen: **„Verwerfen"** (Dirty State wird geleert, Aktion wird fortgesetzt) /
**„Zurück"** (Dialog schließt, Benutzer bleibt im Textfeld)
---
## Architektur
### Manuelle Namenskorrektur als Application-Use-Case
Die manuelle Dateinamen-Korrektur wird als **eigenständiger Application-Use-Case**
modelliert, nicht im GUI-Adapter implementiert:
- Ein neuer Use-Case `ManualFileRenameUseCase` (o. ä.) kapselt die atomare Transaktion
aus FS-Rename + DB-Update
- Der `GuiBatchRunCoordinator` (GUI-Adapter) delegiert ausschließlich an diesen Use-Case
- Dateisystem- und DB-Zugriffe laufen ausschließlich über bestehende oder neue
Ports/Adapter kein Direktzugriff aus dem GUI-Adapter
- Damit bleibt die hexagonale Architektur gewahrt und der Use-Case ist unabhängig
von der GUI testbar
### Komponenten-Übersicht
| Komponente | Änderung |
|---|---|
| `GuiBatchRunTab` | Hauptumbau: SplitPane, Detailbereich-Redesign, Spike-Code entfernen |
| `GuiBatchRunResultRow` | Neues Feld: `correctedFileName` als `Optional<String>` |
| `GuiBatchRunCoordinator` | Delegiert Dateinamen-Korrektur an neuen Use-Case |
| `ManualFileRenameUseCase` | Neuer Application-Use-Case: atomares FS-Rename + DB-Update |
| `pom.xml` (GUI-Modul) | PDFViewFX + jai-imageio-jpeg2000 bleiben; Spike-Klasse entfernen |
| Domain / Ports | Ggf. neuer Port für Datei-Rename-Operation erforderlich |
| Headless-Betrieb | Unberührt |
---
## Abhängigkeiten zwischen den Funktionen
- PDF-Vorschau und editierbarer Dateiname sind **unabhängig voneinander nutzbar**
- Beide beziehen sich auf den in der Ergebnistabelle selektierten Eintrag
- Beim Selektionswechsel mit Dirty-State: Hinweisdialog erscheint (siehe oben)
- PDF-Vorschau-Cache wird beim Selektionswechsel geleert
---
## Verhalten während eines laufenden Batch-Laufs
- Der Detailbereich (PDF-Vorschau + Dateinamen-Editor) ist **vollständig deaktiviert**
während ein regulärer Lauf oder Mini-Lauf aktiv ist
- Bereits angezeigte Vorschau bleibt sichtbar, aber Navigation und Bearbeitung
sind gesperrt
---
## Nicht in V2.9 enthalten
- Löschen der Quelldatei nach Bestätigung (spätere Version)
- Vollständiger PDF-Viewer mit freiem Scrollen und Zoom (Issue #23: DPI-Optimierung)
- Historien-Tab / SQLite-Ansicht (Issue #7, V3.0)
- Automatischer Scheduler / System-Tray (Issues #20, #22)
- Kompakteres Layout der Konfigurationsseite (Issue #24)
- Anwendungs-Icon (Issue #21)
---
## Abnahmekriterien
### Fachliche Akzeptanz
#### PDF-Vorschau
- [ ] Beim Anklicken einer Zeile wird Seite 1 der Quelldatei automatisch gerendert ohne extra Klick
- [ ] Während des Renderings ist ein Ladeindikator sichtbar; die GUI bleibt reaktionsfähig
- [ ] Die Vorschau rendert „fit to width" mit beibehaltenem Seitenverhältnis
- [ ] Seitenanzahl wird angezeigt: „Seite 1 / X"
- [ ] „Nächste Seite" / „Vorherige Seite" laden Seiten on-demand
- [ ] Bereits gerenderte Seiten werden gecacht; Selektionswechsel leert den Cache
- [ ] Navigations-Buttons sind korrekt deaktiviert (erste / letzte Seite)
- [ ] Schneller Selektionswechsel oder Seitenwechsel während Rendering: nur das zuletzt angeforderte Ergebnis wird angezeigt (latest preview request wins)
- [ ] Quelldatei nicht vorhanden → verständliche Fehlermeldung im Vorschaubereich
- [ ] PDF nicht lesbar / korrupt → verständliche Fehlermeldung im Vorschaubereich
- [ ] PDF passwortgeschützt → verständliche Fehlermeldung im Vorschaubereich
#### Dateiname-Editor
- [ ] Textfeld zeigt beim Selektieren den **letzten gespeicherten Namen** (nicht KI-Vorschlag) ohne `.pdf`-Erweiterung; `.pdf` als nicht editierbares Label daneben sichtbar
- [ ] Dateiname ist direkt im Textfeld editierbar
- [ ] Dirty-State (Abweichung von letztem gespeichertem Namen) wird visuell am Textfeld angezeigt
- [ ] Enter im Textfeld löst „Dateiname übernehmen" aus (wenn Validierung grün)
- [ ] Escape im Textfeld stellt den **letzten gespeicherten Namen** wieder her
- [ ] „Zurücksetzen auf KI-Vorschlag" setzt das Textfeld auf den KI-Ursprung zurück (ohne Speichern)
- [ ] Validierung prüft live: leer/nur Leerzeichen, führende/abschließende Leerzeichen, unerlaubte Zeichen, reservierte Windows-Namen, endet auf Punkt, Pfadlänge > 259
- [ ] Bei Validierungsfehler: Speichern-Button deaktiviert, Hinweistext sichtbar
- [ ] „Dateiname übernehmen" ist atomar: FS und DB werden beide aktualisiert oder nichts davon
- [ ] Bei Fehler in FS oder DB: kein Teilupdate, Rollback, Fehlermeldung im Statusbereich, Textfeld behält Eingabe
- [ ] Nach Erfolg: Tabellenspalte und Statusbereich aktualisiert (Projektionsschritt)
- [ ] Dateikonflikt mit gleichem Fingerprint → keine Aktion, Meldung „Identische Datei bereits vorhanden"
- [ ] Dateikonflikt mit unterschiedlichem Fingerprint → Warnung, Suffix `(1)` usw., DB mit tatsächlichem Namen
- [ ] Zieldatei fehlt → Fehlermeldung, weder FS noch DB werden geändert
- [ ] Ungespeicherte Änderungen bei Selektionswechsel → Hinweisdialog erscheint
- [ ] Ungespeicherte Änderungen bei Tabwechsel → Hinweisdialog erscheint
- [ ] Ungespeicherte Änderungen beim App-Schließen → Hinweisdialog erscheint
- [ ] Ungespeicherte Änderungen bei Laufstart → Hinweisdialog erscheint
- [ ] Status `FAILED_*` und `SKIPPED` → Dateiname-Textfeld deaktiviert
- [ ] Während eines aktiven Laufs: Detailbereich vollständig deaktiviert
### Technische DoD
- [ ] Spike-Button und `PdfViewerSpike.java` sind vollständig entfernt
- [ ] Tab „Verarbeitungslauf" zeigt Tabelle und Detailbereich nebeneinander (SplitPane, 60/40, verschiebbar)
- [ ] `ManualFileRenameUseCase` ist im Application-Modul implementiert und unabhängig von der GUI testbar
- [ ] headless-Betrieb ist unverändert funktionsfähig
- [ ] `mvn clean verify` ist grün