Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
15 KiB
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.port.out.history |
Outbound-Port für lesende Historien-Abfragen aus dem Historien-Tab; bewusst getrennt von den bestehenden Repositories, um diese nicht mit GUI-spezifischen Methoden aufzublähen |
de.gecheckt.pdf.umbenenner.application.service |
Anwendungsnahe, zustandslose Dienste: KI-Antwort-Parsing, Pre-Check-Auswertung, Verarbeitungs-Pipeline, Retry-Entscheidung |
de.gecheckt.pdf.umbenenner.application.config |
Konfigurationsmodelle der Anwendungsschicht (RuntimeConfiguration, Provider-Konfiguration) |
de.gecheckt.pdf.umbenenner.application.config.startup |
Vollständiges Startup-Konfigurationsmodell (StartConfiguration) |
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.
de.gecheckt.pdf.umbenenner.application.port.out.history.HistoryQuery
Record mit den Abfrageparametern für den Historien-Tab: optionaler Suchbegriff (searchText, Teilstring, case-insensitiv), optionaler Status-Filter (statusFilter als Enum-Name) und Limit der zurückzugebenden Zeilen (Standard DEFAULT_LIMIT = 501). Das Limit 501 ermöglicht der aufrufenden Schicht zu erkennen, ob mehr als 500 Treffer vorhanden sind.
de.gecheckt.pdf.umbenenner.application.port.out.history.DocumentHistoryRow
Einzelzeile der Dokumentenliste im Historien-Tab. Felder: fingerprint, overallStatus, sourceFileName, targetFileName (null wenn noch kein Erfolg), sourcePath, updatedAt und attemptCount. Stammt aus document_record mit einem COUNT-Ausdruck über processing_attempt.
de.gecheckt.pdf.umbenenner.application.port.out.PromptSaveResult
Versiegeltes Ergebnis-Interface für PromptPort.savePrompt(String). Zulässige Ausprägungen: Saved (Erfolg, enthält absoluten Pfad), WriteFailed (I/O-Fehler beim Schreiben der Temp-Datei), TargetDirectoryMissing (Zielordner fehlt), AtomicMoveFailed (atomares Verschieben nicht möglich; kein stiller Fallback).
Neue Use-Case-Implementierungen im Paket de.gecheckt.pdf.umbenenner.application.usecase
| Klasse | Zweck |
|---|---|
DefaultHistoryOverviewUseCase |
Lädt die gefilterte Dokumentenübersicht über HistoryQueryPort.loadOverview; gibt HistoryOverviewResult mit Liste und hasMore-Flag zurück |
DefaultHistoryDetailsUseCase |
Lädt Stammsatz und alle Verarbeitungsversuche für einen Fingerprint über HistoryQueryPort; gibt HistoryDetailsResult zurück |
DefaultHistoryResetDocumentStatusUseCase |
Feldgenauer Status-Reset via UnitOfWorkPort.TransactionOperations.resetDocumentStatusForRetry; setzt overall_status, content_error_count, transient_error_count und last_failure_instant zurück; lässt die Versuchshistorie unangetastet |
DefaultDeleteDocumentHistoryUseCase |
Löscht Stammsatz und alle Verarbeitungsversuche vollständig und transaktional via UnitOfWorkPort |
DefaultPromptEditorUseCase |
Delegiert Laden, Speichern und Standard-Anlegen der Prompt-Datei an PromptPort und ResourceCreationPort; wird im GUI-Pfad über GuiPromptEditorPort angesteuert |
4. Inbound Ports
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:
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; speichert geänderten Inhalt atomar via savePrompt(String) – der Pfad stammt aus der Adapter-internen Konfiguration, nicht aus dem Port-Aufruf |
PromptLoadingResult loadPrompt(), PromptSaveResult savePrompt(String content) |
TargetFileCopyPort |
Kopiert Quelldokument unter aufgelöstem Namen in den Zielordner (Temp + Rename) | TargetFileCopyResult copyToTarget(...) |
TargetFileRenamePort |
Atomare Umbenennung einer bereits kopierten Zieldatei (manuelle Korrektur) | TargetFileRenameResult rename(...) |
RunLockPort |
Exklusiver Lauf-Lock gegen parallele Instanzen | acquire() / release() |
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(...) |
HistoryQueryPort |
Lesender Zugriff auf die Verarbeitungshistorie für den Historien-Tab; bewusst getrennt von den regulären Repositories | List<DocumentHistoryRow> loadOverview(HistoryQuery), Optional<DocumentRecord> findRecordByFingerprint(DocumentFingerprint), List<ProcessingAttempt> findAttemptsByFingerprint(DocumentFingerprint) |
Hinweis zu GUI-spezifischen Ports:
AiModelCatalogPort,PathCheckPort,ResourceCreationPort,ApiKeyResolutionPortundHistoryQueryPortwerden ausschließlich im GUI-Pfad genutzt. Ihre Implementierungen und der Aufrufkontext sind ingui-overview.mdbzw.adapter-overview.mdbeschrieben.
Hinweis zu
UnitOfWorkPort.TransactionOperations: Die innere SchnittstelleTransactionOperationswurde um die MethoderesetDocumentStatusForRetry(DocumentFingerprint)erweitert. Diese setzt feldgenauoverall_status → READY_FOR_AI,content_error_count → 0,transient_error_count → 0undlast_failure_instant → NULL, ohne die Versuchshistorie zu berühren. Die Implementierung liegt inSqliteUnitOfWorkAdapter.
6. Einstiegspunkte für neue Entwickler
Die folgende Lesereihenfolge gibt den kürzesten Weg zum Gesamtverständnis:
de.gecheckt.pdf.umbenenner.application.port.in.BatchRunProcessingUseCase– beschreibt den gesamten Anwendungszweck in einer Methode.de.gecheckt.pdf.umbenenner.domain.model.ProcessingStatus– fachliches Herzstück; dokumentiert Zustandsübergänge und Retry-Schwellen.de.gecheckt.pdf.umbenenner.domain.model(gesamtes Paket) – gemeinsame Sprache aller Schichten; vollständig in wenigen Minuten lesbar.de.gecheckt.pdf.umbenenner.application.service.DocumentProcessingService– kompakte Pipeline-Klasse; zeigt, wie Pre-Check und Ergebnis-Typen zusammenspielen.de.gecheckt.pdf.umbenenner.application.port.out(gesamtes Paket) – vollständige Außengrenzen der Architektur; jeder Infrastrukturzugriff ist hier als Port definiert.