Spezifikation für V2.9 (PDF Ansicht + manuelles Umbenennen hinzugefügt

This commit is contained in:
2026-04-24 11:47:02 +02:00
parent 3a98304a5c
commit f6b265b370
+378
View File
@@ -0,0 +1,378 @@
# 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