diff --git a/docs/architecture/adapter-overview.md b/docs/architecture/adapter-overview.md index 72977dd..81cad54 100644 --- a/docs/architecture/adapter-overview.md +++ b/docs/architecture/adapter-overview.md @@ -120,12 +120,19 @@ ausschließlich der Bootstrap (→ `AiProviderSelector`). #### SQLite -- **`...sqlite.SqliteSchemaInitializationAdapter`** – legt Tabellen `document_record` und - `processing_attempt` an. Schema-Evolution erfolgt per `ALTER TABLE ADD COLUMN`; bestehende - Datenbestände bleiben rückwärtskompatibel. +- **`...sqlite.SqliteSchemaInitializationAdapter`** – Flyway-basierte Schema-Initialisierung + mit `V1__initial_schema.sql`. Drei-Fall-Strategie: leere Datenbank (Flyway führt das Skript + vollständig aus), bestehender Datenbestand ohne Flyway-History (Schema-Prüfung, datiertes + Backup, dann Baseline-Eintrag ohne Skriptausführung), regulärer Folgestart mit Flyway-History + (idempotenter Lauf). Foreign-Key-Durchsetzung via `SQLiteConfig.enforceForeignKeys(true)` auf + DataSource-Ebene, sodass jede neue Verbindung automatisch `PRAGMA foreign_keys = ON` erhält. - **`...sqlite.SqliteUnitOfWorkAdapter`** – implementiert `UnitOfWorkPort`. Setzt - `autoCommit=false`, führt atomare Commits durch, rollt bei Fehlern zurück. + `autoCommit=false`, führt atomare Commits durch, rollt bei Fehlern zurück. Die innere + `TransactionOperations`-Implementierung wurde um `resetDocumentStatusForRetry(DocumentFingerprint)` + erweitert: setzt feldgenau `overall_status = 'READY_FOR_AI'`, `content_error_count = 0`, + `transient_error_count = 0`, `last_failure_instant = NULL`; alle anderen Felder und alle + `processing_attempt`-Einträge bleiben unangetastet. - **`...sqlite.SqliteDocumentRecordRepositoryAdapter`** – Stammsatz pro SHA-256-Fingerprint (Gesamtstatus, Fehlerzähler, Zieldateiname usw.). @@ -134,6 +141,12 @@ ausschließlich der Bootstrap (→ `AiProviderSelector`). über Fingerprint. Enthält u. a. Provider-Identifikator, Modellname, Prompt-Identifikator, KI-Rohantwort und finalen Zieldateinamen. +- **`...sqlite.SqliteHistoryQueryAdapter`** – implementiert `HistoryQueryPort`. Kapselt alle + lesenden Datenbankoperationen für den Historien-Tab: Übersicht (`loadOverview` mit + Sortierung `updated_at DESC, fingerprint ASC`, LIMIT 501-Strategie, case-insensitive + Freitextsuche via `LOWER()` mit Sonderzeichen-Escape für `%` und `_`), Stammsatz-Lookup + (`findRecordByFingerprint`) und Versuchshistorie (`findAttemptsByFingerprint`). + #### Konfiguration - **`...configuration.PropertiesConfigurationPortAdapter`** – implementiert `ConfigurationPort`. @@ -145,6 +158,15 @@ ausschließlich der Bootstrap (→ `AiProviderSelector`). (Schlüssel wie `api.baseUrl`, `api.model`), legt eine `.bak`-Sicherung an und überführt den Inhalt in das aktuelle Multi-Provider-Schema. +#### Prompt-Adapter + +- **`...prompt.FilesystemPromptPortAdapter`** – implementiert `PromptPort`. Lädt das + Prompt-Template aus einer externen Datei und leitet den Identifikator aus dem Dateinamen ab. + Die neue Methode `savePrompt(String content)` schreibt den Inhalt atomar: temporäre Datei + im selben Verzeichnis anlegen (gleiche Partition), Inhalt in UTF-8 schreiben, dann + `ATOMIC_MOVE` zur Zieldatei. Kein stiller Fallback bei `AtomicMoveNotSupportedException`. + Der Pfad stammt aus der Adapter-internen Konfiguration, nicht aus dem Port-Aufruf. + #### Laufzeitinfrastruktur - **`...lock.FilesystemRunLockPortAdapter`** – Lock-Datei mit PID-Inhalt. Wirft @@ -207,6 +229,11 @@ ausschließlich der Bootstrap (→ `AiProviderSelector`). Routet `AiModelCatalogPort`-Aufrufe anhand des `providerIdentifier` an den Claude- oder OpenAI-kompatiblen Modell-Katalog-Adapter. Thread-safe. +- **`...bootstrap.ApplicationVersionProvider`** – statische Hilfsklasse ohne Zustand. Liest + `Implementation-Version` aus dem Paket-Manifest via `getClass().getPackage().getImplementationVersion()`. + Fallback `"dev"` bei IDE-Start und ungepacktem Betrieb (kein Manifest-Eintrag vorhanden). + Der aufgelöste Wert wird im GUI-Pfad in `GuiStartupContext.applicationVersion` eingesetzt. + - **`...bootstrap.adapter.Log4jProcessingLogger`** – implementiert `ProcessingLogger` auf Basis von Log4j2. Unterdrückt sensitive KI-Inhalte, wenn `AiContentSensitivity.PROTECT_SENSITIVE_CONTENT` gesetzt ist. @@ -267,8 +294,18 @@ DI-Framework verwendet. - `startGuiMode()` baut via `buildGuiStartupContext()` einen `GuiStartupContext`: enthält `AiModelCatalogDispatcher`, `EnvironmentApiKeyResolutionAdapter`, `TechnicalTestOrchestrator`, `GuiConfigurationPropertiesWriter` +- Bootstrap verdrahtet zusätzlich vier neue History-Use-Cases (`DefaultHistoryOverviewUseCase`, + `DefaultHistoryDetailsUseCase`, `DefaultHistoryResetDocumentStatusUseCase`, + `DefaultDeleteDocumentHistoryUseCase`) und den `DefaultPromptEditorUseCase` als anonyme + Bridge-Implementierungen in den `GuiStartupContext` +- `ApplicationVersionProvider.resolveVersion()` wird aufgerufen und der Wert in + `GuiStartupContext.applicationVersion` gesetzt +- Wenn eine Konfigurationsdatei beim Start bekannt ist, erzeugt Bootstrap zusätzlich einen + vollständig verdrahteten `GuiPromptEditorPort` (kombiniert `FilesystemPromptPortAdapter` mit + `DefaultPromptEditorUseCase`); ohne Konfiguration erhält der Context einen No-Op-Port - `GuiAdapter.start(context)` übernimmt; ab diesem Punkt liegt die Kontrolle beim GUI-Adapter -- Im GUI-Pfad: keine SQLite-Schema-Initialisierung, kein Run-Lock-Erwerb, kein Batch-Use-Case +- Im GUI-Pfad: keine SQLite-Schema-Initialisierung beim Start, kein Run-Lock-Erwerb, kein Batch-Use-Case; + History-Operationen initialisieren die Schema-Verbindung ad-hoc pro Aufruf - GUI-interne Ports und deren Verbindung mit Outbound-Adaptern sind in `docs/architecture/gui-overview.md` beschrieben diff --git a/docs/architecture/domain-overview.md b/docs/architecture/domain-overview.md index d1b4624..b71dedb 100644 --- a/docs/architecture/domain-overview.md +++ b/docs/architecture/domain-overview.md @@ -33,6 +33,7 @@ Definiert Use-Case-Orchestrierung sowie alle Inbound- und Outbound-Ports der hex | `de.gecheckt.pdf.umbenenner.application.port.in` | Inbound-Ports (Use-Case-Interfaces) – Einstiegspunkte für den Aufrufer | | `de.gecheckt.pdf.umbenenner.application.port.out` | Outbound-Ports – Verträge gegenüber Infrastruktur-Adaptern (Persistenz, Dateisystem, KI, Uhr, Logging) | | `de.gecheckt.pdf.umbenenner.application.port.out.modelcatalog` | Spezialisierter Outbound-Port für den Abruf verfügbarer KI-Modelle; ausschließlich im GUI-Pfad genutzt (siehe `gui-overview.md`) | +| `de.gecheckt.pdf.umbenenner.application.port.out.history` | Outbound-Port für lesende Historien-Abfragen aus dem Historien-Tab; bewusst getrennt von den bestehenden Repositories, um diese nicht mit GUI-spezifischen Methoden aufzublähen | | `de.gecheckt.pdf.umbenenner.application.service` | Anwendungsnahe, zustandslose Dienste: KI-Antwort-Parsing, Pre-Check-Auswertung, Verarbeitungs-Pipeline, Retry-Entscheidung | | `de.gecheckt.pdf.umbenenner.application.config` | Konfigurationsmodelle der Anwendungsschicht (`RuntimeConfiguration`, Provider-Konfiguration) | | `de.gecheckt.pdf.umbenenner.application.config.startup` | Vollständiges Startup-Konfigurationsmodell (`StartConfiguration`) | @@ -106,6 +107,25 @@ Record für einen Versuchshistorie-Eintrag; enthält u. a. Provider-Identifikato **`de.gecheckt.pdf.umbenenner.application.port.out.DocumentRecord`** Record für den Dokument-Stammsatz; enthält Gesamtstatus, Fehler- und Transientzähler sowie letzten Zielpfad. +**`de.gecheckt.pdf.umbenenner.application.port.out.history.HistoryQuery`** +Record mit den Abfrageparametern für den Historien-Tab: optionaler Suchbegriff (`searchText`, Teilstring, case-insensitiv), optionaler Status-Filter (`statusFilter` als Enum-Name) und Limit der zurückzugebenden Zeilen (Standard `DEFAULT_LIMIT = 501`). Das Limit 501 ermöglicht der aufrufenden Schicht zu erkennen, ob mehr als 500 Treffer vorhanden sind. + +**`de.gecheckt.pdf.umbenenner.application.port.out.history.DocumentHistoryRow`** +Einzelzeile der Dokumentenliste im Historien-Tab. Felder: `fingerprint`, `overallStatus`, `sourceFileName`, `targetFileName` (null wenn noch kein Erfolg), `sourcePath`, `updatedAt` und `attemptCount`. Stammt aus `document_record` mit einem `COUNT`-Ausdruck über `processing_attempt`. + +**`de.gecheckt.pdf.umbenenner.application.port.out.PromptSaveResult`** +Versiegeltes Ergebnis-Interface für `PromptPort.savePrompt(String)`. Zulässige Ausprägungen: `Saved` (Erfolg, enthält absoluten Pfad), `WriteFailed` (I/O-Fehler beim Schreiben der Temp-Datei), `TargetDirectoryMissing` (Zielordner fehlt), `AtomicMoveFailed` (atomares Verschieben nicht möglich; kein stiller Fallback). + +**Neue Use-Case-Implementierungen im Paket `de.gecheckt.pdf.umbenenner.application.usecase`** + +| Klasse | Zweck | +|--------|-------| +| `DefaultHistoryOverviewUseCase` | Lädt die gefilterte Dokumentenübersicht über `HistoryQueryPort.loadOverview`; gibt `HistoryOverviewResult` mit Liste und `hasMore`-Flag zurück | +| `DefaultHistoryDetailsUseCase` | Lädt Stammsatz und alle Verarbeitungsversuche für einen Fingerprint über `HistoryQueryPort`; gibt `HistoryDetailsResult` zurück | +| `DefaultHistoryResetDocumentStatusUseCase` | Feldgenauer Status-Reset via `UnitOfWorkPort.TransactionOperations.resetDocumentStatusForRetry`; setzt `overall_status`, `content_error_count`, `transient_error_count` und `last_failure_instant` zurück; lässt die Versuchshistorie unangetastet | +| `DefaultDeleteDocumentHistoryUseCase` | Löscht Stammsatz und alle Verarbeitungsversuche vollständig und transaktional via `UnitOfWorkPort` | +| `DefaultPromptEditorUseCase` | Delegiert Laden, Speichern und Standard-Anlegen der Prompt-Datei an `PromptPort` und `ResourceCreationPort`; wird im GUI-Pfad über `GuiPromptEditorPort` angesteuert | + --- ## 4. Inbound Ports @@ -142,7 +162,7 @@ Alle Outbound-Ports liegen in `de.gecheckt.pdf.umbenenner.application.port.out` | `FingerprintPort` | Berechnet SHA-256-Fingerabdruck eines Kandidaten | `FingerprintResult computeFingerprint(SourceDocumentCandidate)` | | `PdfTextExtractionPort` | Extrahiert Text und Seitenanzahl aus einer PDF | `PdfExtractionResult extractTextAndPageCount(...)` | | `AiInvocationPort` | Ruft den aktiven KI-Dienst auf; provider-neutral | `AiInvocationResult invoke(AiRequestRepresentation)` | -| `PromptPort` | Lädt das Prompt-Template aus der konfigurierten Quelle | `PromptLoadingResult loadPrompt()` | +| `PromptPort` | Lädt das Prompt-Template aus der konfigurierten Quelle; speichert geänderten Inhalt atomar via `savePrompt(String)` – der Pfad stammt aus der Adapter-internen Konfiguration, nicht aus dem Port-Aufruf | `PromptLoadingResult loadPrompt()`, `PromptSaveResult savePrompt(String content)` | | `TargetFileCopyPort` | Kopiert Quelldokument unter aufgelöstem Namen in den Zielordner (Temp + Rename) | `TargetFileCopyResult copyToTarget(...)` | | `TargetFileRenamePort` | Atomare Umbenennung einer bereits kopierten Zieldatei (manuelle Korrektur) | `TargetFileRenameResult rename(...)` | | `RunLockPort` | Exklusiver Lauf-Lock gegen parallele Instanzen | `acquire()` / `release()` | @@ -154,8 +174,11 @@ Alle Outbound-Ports liegen in `de.gecheckt.pdf.umbenenner.application.port.out` | `PathCheckPort` | Lesende Pfad-Prüfung für den technischen Selbsttest | `isDirectoryReadable`, `isDirectoryWritableOrCreatable`, `isFileReadable`, `isSqlitePathUsable` | | `ResourceCreationPort` | Schreibende Korrektur-Aktionen (Ordner anlegen, Prompt-Datei erzeugen, SQLite-Pfad vorbereiten) | `createDirectory`, `createPromptFile`, `prepareSqlitePath` | | `ApiKeyResolutionPort` | Ermittelt API-Key-Herkunft pro Provider-Familie für die GUI-Validierung | `EffectiveApiKeyDescriptor resolve(...)` | +| `HistoryQueryPort` | Lesender Zugriff auf die Verarbeitungshistorie für den Historien-Tab; bewusst getrennt von den regulären Repositories | `List loadOverview(HistoryQuery)`, `Optional findRecordByFingerprint(DocumentFingerprint)`, `List findAttemptsByFingerprint(DocumentFingerprint)` | -> **Hinweis zu GUI-spezifischen Ports:** `AiModelCatalogPort`, `PathCheckPort`, `ResourceCreationPort` und `ApiKeyResolutionPort` werden ausschließlich im GUI-Pfad genutzt. Ihre Implementierungen und der Aufrufkontext sind in `gui-overview.md` beschrieben. +> **Hinweis zu GUI-spezifischen Ports:** `AiModelCatalogPort`, `PathCheckPort`, `ResourceCreationPort`, `ApiKeyResolutionPort` und `HistoryQueryPort` werden ausschließlich im GUI-Pfad genutzt. Ihre Implementierungen und der Aufrufkontext sind in `gui-overview.md` bzw. `adapter-overview.md` beschrieben. + +> **Hinweis zu `UnitOfWorkPort.TransactionOperations`:** Die innere Schnittstelle `TransactionOperations` wurde um die Methode `resetDocumentStatusForRetry(DocumentFingerprint)` erweitert. Diese setzt feldgenau `overall_status → READY_FOR_AI`, `content_error_count → 0`, `transient_error_count → 0` und `last_failure_instant → NULL`, ohne die Versuchshistorie zu berühren. Die Implementierung liegt in `SqliteUnitOfWorkAdapter`. --- diff --git a/docs/architecture/gui-overview.md b/docs/architecture/gui-overview.md index c049101..6f43892 100644 --- a/docs/architecture/gui-overview.md +++ b/docs/architecture/gui-overview.md @@ -25,20 +25,33 @@ de.gecheckt.pdf.umbenenner.adapter.in.gui ├── (root) Einstiegspunkt, Hauptfenster, Orchestrierung, GUI-interne │ Ports, Hilfsklassen für Fenstertitel, System-Tray, │ Dateiladen/-schreiben und Startkontext. +│ Enthält außerdem: GuiStatusBar, GuiPromptEditorTab und +│ GuiPromptEditorPort. │ ├── batchrun Komponenten für den Tab „Verarbeitungslauf": │ Worker-Koordinator, Tab-Ansicht, Ergebniszeilen, │ PDF-Vorschau, Dateiname-Editor sowie GUI-interne │ Port-Interfaces für Batch-Run, Mini-Run, manuelles │ Umbenennen/Kopieren, Status-Reset und historischen Kontext. +│ Enthält außerdem: BatchRunSummaryBanner und +│ ProcessingStatusPresentation. │ -└── editor View-Modell- und Zustandstypen ohne JavaFX-Controls - (Ausnahme: GuiModelFieldContainer). Enthält Snapshot, - Baseline/Current-Values, Dirty-State-Berechnung, - Provider-Konfigurationszustände, API-Key-Zustände, - Validierungsergebnisse, Meldungs- und Feldbefund-Typen. +├── editor View-Modell- und Zustandstypen ohne JavaFX-Controls +│ (Ausnahme: GuiModelFieldContainer). Enthält Snapshot, +│ Baseline/Current-Values, Dirty-State-Berechnung, +│ Provider-Konfigurationszustände, API-Key-Zustände, +│ Validierungsergebnisse, Meldungs- und Feldbefund-Typen. +│ +└── history Komponenten für den Tab „Verlauf": Tab-Ansicht mit + zweigeteiltem Layout (Liste + Detail), Filter, Aktionen + (Status-Reset / vollständiges Löschen) sowie die vier + Bridge-Interfaces GuiHistoryOverviewPort, + GuiHistoryDetailsPort, GuiHistoryResetDocumentStatusPort + und GuiDeleteDocumentHistoryPort. ``` +**Tab-Reihenfolge:** `Konfiguration | Verarbeitungslauf | Verlauf | Prompt` + --- ## 3. Schlüsselklassen @@ -49,8 +62,10 @@ de.gecheckt.pdf.umbenenner.adapter.in.gui |---|---| | `GuiAdapter` | Einziger öffentlicher Bootstrap-Einstiegspunkt. Speichert `GuiStartupContext` im `GuiStartupContextHolder` und startet JavaFX via `Application.launch`. Genau einmal pro JVM aufrufbar. | | `PdfUmbenennerGuiApplication` | JavaFX-`Application`-Unterklasse. Baut in `start(Stage)` Hauptfenster, `GuiConfigurationEditorWorkspace`, Titelaktualisierungs-Listener, Close-Handler und System-Tray auf. Triggert nach Anzeige `autoLoadLastConfiguration()`. | -| `GuiStartupContext` | Immutable Record mit allen Bootstrap-gelieferten Ports und Services: Dateilader/-schreiber, Modellkatalog-Port, API-Key-Resolution-Port, Technical-Test-Orchestrator, Correction-Execution-Service, Batch-Run-Launcher, Mini-Run-Launcher, Reset-Port, Manual-Rename-Port, Manual-Copy-Port, Historical-Context-Port. Bietet `blank()`-Fabrikmethode für Tests. | -| `GuiConfigurationEditorWorkspace` | Herzstück der Oberfläche. Baut `TabPane` mit Editor-Tab und Verarbeitungslauf-Tab, verwaltet `GuiConfigurationEditorState`, koordiniert Lade- und Schreibvorgänge auf Worker-Threads, steuert Dirty-State-Anzeige und Fenstertitel. | +| `GuiStartupContext` | Immutable Record mit allen Bootstrap-gelieferten Ports und Services: Dateilader/-schreiber, Modellkatalog-Port, API-Key-Resolution-Port, Technical-Test-Orchestrator, Correction-Execution-Service, Batch-Run-Launcher, Mini-Run-Launcher, Reset-Port, Manual-Rename-Port, Manual-Copy-Port, Historical-Context-Port, `applicationVersion` (Versions-String aus `ApplicationVersionProvider`), `promptEditorPort`, `historyOverviewPort`, `historyDetailsPort`, `historyResetDocumentStatusPort`, `deleteDocumentHistoryPort`. Bietet `blank()`-Fabrikmethode für Tests. | +| `GuiConfigurationEditorWorkspace` | Herzstück der Oberfläche. Baut `TabPane` mit den vier Tabs (Konfiguration, Verarbeitungslauf, Verlauf, Prompt), verwaltet `GuiConfigurationEditorState`, koordiniert Lade- und Schreibvorgänge auf Worker-Threads, steuert Dirty-State-Anzeige und Fenstertitel. | +| `GuiStatusBar` | Permanente Statuszeile am unteren Rand des Hauptfensters. Drei Segmente: links Anwendungsversion im Format `V` (z. B. `Vdev`), Mitte aktiver Provider und Modell aus geladener Konfiguration, rechts Pfad der geladenen Konfigurationsdatei. Ohne geladene Konfiguration zeigen Mitte und Rechts den Platzhaltertext. | +| `GuiPromptEditorTab` | Tab „Prompt" mit `TextArea` zum Lesen, Bearbeiten und Speichern der Prompt-Datei. Dirty-State markiert den Tab-Titel mit einem Asterisk. Speichert atomar via `GuiPromptEditorPort`. Bietet „Auf Standard zurücksetzen" (füllt `TextArea` ohne zu speichern) und „Standard-Prompt erstellen" bei fehlender Datei. | | `GuiModelCatalogCoordinator` | Asynchroner Modellabruf über `AiModelCatalogPort` auf Daemon-Thread `gui-model-catalog`. Liefert Ergebnis via `Platform.runLater` und aktualisiert ComboBox oder manuelles TextField. | | `GuiTechnicalTestCoordinator` | Führt `TechnicalTestOrchestrator` asynchron auf Daemon-Thread `gui-technical-test` aus, ohne implizites Speichern. Replace-Semantik in `pendingMessages`. | | `GuiCorrectionDialogCoordinator` | Empfängt `TechnicalTestReport`, leitet `CorrectionPlan` ab, zeigt gesammelten Bestätigungsdialog. Kein stiller Schreibzugriff. | @@ -70,10 +85,18 @@ de.gecheckt.pdf.umbenenner.adapter.in.gui |---|---| | `GuiBatchRunCoordinator` | Besitzt den Worker-Thread für Batch- und Mini-Run. Übersetzt `BatchRunProgressObserver`-Callbacks via `Platform.runLater`. Soft-Stop per `AtomicBoolean`. Enthält `toRow()` inkl. historischem Kontext-Nachladen. | | `GuiBatchRunTab` | Zweiter Haupt-Tab mit `TableView`, `ProgressBar`, Start-/Stop-Buttons und Detailbereich. Implementiert `GuiBatchRunCoordinator.Listener`. | +| `BatchRunSummaryBanner` | Einzeilige Zusammenfassungsleiste nach Laufabschluss, unterhalb des Fortschrittsbalkens. Zeigt nur Kategorien mit Zähler > 0. Farbe ist niemals das einzige Unterscheidungsmerkmal: jedes Segment enthält Icon und Text. | +| `ProcessingStatusPresentation` | Zentrale Mapping-Klasse für Status-Icons, CSS-Farben, Tooltip-Texte und Summary-Kategoriebeschriften aller `DocumentCompletionStatus`-Werte. Einzige autoritative Quelle für alle Anzeigeorte (Tabelle, Detail, Banner). Enthält keine JavaFX-Typen; zustandslos und statisch. Farbe ist niemals das einzige Unterscheidungsmerkmal. | | `PdfPreviewPane` | Asynchrones PDF-Rendering via PDFBox auf Single-Thread-Executor `pdf-preview-worker`. Stale-Request-Schutz via `AtomicLong`-Sequenznummer, In-Memory-Seiten-Cache. | | `FileNameEditorPane` | Editor für den Zieldateinamen. Drei-Zustands-Modell: KI-Vorschlag / letzter gespeicherter / aktuelle Eingabe. Clientseitige Validierung; Speicher-Aufruf delegiert an Tab. | | `AiFailureMessageTranslator` | Übersetzt englische technische Fehlermeldungen in deutsche Benutzertexte. Paket-privat, zustandslos. | +### Paket `history` + +| Klasse (Kurzname) | Rolle | +|---|---| +| `GuiHistoryTab` | Tab „Verlauf" mit zweigeteiltem Layout: links Dokumentenliste mit Freitext- und Statusfilter, rechts Detailbereich mit Stammsatz und Versuchshistorie. Aktionen: Status-Reset (feldgenau, Versuchshistorie bleibt) und vollständiges Löschen (mit Bestätigungsdialog). Alle Datenbankoperationen auf Worker-Thread, UI-Updates via `Platform.runLater`. | + --- ## 4. Threading-Modell @@ -92,6 +115,8 @@ Alle blockierenden Operationen laufen auf benannten Daemon-Threads außerhalb de | Korrektur-Worker (anonym) | `GuiCorrectionDialogCoordinator` | `correctionExecutionService.execute(...)` | | `pdf-preview-worker` | `PdfPreviewPane` | `PDDocument` laden, `PDFRenderer.renderImageWithDPI`, `PDDocument.close` | | Dateisystem-Worker (inline) | `GuiConfigurationEditorWorkspace` | `configurationFileLoader.load(...)`, `configurationFileWriter.write(...)` | +| Inline-Worker (anonym) | `GuiHistoryTab` | `historyOverviewPort.loadOverview(...)`, `historyDetailsPort.loadDetails(...)`, `historyResetDocumentStatusPort.resetStatus(...)`, `deleteDocumentHistoryPort.deleteHistory(...)` | +| Inline-Worker (anonym) | `GuiPromptEditorTab` | `promptEditorPort.loadCurrentPrompt()`, `promptEditorPort.save(...)`, `promptEditorPort.createDefaultPromptIfMissing(...)` | ### 4.2 JavaFX Application Thread @@ -137,13 +162,28 @@ Durch diese Injektion sind Unit-Tests vollständig ohne JavaFX-Runtime möglich. |---|---| | `GuiBatchRunLauncher` | Bootstrap-Brücke für den regulären Batch-Run auf dem Worker-Thread. | | `GuiMiniRunLauncher` | Bootstrap-Brücke für einen auf einen Fingerprint-Filter beschränkten Mini-Run. | -| `GuiResetDocumentStatusPort` | Bootstrap-Brücke für einen Statusreset ohne Folge-Run. | +| `GuiResetDocumentStatusPort` | Bootstrap-Brücke für den vollständigen Persistenz-Reset (Stammsatz und Versuchshistorie werden gelöscht) ohne Folge-Run. | | `GuiManualFileRenamePort` | Bootstrap-Brücke für die manuelle Umbenennung der Zieldatei (Worker-Thread). | | `GuiManualFileCopyPort` | Bootstrap-Brücke für die Kopie mit benutzerdefiniertem Zieldateinamen bei FAILED/SKIPPED-Dokumenten (Worker-Thread). | | `GuiHistoricalDocumentContextPort` | Nachladen des vollständigen historischen Verarbeitungskontexts für übersprungene Dokumente (Worker-Thread). | | `GuiHistoricalFileNamePort` | Spezialisierter Port für den letzten bekannten KI-Dateinamen. Weitgehend durch `GuiHistoricalDocumentContextPort` abgelöst, aber noch im Einsatz. | -Alle Implementierungen dieser Interfaces liegen in `pdf-umbenenner-bootstrap` oder `pdf-umbenenner-adapter-out`. Das GUI-Modul kennt ausschließlich die Interface-Typen. +### Root-Paket (GUI-interne Ports) + +| Interface | Zweck | +|---|---| +| `GuiPromptEditorPort` | Bootstrap-Brücke zum Prompt-Editor-Use-Case: Laden (`loadCurrentPrompt()`), atomares Speichern (`save(String)`) und Standard-Anlegen (`createDefaultPromptIfMissing(...)`) der Prompt-Datei. | + +### Paket `history` + +| Interface | Zweck | +|---|---| +| `GuiHistoryOverviewPort` | Bootstrap-Brücke zur Historien-Übersicht; lädt gefilterte Dokumentenliste via `loadOverview(Path configFilePath, HistoryQuery)`. `configFilePath` ermöglicht der Bootstrap-Implementierung, die SQLite-Datenbank aus der aktuell geladenen Konfiguration abzuleiten. | +| `GuiHistoryDetailsPort` | Bootstrap-Brücke zur Detailansicht; lädt Stammsatz und alle Verarbeitungsversuche für einen Fingerprint via `loadDetails(Path, DocumentFingerprint)`. | +| `GuiHistoryResetDocumentStatusPort` | Bootstrap-Brücke für den feldgenauen Status-Reset im Historien-Tab (`overall_status → READY_FOR_AI`, Fehlerzähler → 0, `last_failure_instant → null`). Die Versuchshistorie bleibt vollständig erhalten. **Abgrenzung:** `GuiResetDocumentStatusPort` im `batchrun`-Paket löscht dagegen Stammsatz und Versuchshistorie vollständig. | +| `GuiDeleteDocumentHistoryPort` | Bootstrap-Brücke zum vollständigen Löschen von Stammsatz und Versuchshistorie via `deleteHistory(Path, DocumentFingerprint)`; destruktiv und nicht rückgängig zu machen. Die GUI zeigt vor dem Aufruf einen Bestätigungsdialog. | + +Alle Implementierungen dieser Interfaces liegen in `pdf-umbenenner-bootstrap`. Das GUI-Modul kennt ausschließlich die Interface-Typen. ---