Doku: Modulare Architektur-Dokumentation (#34)
Drei neue Architektur-Übersichten unter docs/architecture/ angelegt (domain-overview, gui-overview, adapter-overview), die das bisher in CLAUDE.md verstreute Detailwissen zu Paketen, Schlüsselklassen, Ports und Bootstrap-Verdrahtung pro Modulbereich bündeln. CLAUDE.md verweist auf die drei Dateien und enthält das Detailwissen nicht mehr selbst, sodass Arbeit an einem Modulbereich mit CLAUDE.md plus der jeweils passenden Übersicht auskommt. Workpackage-Liste um M14 und M15 ergänzt; V2.9-Implementierungsstand auf Modul-/Verhaltensebene konsolidiert. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -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.
|
||||
|
||||
|
||||
@@ -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 <Pfad>` 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`*
|
||||
@@ -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<SourceDocumentCandidate> 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.
|
||||
@@ -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<Runnable, Thread>` | `Thread::new` (Daemon) | synchroner Direktaufruf |
|
||||
| `fxDispatcher` | `Consumer<Runnable>` | `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`
|
||||
Reference in New Issue
Block a user