diff --git a/CLAUDE.md b/CLAUDE.md index d641762..2eb802d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -11,9 +11,18 @@ Ab V2.0 wird die Anwendung um eine **lokale JavaFX-Desktop-GUI** erweitert. Die @docs/specs/meilensteine-v2_0.md Für die Umsetzung ist zusätzlich immer das aktuell aktive Arbeitspaket unter `docs/workpackages/` maßgeblich. -Dateinamensschema: `M9 - Arbeitspakete.md`, `M10 - Arbeitspakete.md`, … `M13 - Arbeitspakete.md` +Dateinamensschema: `M9 - Arbeitspakete.md`, `M10 - Arbeitspakete.md`, … `M13 - Arbeitspakete.md`, `M14_-_Arbeitspakete.md`, `M15_-_Arbeitspakete.md`. Nicht raten, wenn Dokumente fehlen, unklar sind oder sich widersprechen. +## Modulare Architektur-Übersichten +Detailwissen über Pakete, Schlüsselklassen, Ports und Bootstrap-Verdrahtung ist in drei modularen Übersichtsdokumenten unter `docs/architecture/` ausgelagert. Wer in einem bestimmten Modul arbeitet, liest diese Datei zusätzlich zu CLAUDE.md: + +- `docs/architecture/domain-overview.md` – `pdf-umbenenner-domain` und `pdf-umbenenner-application`: Domänenmodell, Inbound- und Outbound-Ports, Application-Services. +- `docs/architecture/gui-overview.md` – `pdf-umbenenner-adapter-in-gui`: Workspace-/Tab-Struktur, View-Modelle, GUI-interne Ports, JavaFX-Threading-Modell. +- `docs/architecture/adapter-overview.md` – `pdf-umbenenner-adapter-out`, `pdf-umbenenner-adapter-in-cli`, `pdf-umbenenner-bootstrap`: konkrete Outbound-Adapter, CLI-Einstiegspunkt, Verdrahtungslogik und Provider-Auswahl. + +Für Arbeit ausschließlich in einem dieser Bereiche genügt CLAUDE.md plus die jeweils passende Übersichtsdatei. + ## Priorisierung der Regeln Die Dokumente haben folgende feste Bedeutung: @@ -138,30 +147,9 @@ V1.1 ist vollständig umgesetzt, dokumentiert, getestet und freigegeben. Der Basisstand V2.0 (JavaFX-GUI als Standardstart, Konfigurationseditor, technische Tests) ist abgeschlossen. -**V2.9 ist abgeschlossen.** Der Tab „Verarbeitungslauf" wurde erweitert um: +**V2.9 ist abgeschlossen.** Der Tab „Verarbeitungslauf" wurde erweitert um eine integrierte PDF-Vorschau (Lazy-Rendering direkt über PDFBox, In-Memory-Cache, Seitennavigation) sowie einen editierbaren Dateiname-Bereich mit Live-Validierung, Dirty-State-Dialog und atomarer Dateisystem-/DB-Transaktion inklusive Rollback und Fingerprint-basierter Konfliktauflösung. Die zugehörigen neuen Ports, Use Cases und Adapter sind in den modularen Architektur-Übersichten beschrieben. -- **Integrierte PDF-Vorschau** (`PdfPreviewPane`) mit Lazy-Rendering, In-Memory-Cache und - Seitennavigation. Das Rendering erfolgt direkt über PDFBox - (`PDFRenderer.renderImageWithDPI` + `SwingFXUtils.toFXImage`); eine externe PDFViewFX-Abhängigkeit - wird nicht mehr verwendet. -- **Editierbarer Dateiname-Bereich** (`FileNameEditorPane`) mit Live-Validierung, Dirty-State-Dialog - bei Zeilen-/Tabwechsel, Schließen und Laufstart sowie atomarer Dateisystem- und DB-Transaktion - inkl. Rollback und Fingerprint-basierter Konfliktauflösung. - -Neue Architekturkomponenten in V2.9: - -- Outbound-Port `TargetFileRenamePort` (`pdf-umbenenner-application`) -- Application-Use-Case `ManualFileRenameUseCase` / `DefaultManualFileRenameUseCase` -- Adapter-Out `FilesystemTargetFileRenameAdapter` (`pdf-umbenenner-adapter-out`) -- GUI-interner Port `GuiManualFileRenamePort` (`pdf-umbenenner-adapter-in-gui`) - -Weitere Verhaltensänderungen: - -- Die GUI startet **maximiert** (Vollbild); `stage.setMaximized(true)` in `PdfUmbenennerGuiApplication`. -- Beim Start wird die **zuletzt geladene Konfigurationsdatei** automatisch geladen - (gespeichert in `java.util.prefs.Preferences` unter Schlüssel `lastConfigPath`, - umgesetzt in `GuiConfigurationEditorWorkspace.autoLoadLastConfiguration()`). - Existiert die Datei nicht mehr, startet die GUI ohne Fehlermeldung mit dem Willkommenstext. +Verhaltensänderungen seit V2.9: Die GUI startet maximiert, und die zuletzt geladene Konfigurationsdatei wird beim Start automatisch wieder geladen; existiert sie nicht mehr, startet die GUI ohne Fehlermeldung mit dem Willkommenstext. Die fachliche Kernverarbeitung des PDF-Umbenenners bleibt unverändert. diff --git a/docs/architecture/adapter-overview.md b/docs/architecture/adapter-overview.md new file mode 100644 index 0000000..72977dd --- /dev/null +++ b/docs/architecture/adapter-overview.md @@ -0,0 +1,319 @@ +# Architektur-Übersicht: Adapter-Out, CLI & Bootstrap + +Diese Datei beschreibt die drei Module `pdf-umbenenner-adapter-out`, `pdf-umbenenner-adapter-in-cli` +und `pdf-umbenenner-bootstrap`: ihren Zweck, ihre Paketstruktur, die wichtigsten Klassen und die +Verdrahtungslogik beim Programmstart. Sie richtet sich an Entwickler, die in einem dieser Module +arbeiten wollen und noch keinen Überblick über das Projekt haben. Domain- und Application-Schicht +(Port-Verträge, fachliche Domänenobjekte, Use-Case-Interfaces) sind nicht Gegenstand dieses +Dokuments – sie sind in `docs/architecture/domain-overview.md` beschrieben. GUI-interne Ports und +die Struktur des GUI-Adapters finden sich in `docs/architecture/gui-overview.md`. Die hexagonale +Abhängigkeitsrichtung ist strikt: Adapter kennen Domain und Application, nicht umgekehrt. Adapter +dürfen außerdem nicht direkt voneinander abhängen. + +--- + +## 1. Modulzweck + +### pdf-umbenenner-adapter-out + +Enthält alle Outbound-Adapter-Implementierungen, also die konkreten technischen Lösungen für +sämtliche Outbound-Ports der Application. Dazu gehören: Dateisystemzugriff, PDF-Textextraktion +via PDFBox, SQLite-Persistenz (Schema, Repositories, Unit of Work), HTTP-Clients für zwei +KI-Provider-Familien (OpenAI-kompatibel und Anthropic nativ), Properties-Konfiguration inklusive +Legacy-Migration, dateibasierter Run-Lock sowie Systemuhr und SHA-256-Fingerprint. + +### pdf-umbenenner-adapter-in-cli + +Schlanker Inbound-Adapter für den kopflosen Batch-Betrieb. Enthält genau eine Klasse +(`SchedulerBatchCommand`), die den CLI-Einstiegspunkt bildet und ausschließlich über das +Inbound-Port-Interface an die Application delegiert. Keine eigene Fachlogik. + +### pdf-umbenenner-bootstrap + +Composition Root der Anwendung. Verantwortlich für: CLI-Argument-Parsing, +Konfigurationsauflösung und -validierung, Aufbau des vollständigen Objektgraphen (manuell, ohne +DI-Framework), Auswahl der aktiven KI-Adapter-Implementierung, Dispatch auf GUI- oder +Headless-Pfad sowie Exit-Code-Ableitung. Bootstrap ist die einzige Stelle, an der alle Module +zusammengeführt werden. + +--- + +## 2. Paketstruktur + +### pdf-umbenenner-adapter-out + +Wurzelpaket: `de.gecheckt.pdf.umbenenner.adapter.out` + +| Unterpaket | Inhalt | +|-------------------------|-------------------------------------------------------------------------------------| +| `.ai` | HTTP-Adapter für OpenAI-kompatible Schnittstelle und Anthropic Messages API | +| `.clock` | Systemuhr-Adapter (`Instant.now()`) | +| `.configuration` | Properties-Laden, Multi-Provider-Parsing/-Validierung, Legacy-Migration | +| `.fingerprint` | SHA-256-Inhalts-Fingerprint | +| `.lock` | Dateibasierter Run-Lock | +| `.modelcatalog` | HTTP-Modellabruf für den GUI-Konfigurationseditor | +| `.pathcheck` | Pfadprüfung für den GUI-Editor | +| `.pdfextraction` | PDFBox-3.x-Adapter: Textextraktion und Seitenanzahl | +| `.prompt` | Prompt-Template-Lader | +| `.resourcecreation` | Anlegen von Ordnern und Dateien (korrigierende technische Tests) | +| `.sourcedocument` | Quellordner-Scanner (nicht rekursiv) | +| `.sqlite` | Schema-Initialisierung, Repositories, Unit of Work | +| `.targetcopy` | Zielkopie via Temp-Datei und atomarem Move | +| `.targetfolder` | Kollisionsfreier Zieldateiname, Umbenennung bestehender Zieldateien | +| `.validation` | API-Key-Auflösung aus Umgebungsvariablen (GUI-Editor) | +| `.bootstrap.validation` | `StartConfiguration`-Validierung vor Prozessstart | + +### pdf-umbenenner-adapter-in-cli + +Wurzelpaket: `de.gecheckt.pdf.umbenenner.adapter.in.cli` + +Enthält ausschließlich `SchedulerBatchCommand` sowie die zugehörige `package-info.java`. + +### pdf-umbenenner-bootstrap + +Wurzelpaket: `de.gecheckt.pdf.umbenenner.bootstrap` + +| Unterpaket | Inhalt | +|---------------------|-------------------------------------------------------------------------------------------------------| +| *(Wurzel)* | `PdfUmbenennerApplication` (main), `BootstrapRunner`, `AiProviderSelector` | +| `.adapter` | Bootstrap-interne Adapter: `Log4jProcessingLogger`, `GuiConfigurationPropertiesWriter`, `AiModelCatalogDispatcher` | +| `.singleinstance` | `SingleInstanceGuard` – Einzelinstanz-Schutz via Loopback-ServerSocket | +| `.startup` | `StartupMode`, `StartupArguments`, `CliArgumentParser` | + +--- + +## 3. Schlüsselklassen + +Die folgenden Klassen sind für das Verständnis der drei Module zentral. FQN-Kürzel: `...` steht +jeweils für das Wurzelpaket des Moduls. + +### Adapter-Out + +#### KI-Adapter + +- **`...ai.OpenAiHttpAdapter`** – implementiert `AiInvocationPort` für OpenAI-kompatible Endpunkte. + POST `{baseUrl}/v1/chat/completions`, Bearer-Authentifizierung, extrahiert + `choices[0].message.content`, klassifiziert HTTP-Fehler und Timeouts als + `AiInvocationTechnicalFailure`. + +- **`...ai.AnthropicClaudeHttpAdapter`** – implementiert `AiInvocationPort` für die native + Anthropic Messages API. POST `/v1/messages`, Header `x-api-key` und `anthropic-version`, + konkateniert `text`-Content-Blöcke aus dem Antwort-Array. + +Beide Adapter liefern denselben Domain-Typ (`NamingProposal`) und enthalten keinerlei +provider-spezifische Typen in öffentlichen Signaturen. Welche Implementierung aktiv ist, entscheidet +ausschließlich der Bootstrap (→ `AiProviderSelector`). + +#### Modell-Katalog (GUI) + +- **`...modelcatalog.ClaudeModelCatalogAdapter`** – `AiModelCatalogPort` für Claude, + GET `/v1/models` mit `x-api-key`. + +- **`...modelcatalog.OpenAiCompatibleModelCatalogAdapter`** – `AiModelCatalogPort` für + OpenAI-kompatibel, GET `/v1/models` mit Bearer. + +#### PDF-Extraktion + +- **`...pdfextraction.PdfTextExtractionPortAdapter`** – PDFBox-3.x-Adapter. Alle technischen + Fehler werden als `PdfExtractionTechnicalError` zurückgegeben; es werden keine Exceptions + propagiert. + +#### 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.SqliteUnitOfWorkAdapter`** – implementiert `UnitOfWorkPort`. Setzt + `autoCommit=false`, führt atomare Commits durch, rollt bei Fehlern zurück. + +- **`...sqlite.SqliteDocumentRecordRepositoryAdapter`** – Stammsatz pro SHA-256-Fingerprint + (Gesamtstatus, Fehlerzähler, Zieldateiname usw.). + +- **`...sqlite.SqliteProcessingAttemptRepositoryAdapter`** – Versuchshistorie, referenziert + über Fingerprint. Enthält u. a. Provider-Identifikator, Modellname, Prompt-Identifikator, + KI-Rohantwort und finalen Zieldateinamen. + +#### Konfiguration + +- **`...configuration.PropertiesConfigurationPortAdapter`** – implementiert `ConfigurationPort`. + Lädt `config/application.properties` (oder einen `--config`-Override), parst via + `MultiProviderConfigurationParser`, löst API-Keys aus Umgebungsvariablen + (`OPENAI_COMPATIBLE_API_KEY`, `ANTHROPIC_API_KEY`). + +- **`...configuration.LegacyConfigurationMigrator`** – erkennt alte Flat-Key-Konfigurationen + (Schlüssel wie `api.baseUrl`, `api.model`), legt eine `.bak`-Sicherung an und überführt den + Inhalt in das aktuelle Multi-Provider-Schema. + +#### Laufzeitinfrastruktur + +- **`...lock.FilesystemRunLockPortAdapter`** – Lock-Datei mit PID-Inhalt. Wirft + `RunLockUnavailableException`, wenn die Datei bereits vorhanden ist. Release löscht die Datei + (best-effort). + +- **`...clock.SystemClockAdapter`** – delegiert an `Instant.now()`. + +- **`...fingerprint.Sha256FingerprintAdapter`** – SHA-256 über den Rohdatei-Inhalt. Fehler als + `FingerprintTechnicalError`. + +#### Zieldatei + +- **`...targetcopy.FilesystemTargetFileCopyAdapter`** – kopiert die Quelldatei zunächst in eine + `.tmp`-Datei, dann atomarer Move (Fallback: Standard-Move). Die Quelldatei wird in keinem Fall + verändert. + +- **`...targetfolder.FilesystemTargetFolderAdapter`** – ermittelt einen kollisionsfreien + Zieldateinamen mit `(1)`, `(2)`-Suffix. Erkennt inhaltsidentische Duplikate via SHA-256. + +#### Validierung vor Prozessstart + +- **`...bootstrap.validation.StartConfigurationValidator`** – validiert die geladene + `StartConfiguration` auf Pflichtfelder, Wertebereiche, URI-Syntax und Pfadbedingungen. + Wird im Bootstrap-Headless-Pfad unmittelbar nach dem Laden der Konfiguration aufgerufen. + +--- + +### Adapter-In-CLI + +- **`...adapter.in.cli.SchedulerBatchCommand`** – einziger Inbound-Adapter für den Headless-Betrieb. + Nimmt einen `BatchRunContext` entgegen, delegiert an `BatchRunProcessingUseCase.execute()` und + gibt `BatchRunOutcome` zurück. Enthält keine eigene Fachlogik; die Verdrahtung mit dem + Use-Case-Interface erfolgt ausschließlich im Bootstrap. + +--- + +### Bootstrap + +- **`...bootstrap.PdfUmbenennerApplication`** – `main`-Methode. Parst CLI-Argumente via + `CliArgumentParser`, bricht bei ungültiger Verwendung mit Exit-Code 1 ab, delegiert an + `BootstrapRunner.run()` und ruft abschließend `System.exit()` mit dem zurückgegebenen Code auf. + +- **`...bootstrap.BootstrapRunner`** – Herzstück der Verdrahtung. Baut den Objektgraph für + Headless- und GUI-Pfad, dispatcht über `StartupMode`, enthält `buildProductionBatchUseCase()` + und `runHeadlessBatch()` als zentrale Kompositionsmethoden, liefert den Exit-Code zurück. + +- **`...bootstrap.AiProviderSelector`** – einzige Stelle, an der `AiProviderFamily` auf eine + konkrete `AiInvocationPort`-Implementierung abgebildet wird: + `OPENAI_COMPATIBLE` → `OpenAiHttpAdapter`, `CLAUDE` → `AnthropicClaudeHttpAdapter`. + +- **`...bootstrap.startup.CliArgumentParser`** – parst `--headless` und `--config ` zu einem + typsicheren `StartupArgumentsParseResult` (sealed: `Valid` / `Invalid`). + +- **`...bootstrap.singleinstance.SingleInstanceGuard`** – bindet einen Loopback-ServerSocket auf + Port 47832. Wirft `AnotherInstanceRunningException`, wenn der Port bereits belegt ist. Ein + Shutdown-Hook gibt den Socket frei. + +- **`...bootstrap.adapter.AiModelCatalogDispatcher`** – Bootstrap-interner Dispatcher für die GUI. + Routet `AiModelCatalogPort`-Aufrufe anhand des `providerIdentifier` an den Claude- oder + OpenAI-kompatiblen Modell-Katalog-Adapter. Thread-safe. + +- **`...bootstrap.adapter.Log4jProcessingLogger`** – implementiert `ProcessingLogger` auf Basis + von Log4j2. Unterdrückt sensitive KI-Inhalte, wenn `AiContentSensitivity.PROTECT_SENSITIVE_CONTENT` + gesetzt ist. + +- **`...bootstrap.adapter.GuiConfigurationPropertiesWriter`** – schreibt die im GUI-Editor + bearbeitete Konfiguration als normalisierte `application.properties` zurück auf das Dateisystem. + +--- + +## 4. Verdrahtungslogik in Bootstrap + +Die folgende Sequenz beschreibt den Ablauf von `main()` bis zum Start des eigentlichen Adapters. +Der Objektgraph wird ausschließlich durch manuelle `new`-Aufrufe aufgebaut; es wird kein +DI-Framework verwendet. + +**Argument-Parsing** +- `PdfUmbenennerApplication.main()` → `CliArgumentParser.parse(args)` +- Ergebnis `Invalid` → Exit-Code 1, keine weiteren Schritte + +**Einzelinstanz-Schutz** +- `BootstrapRunner.run()` → `SingleInstanceGuard.acquire()` +- `AnotherInstanceRunningException` → Exit-Code 1; im GUI-Modus zusätzlich ein Swing-Warndialog + +**Modus-Dispatch** +- `BootstrapRunner.run()` wertet `startupArguments.mode()` aus: + - `HEADLESS` → `runHeadlessBatch()` + - `GUI` → `startGuiMode()` + +**Konfigurationsauflösung (Headless-Pfad)** +- Prüfung, ob `--config`-Datei existiert (Fehler → Exit-Code 1) +- `LegacyConfigurationMigrator.migrateIfLegacy()` bei erkannter Legacy-Form +- `PropertiesConfigurationPortAdapter` lädt und parst die Properties +- `StartConfigurationValidator` validiert die geladene `StartConfiguration` +- Validierungsfehler → Exit-Code 1 + +**KI-Provider-Auswahl** +- Innerhalb von `buildProductionBatchUseCase()`: + `multiProviderConfiguration().activeProviderFamily()` → `AiProviderSelector.select(family, providerConfig)` +- Ergebnis: genau eine `AiInvocationPort`-Instanz + +**Objektgraph-Aufbau (Headless)** +- Erzeugte Instanzen (Reihenfolge nach Abhängigkeit): `Sha256FingerprintAdapter`, + `SqliteDocumentRecordRepositoryAdapter`, `SqliteProcessingAttemptRepositoryAdapter`, + `SqliteUnitOfWorkAdapter`, `FilesystemTargetFolderAdapter`, `FilesystemTargetFileCopyAdapter`, + `FilesystemPromptPortAdapter`, `SystemClockAdapter`, `SourceDocumentCandidatesPortAdapter`, + `PdfTextExtractionPortAdapter`, `Log4jProcessingLogger` +- Application-Services (`DocumentProcessingCoordinator`, `AiResponseValidator`, + `AiNamingService`) werden verdrahtet und in `DefaultBatchRunProcessingUseCase` eingebettet + +**CLI-Adapter** +- `BootstrapRunner` erzeugt `SchedulerBatchCommand` mit dem fertigen `BatchRunProcessingUseCase` + +**Exit-Code-Ableitung** +- `BatchRunOutcome` → 0 (Lauf technisch erfolgreich) oder 1 (harter Bootstrap-/Konfigurationsfehler) +- `PdfUmbenennerApplication` ruft `System.exit(exitCode)` auf + +**GUI-Pfad** +- `startGuiMode()` baut via `buildGuiStartupContext()` einen `GuiStartupContext`: + enthält `AiModelCatalogDispatcher`, `EnvironmentApiKeyResolutionAdapter`, + `TechnicalTestOrchestrator`, `GuiConfigurationPropertiesWriter` +- `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 +- GUI-interne Ports und deren Verbindung mit Outbound-Adaptern sind in + `docs/architecture/gui-overview.md` beschrieben + +--- + +## 5. Einstiegspunkte je Modul + +### pdf-umbenenner-adapter-out + +1. **`...ai.OpenAiHttpAdapter`** – zeigt das typische Adapter-Muster: Port-Interface implementieren, + alle provider-spezifischen Details kapseln, `ProviderConfiguration` als einzige + Konfigurationsquelle konsumieren. Danach `AnthropicClaudeHttpAdapter` zum Vergleich lesen. + +2. **`...sqlite.SqliteSchemaInitializationAdapter`** – erklärt das Datenbankschema, das alle + SQLite-Adapter voraussetzen. Hier sieht man, welche Felder in `document_record` und + `processing_attempt` existieren und wie Schema-Evolution additiv umgesetzt ist. + +3. **`...configuration.PropertiesConfigurationPortAdapter`** – Einstieg in die + Konfigurationskette. Von hier aus `MultiProviderConfigurationParser` und + `LegacyConfigurationMigrator` nachverfolgen. + +### pdf-umbenenner-adapter-in-cli + +1. **`...adapter.in.cli.SchedulerBatchCommand`** – komprimiertes Inbound-Adapter-Muster in einer + einzigen Klasse. Zeigt, wie ein Inbound-Adapter ausschließlich über Port-Interfaces mit der + Application kommuniziert. + +2. **`package-info.java`** – beschreibt Abhängigkeitsrichtung und Verdrahtungsvertrag dieses + Adapters. + +3. **`SchedulerBatchCommandTest`** – zeigt, wie der Adapter ohne Bootstrap testbar ist. + +### pdf-umbenenner-bootstrap + +1. **`PdfUmbenennerApplication`** – Startpunkt; die kurze Kette von `main()` bis `System.exit()` + gibt einen ersten Überblick über die gesamte Startsequenz. + +2. **`BootstrapRunner`** – Herzstück; `buildProductionBatchUseCase()` zeigt, wie der vollständige + Objektgraph manuell aufgebaut wird. `runHeadlessBatch()` zeigt den Headless-Kontrollfluss. + +3. **`AiProviderSelector`** – kleinste Klasse mit größter Hebelwirkung: hier liegt die einzige + Stelle, an der die Provider-Auswahl aus der Konfiguration auf eine konkrete + `AiInvocationPort`-Implementierung trifft. + +--- + +*Port-Verträge und Domain-Typen: `docs/architecture/domain-overview.md`* +*GUI-interne Ports und GUI-Adapter-Struktur: `docs/architecture/gui-overview.md`* diff --git a/docs/architecture/domain-overview.md b/docs/architecture/domain-overview.md new file mode 100644 index 0000000..d1b4624 --- /dev/null +++ b/docs/architecture/domain-overview.md @@ -0,0 +1,170 @@ +# Architektur-Übersicht: Domain & Application + +Dieses Dokument beschreibt die fachliche und anwendungsnahe Schicht des PDF-Umbenenners: das Modul `pdf-umbenenner-domain` und das Modul `pdf-umbenenner-application`. Es richtet sich an Entwickler, die in diesen beiden Modulen arbeiten, und soll als alleiniger Architekturkontext ausreichen – ergänzt durch die `CLAUDE.md` im Projektroot. Nicht enthalten sind Adapter-Implementierungen (Dateisystem, PDFBox, SQLite, HTTP-Clients); diese sind in `adapter-overview.md` beschrieben. GUI-spezifische Ports und deren Einbettung in den Konfigurationseditor sind in `gui-overview.md` dokumentiert. + +--- + +## 1. Modulzweck + +### `pdf-umbenenner-domain` + +Enthält ausschließlich fachliche Kerntypen (Records, Enums, Sealed Interfaces) ohne jegliche Infrastrukturabhängigkeiten. Alle Typen modellieren den Problembereich und sind von anderen Modulen referenzierbar, ohne transitive Abhängigkeiten einzuschleppen. + +### `pdf-umbenenner-application` + +Definiert Use-Case-Orchestrierung sowie alle Inbound- und Outbound-Ports der hexagonalen Architektur. Enthält anwendungsnahe Dienste (KI-Antwort-Parsing, Pre-Check-Auswertung, Retry-Entscheidung) und Konfigurationsmodelle, aber keinerlei Infrastrukturcode (kein JDBC, kein PDFBox, kein HTTP-Client, kein JavaFX). + +--- + +## 2. Paketstruktur + +### `pdf-umbenenner-domain` + +| Paket | Verantwortung | +|-------|---------------| +| `de.gecheckt.pdf.umbenenner.domain` | Wurzelpaket; enthält nur `package-info.java` | +| `de.gecheckt.pdf.umbenenner.domain.model` | Alle fachlichen Kerntypen: Records, Sealed Interfaces und Enums, die die Verarbeitungsdomäne beschreiben | + +### `pdf-umbenenner-application` + +| Paket | Verantwortung | +|-------|---------------| +| `de.gecheckt.pdf.umbenenner.application` | Wurzelpaket des Application-Moduls | +| `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.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`) | +| `de.gecheckt.pdf.umbenenner.application.config.provider` | Modelle für KI-Provider-Konfiguration (Provider-Familie, Einzelkonfiguration, Multi-Provider) | +| `de.gecheckt.pdf.umbenenner.application.validation.editor` | Validierungslogik für den GUI-Konfigurationseditor (Findings, Report, API-Key-Auflösung); siehe `gui-overview.md` | +| `de.gecheckt.pdf.umbenenner.application.validation.technicaltest` | Technischer Selbsttest: Pfad-Checks, Korrekturpläne, Checkpoints; Details in `gui-overview.md` | +| `de.gecheckt.pdf.umbenenner.application.usecase` | Paket-Marker für Use-Case-Implementierungen | + +--- + +## 3. Schlüsselklassen + +### Domain-Modul + +**`de.gecheckt.pdf.umbenenner.domain.model.SourceDocumentCandidate`** +Record für einen PDF-Kandidaten aus dem Quellordner. Enthält keinen `Path`, sondern einen opaken `SourceDocumentLocator`, damit die Domain frei von NIO-Typen bleibt. + +**`de.gecheckt.pdf.umbenenner.domain.model.DocumentFingerprint`** +Record mit einem SHA-256-Hex-String (64 Zeichen) als stabiler Dokumentidentität; Grundlage für Idempotenz und Persistenz-Lookup. + +**`de.gecheckt.pdf.umbenenner.domain.model.DocumentProcessingOutcome`** +Sealed Interface mit sechs Implementierungen, die alle möglichen Ausgänge der Dokumentverarbeitung exhaustiv abbilden: + +| Implementierung | Bedeutung | +|-----------------|-----------| +| `PreCheckPassed` | Vorprüfung bestanden, KI-Pfad freigegeben | +| `PreCheckFailed` | Deterministischer Inhaltsfehler vor KI-Aufruf | +| `TechnicalDocumentError` | Technischer Fehler ohne erneuten KI-Aufruf | +| `NamingProposalReady` | KI-Antwort gültig, Vorschlag liegt vor | +| `AiTechnicalFailure` | Transienter technischer Fehler beim KI-Aufruf | +| `AiFunctionalFailure` | Deterministischer fachlicher Fehler der KI-Antwort | + +**`de.gecheckt.pdf.umbenenner.domain.model.ProcessingStatus`** +Enum mit acht Zuständen. Dokumentiert Zustandsübergänge und Retry-Schwellen; fachliches Herzstück der Persistenz-Semantik. + +| 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 | +| `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 | + +**`de.gecheckt.pdf.umbenenner.domain.model.NamingProposal`** +Record mit aufgelöstem Datum, `DateSource`, validiertem Titel und KI-Begründung. Führende Quelle für die Zieldateinamensbildung. + +**`de.gecheckt.pdf.umbenenner.domain.model.BatchRunContext`** +Klasse mit Run-ID, Zeitstempel und optionalem Fingerabdruck-Filter; steuert den Umfang eines Batch-Laufs. + +--- + +### Application-Modul + +**`de.gecheckt.pdf.umbenenner.application.config.RuntimeConfiguration`** +Schmales Laufzeit-Record (`maxPages`, `maxRetriesTransient`, `aiContentSensitivity`). Wird von den Use Cases verwendet, enthält keine Pfade. + +**`de.gecheckt.pdf.umbenenner.application.config.startup.StartConfiguration`** +Vollständige typisierte Startup-Konfiguration; einziger Ort in der Anwendungsschicht, an dem `java.nio.file.Path` vorkommt. Wird vom `ConfigurationPort` geliefert und von Bootstrap ausgewertet. + +**`de.gecheckt.pdf.umbenenner.application.service.DocumentProcessingService`** +Statische Hilfsklasse: überführt ein Extraktionsergebnis über den Pre-Check in ein `DocumentProcessingOutcome`. Kompakte Pipeline-Klasse; guter Einstieg zum Verständnis der Verarbeitungslogik. + +**`de.gecheckt.pdf.umbenenner.application.service.AiResponseParser`** +Statischer Parser für KI-Antworten in `ParsedAiResponse`. Erzwingt reines JSON-Objekt; Validierungslogik liegt vollständig in der Anwendungsschicht. + +**`de.gecheckt.pdf.umbenenner.application.port.out.ProcessingAttempt`** +Record für einen Versuchshistorie-Eintrag; enthält u. a. Provider-Identifikator, Modellname, Prompt-Identifikator, aufgelöstes Datum und finalen Zieldateinamen. + +**`de.gecheckt.pdf.umbenenner.application.port.out.DocumentRecord`** +Record für den Dokument-Stammsatz; enthält Gesamtstatus, Fehler- und Transientzähler sowie letzten Zielpfad. + +--- + +## 4. Inbound Ports + +### `BatchRunProcessingUseCase` + +``` +de.gecheckt.pdf.umbenenner.application.port.in.BatchRunProcessingUseCase +``` + +Zentraler Use-Case-Einstiegspunkt für den gesamten Batch-Betrieb. Beschreibt den Anwendungszweck in einer einzigen Methode: + +```java +BatchRunOutcome execute(BatchRunContext context); +``` + +Mögliche Ergebnisse: + +| Ergebnis | Bedeutung | +|----------|-----------| +| `SUCCESS` | Lauf technisch ordnungsgemäß abgeschlossen | +| `LOCK_UNAVAILABLE` | Run-Lock konnte nicht erworben werden | +| `FAILURE` | Harter technischer Fehler beim Laufstart | + +--- + +## 5. Outbound Ports + +Alle Outbound-Ports liegen in `de.gecheckt.pdf.umbenenner.application.port.out` (bzw. dessen Unterpaket `modelcatalog`). Implementierungen befinden sich ausschließlich in `pdf-umbenenner-adapter-out`; Details dort sind in `adapter-overview.md` beschrieben. + +| Interface | Zweck | Hauptmethode(n) | +|-----------|-------|-----------------| +| `SourceDocumentCandidatesPort` | Scannt Quellordner, liefert Kandidaten in deterministischer Reihenfolge | `List loadCandidates()` | +| `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()` | +| `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()` | +| `PersistenceSchemaInitializationPort` | Idempotente Schema-Initialisierung der SQLite-Datenbank | `initializeSchema()` | +| `ClockPort` | Abstraktion des Systemtakts | `Instant now()` | +| `ConfigurationPort` | Lädt die typisierte Startup-Konfiguration | `StartConfiguration loadConfiguration()` | +| `ProcessingLogger` | Logging-Delegation; sensibles KI-Content-Logging über Flag gesteuert | `info/debug/warn/error/debugSensitiveAiContent(...)` | +| `AiModelCatalogPort` | Abruf verfügbarer Modelle vom Provider (nur GUI-Pfad, siehe `gui-overview.md`) | `ModelCatalogResult fetchAvailableModels(...)` | +| `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(...)` | + +> **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. + +--- + +## 6. Einstiegspunkte für neue Entwickler + +Die folgende Lesereihenfolge gibt den kürzesten Weg zum Gesamtverständnis: + +1. **`de.gecheckt.pdf.umbenenner.application.port.in.BatchRunProcessingUseCase`** – beschreibt den gesamten Anwendungszweck in einer Methode. +2. **`de.gecheckt.pdf.umbenenner.domain.model.ProcessingStatus`** – fachliches Herzstück; dokumentiert Zustandsübergänge und Retry-Schwellen. +3. **`de.gecheckt.pdf.umbenenner.domain.model`** (gesamtes Paket) – gemeinsame Sprache aller Schichten; vollständig in wenigen Minuten lesbar. +4. **`de.gecheckt.pdf.umbenenner.application.service.DocumentProcessingService`** – kompakte Pipeline-Klasse; zeigt, wie Pre-Check und Ergebnis-Typen zusammenspielen. +5. **`de.gecheckt.pdf.umbenenner.application.port.out`** (gesamtes Paket) – vollständige Außengrenzen der Architektur; jeder Infrastrukturzugriff ist hier als Port definiert. diff --git a/docs/architecture/gui-overview.md b/docs/architecture/gui-overview.md new file mode 100644 index 0000000..c049101 --- /dev/null +++ b/docs/architecture/gui-overview.md @@ -0,0 +1,169 @@ +# Architektur-Übersicht: GUI (adapter-in-gui) + +Diese Datei beschreibt den Inbound-Adapter `pdf-umbenenner-adapter-in-gui` – die JavaFX-Desktop-GUI des PDF-Umbenenners. Sie ist zusammen mit `CLAUDE.md` im Projektroot als alleiniger Architekturkontext für GUI-Arbeit gedacht. Domain-Typen, Application-Ports und Outbound-Adapter (Dateisystem, SQLite, KI-HTTP) sind hier bewusst nicht beschrieben; dafür gelten `docs/architecture/domain-overview.md` und `docs/architecture/adapter-overview.md`. **Das JavaFX-Threading-Modell (Abschnitt 4) ist verbindlich und muss strikt eingehalten werden – GUI-Entwickler sollten diesen Abschnitt als erstes lesen.** + +--- + +## 1. Modulzweck + +`pdf-umbenenner-adapter-in-gui` ist der Inbound-Adapter für die Desktop-Oberfläche. Er: + +- empfängt den Startaufruf von der Bootstrap-Schicht über `GuiAdapter`, +- baut das JavaFX-Hauptfenster auf, +- delegiert alle fachlichen und technischen Operationen an Bootstrap-seitig verdrahtete Ports, +- zeigt Ergebnisse ausschließlich auf dem JavaFX Application Thread an. + +Das Modul enthält **keine fachliche Logik**, keinen Datenbankzugriff, keinen HTTP-Code und keine PDF-Verarbeitung. Es koordiniert lediglich Benutzereingaben, Worker-Threads und JavaFX-Controls. + +--- + +## 2. Paketstruktur + +``` +de.gecheckt.pdf.umbenenner.adapter.in.gui +│ +├── (root) Einstiegspunkt, Hauptfenster, Orchestrierung, GUI-interne +│ Ports, Hilfsklassen für Fenstertitel, System-Tray, +│ Dateiladen/-schreiben und Startkontext. +│ +├── 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. +│ +└── 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. +``` + +--- + +## 3. Schlüsselklassen + +### Root-Paket + +| Klasse (Kurzname) | Rolle | +|---|---| +| `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. | +| `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. | +| `GuiUnsavedChangesGuard` | Drei-Wege-Schutzdialog (Speichern / Verwerfen / Abbrechen) vor Neu, Öffnen und Schließen. Dialog-Supplier ist injizierbar für Tests ohne Scene. | +| `SystemTrayManager` | Verwaltet Windows-System-Tray-Icon. Überbrückt AWT-EDT nach JavaFX via `Platform.runLater` für Stage-Operationen. | + +### Paket `editor` + +| Klasse (Kurzname) | Rolle | +|---|---| +| `GuiConfigurationEditorState` | Record mit `loadedFileSnapshot`, `baselineValues`, `values`, `pendingMigrationMessage`. Dirty-State wird per Vergleich berechnet, kein Flag. | +| `GuiConfigurationValues` | Hält alle editierbaren Konfigurationsfelder als JavaFX-freie Plain-Java-Typen. | + +### Paket `batchrun` + +| Klasse (Kurzname) | Rolle | +|---|---| +| `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`. | +| `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. | + +--- + +## 4. Threading-Modell + +Das Modell ist verbindlich. Jede Verletzung dieser Regeln führt zu sporadischen `IllegalStateException`-Fehlern oder einer eingefrorenen Oberfläche. + +### 4.1 Worker-Threads + +Alle blockierenden Operationen laufen auf benannten Daemon-Threads außerhalb des JavaFX Application Thread. + +| Thread-Name | Koordinator-Klasse | Operationen | +|---|---|---| +| `gui-batch-run` | `GuiBatchRunCoordinator` | Batch-Launcher, Mini-Run-Launcher, Reset-Port, historischer Kontext | +| `gui-model-catalog` | `GuiModelCatalogCoordinator` | `modelCatalogPort.fetchAvailableModels(...)` | +| `gui-technical-test` | `GuiTechnicalTestCoordinator` | `orchestrator.runTests(...)` | +| Korrektur-Worker (anonym) | `GuiCorrectionDialogCoordinator` | `correctionExecutionService.execute(...)` | +| `pdf-preview-worker` | `PdfPreviewPane` | `PDDocument` laden, `PDFRenderer.renderImageWithDPI`, `PDDocument.close` | +| Dateisystem-Worker (inline) | `GuiConfigurationEditorWorkspace` | `configurationFileLoader.load(...)`, `configurationFileWriter.write(...)` | + +### 4.2 JavaFX Application Thread + +Alle Mutationen an JavaFX-Controls und alle Dialoganzeigen ausschließlich auf dem JavaFX Application Thread. Kein direktes Schreiben auf Controls vom Worker-Thread. + +### 4.3 Übergangsmechanismus Worker → FX + +Der Übergang erfolgt grundsätzlich via: + +```java +Platform.runLater(runnable); +``` + +Es werden **keine** `javafx.concurrent.Task` und kein `Service` verwendet. Die Koordinatoren steuern Threading manuell über zwei injizierbare Strategien: + +| Injektionspunkt | Typ | Produktion | Tests | +|---|---|---|---| +| `threadFactory` | `Function` | `Thread::new` (Daemon) | synchroner Direktaufruf | +| `fxDispatcher` | `Consumer` | `Platform::runLater` | synchroner Direktaufruf | + +Durch diese Injektion sind Unit-Tests vollständig ohne JavaFX-Runtime möglich. + +### 4.4 Stale-Request-Schutz + +`PdfPreviewPane` vergibt für jede Renderanfrage eine inkrementelle `AtomicLong`-Sequenznummer. Ein abgeschlossenes Render-Ergebnis wird nur dann auf der UI angezeigt, wenn seine Sequenznummer noch der aktuellen entspricht. Veraltete Ergebnisse werden still verworfen. + +--- + +## 5. GUI-interne Ports + +> **Abgrenzung:** Die folgenden Interfaces sind **keine hexagonalen Outbound-Ports der Application-Schicht**. Sie sind modul-interne Brücken, über die `GuiAdapter` die Bootstrap-seitig verdrahteten Implementierungen in die GUI-Klassen einschleust. Die eigentlichen Application-Ports (`AiInvocationPort`, `AiModelCatalogPort` usw.) und deren Outbound-Adapter-Implementierungen sind in `docs/architecture/domain-overview.md` und `docs/architecture/adapter-overview.md` beschrieben. + +### Root-Paket + +| Interface | Zweck | +|---|---| +| `GuiConfigurationFileLoader` | Lädt eine `.properties`-Datei und liefert einen `GuiConfigurationEditorState`. Abstrahiert Migration und Bootstrap-Verdrahtung vom GUI-Code. | +| `GuiConfigurationFileWriter` | Schreibt aktuelle `GuiConfigurationValues` als normalisierte `.properties` inkl. Backup-Schema. | + +### Paket `batchrun` + +| Interface | Zweck | +|---|---| +| `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. | +| `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. + +--- + +## 6. Einstiegspunkte für neue Entwickler + +Folgende Klassen und Dateien decken den schnellsten Einstieg ab: + +1. **`GuiAdapter`** – Architekturgrenze zur Bootstrap-Schicht in zwei Methoden. Zeigt, wie die GUI aus Bootstrap-Sicht aufgerufen wird. + +2. **`GuiStartupContext`** – Vollständige Liste aller Ports und Services, die Bootstrap in die GUI injiziert. Wer wissen will, was die GUI von außen bekommt, liest diesen Record. + +3. **`GuiConfigurationEditorWorkspace`** – Zentrale UI-Klasse: Tab-Aufbau, Sektionen, Editor-Zustand, Dirty-State, Datei-I/O, Sub-Koordinatoren. Einstieg für alle Arbeiten am Konfigurationseditor-Tab. + +4. **`GuiConfigurationEditorState` / `GuiConfigurationValues`** – View-Modell ohne JavaFX-Controls. Einstieg für alle Änderungen an editierbaren Konfigurationsfeldern und Dirty-State-Logik. + +5. **`GuiBatchRunCoordinator`** – Threading-Modell in seiner reinsten Form: Worker-Thread, `Platform.runLater`-Übergabe, Soft-Stop, Listener-Protokoll. Einstieg für alle Arbeiten am Verarbeitungslauf-Tab. + +6. **`batchrun/package-info.java`** – Kompakte Beschreibung des Threading-Kontrakts, der Abbruch-Semantik und der Konfigurationsquelle für dieses Paket. + +### Querverweise + +- Application-Ports und Domain-Typen (`NamingProposal`, `ProcessingStatus`, `DocumentFingerprint` usw.): `docs/architecture/domain-overview.md` +- Outbound-Adapter-Implementierungen (Dateisystem, SQLite, KI-HTTP, PDFBox) und Bootstrap-Verdrahtung: `docs/architecture/adapter-overview.md`