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>
16 KiB
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– implementiertAiInvocationPortfür OpenAI-kompatible Endpunkte. POST{baseUrl}/v1/chat/completions, Bearer-Authentifizierung, extrahiertchoices[0].message.content, klassifiziert HTTP-Fehler und Timeouts alsAiInvocationTechnicalFailure. -
...ai.AnthropicClaudeHttpAdapter– implementiertAiInvocationPortfür die native Anthropic Messages API. POST/v1/messages, Headerx-api-keyundanthropic-version, konkatenierttext-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–AiModelCatalogPortfür Claude, GET/v1/modelsmitx-api-key. -
...modelcatalog.OpenAiCompatibleModelCatalogAdapter–AiModelCatalogPortfür OpenAI-kompatibel, GET/v1/modelsmit Bearer.
PDF-Extraktion
...pdfextraction.PdfTextExtractionPortAdapter– PDFBox-3.x-Adapter. Alle technischen Fehler werden alsPdfExtractionTechnicalErrorzurückgegeben; es werden keine Exceptions propagiert.
SQLite
-
...sqlite.SqliteSchemaInitializationAdapter– legt Tabellendocument_recordundprocessing_attemptan. Schema-Evolution erfolgt perALTER TABLE ADD COLUMN; bestehende Datenbestände bleiben rückwärtskompatibel. -
...sqlite.SqliteUnitOfWorkAdapter– implementiertUnitOfWorkPort. SetztautoCommit=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– implementiertConfigurationPort. Lädtconfig/application.properties(oder einen--config-Override), parst viaMultiProviderConfigurationParser, löst API-Keys aus Umgebungsvariablen (OPENAI_COMPATIBLE_API_KEY,ANTHROPIC_API_KEY). -
...configuration.LegacyConfigurationMigrator– erkennt alte Flat-Key-Konfigurationen (Schlüssel wieapi.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. WirftRunLockUnavailableException, wenn die Datei bereits vorhanden ist. Release löscht die Datei (best-effort). -
...clock.SystemClockAdapter– delegiert anInstant.now(). -
...fingerprint.Sha256FingerprintAdapter– SHA-256 über den Rohdatei-Inhalt. Fehler alsFingerprintTechnicalError.
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 geladeneStartConfigurationauf 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 einenBatchRunContextentgegen, delegiert anBatchRunProcessingUseCase.execute()und gibtBatchRunOutcomezurü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 viaCliArgumentParser, bricht bei ungültiger Verwendung mit Exit-Code 1 ab, delegiert anBootstrapRunner.run()und ruft abschließendSystem.exit()mit dem zurückgegebenen Code auf. -
...bootstrap.BootstrapRunner– Herzstück der Verdrahtung. Baut den Objektgraph für Headless- und GUI-Pfad, dispatcht überStartupMode, enthältbuildProductionBatchUseCase()undrunHeadlessBatch()als zentrale Kompositionsmethoden, liefert den Exit-Code zurück. -
...bootstrap.AiProviderSelector– einzige Stelle, an derAiProviderFamilyauf eine konkreteAiInvocationPort-Implementierung abgebildet wird:OPENAI_COMPATIBLE→OpenAiHttpAdapter,CLAUDE→AnthropicClaudeHttpAdapter. -
...bootstrap.startup.CliArgumentParser– parst--headlessund--config <Pfad>zu einem typsicherenStartupArgumentsParseResult(sealed:Valid/Invalid). -
...bootstrap.singleinstance.SingleInstanceGuard– bindet einen Loopback-ServerSocket auf Port 47832. WirftAnotherInstanceRunningException, wenn der Port bereits belegt ist. Ein Shutdown-Hook gibt den Socket frei. -
...bootstrap.adapter.AiModelCatalogDispatcher– Bootstrap-interner Dispatcher für die GUI. RoutetAiModelCatalogPort-Aufrufe anhand desproviderIdentifieran den Claude- oder OpenAI-kompatiblen Modell-Katalog-Adapter. Thread-safe. -
...bootstrap.adapter.Log4jProcessingLogger– implementiertProcessingLoggerauf Basis von Log4j2. Unterdrückt sensitive KI-Inhalte, wennAiContentSensitivity.PROTECT_SENSITIVE_CONTENTgesetzt ist. -
...bootstrap.adapter.GuiConfigurationPropertiesWriter– schreibt die im GUI-Editor bearbeitete Konfiguration als normalisierteapplication.propertieszurü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()wertetstartupArguments.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-FormPropertiesConfigurationPortAdapterlädt und parst die PropertiesStartConfigurationValidatorvalidiert die geladeneStartConfiguration- 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 inDefaultBatchRunProcessingUseCaseeingebettet
CLI-Adapter
BootstrapRunnererzeugtSchedulerBatchCommandmit dem fertigenBatchRunProcessingUseCase
Exit-Code-Ableitung
BatchRunOutcome→ 0 (Lauf technisch erfolgreich) oder 1 (harter Bootstrap-/Konfigurationsfehler)PdfUmbenennerApplicationruftSystem.exit(exitCode)auf
GUI-Pfad
startGuiMode()baut viabuildGuiStartupContext()einenGuiStartupContext: enthältAiModelCatalogDispatcher,EnvironmentApiKeyResolutionAdapter,TechnicalTestOrchestrator,GuiConfigurationPropertiesWriterGuiAdapter.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.mdbeschrieben
5. Einstiegspunkte je Modul
pdf-umbenenner-adapter-out
-
...ai.OpenAiHttpAdapter– zeigt das typische Adapter-Muster: Port-Interface implementieren, alle provider-spezifischen Details kapseln,ProviderConfigurationals einzige Konfigurationsquelle konsumieren. DanachAnthropicClaudeHttpAdapterzum Vergleich lesen. -
...sqlite.SqliteSchemaInitializationAdapter– erklärt das Datenbankschema, das alle SQLite-Adapter voraussetzen. Hier sieht man, welche Felder indocument_recordundprocessing_attemptexistieren und wie Schema-Evolution additiv umgesetzt ist. -
...configuration.PropertiesConfigurationPortAdapter– Einstieg in die Konfigurationskette. Von hier ausMultiProviderConfigurationParserundLegacyConfigurationMigratornachverfolgen.
pdf-umbenenner-adapter-in-cli
-
...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. -
package-info.java– beschreibt Abhängigkeitsrichtung und Verdrahtungsvertrag dieses Adapters. -
SchedulerBatchCommandTest– zeigt, wie der Adapter ohne Bootstrap testbar ist.
pdf-umbenenner-bootstrap
-
PdfUmbenennerApplication– Startpunkt; die kurze Kette vonmain()bisSystem.exit()gibt einen ersten Überblick über die gesamte Startsequenz. -
BootstrapRunner– Herzstück;buildProductionBatchUseCase()zeigt, wie der vollständige Objektgraph manuell aufgebaut wird.runHeadlessBatch()zeigt den Headless-Kontrollfluss. -
AiProviderSelector– kleinste Klasse mit größter Hebelwirkung: hier liegt die einzige Stelle, an der die Provider-Auswahl aus der Konfiguration auf eine konkreteAiInvocationPort-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