M12 vollständig abgeschlossen (AP-001 bis AP-008)

- AP-001: Prüf- und Korrektur-Kernobjekte (CheckpointId, CheckpointResult
  sealed interface, TechnicalTestReport mit Correction-Plan-Ableitung,
  CorrectionSuggestion sealed interface, PathCheckPort, ResourceCreationPort)
- AP-002: Aktion "Validieren" als explizite, nicht schreibende Gesamtprüfung
  des aktuellen Editorzustands
- AP-003: Provider-nahe technische Prüflogik für Endpoint, API-Key,
  Modellliste und Modellplausibilität — wiederverwendet den bestehenden
  Modellabruf-Port, kein zweiter HTTP-Pfad
- AP-004: Windows-Pfadprüfung mit ausdrücklicher Unterstützung gemappter
  Laufwerksbuchstaben (FilesystemPathCheckAdapter)
- AP-005: Aktion "Technische Tests ausführen" als vollständiger Gesamttest
  ohne Frühabbruch, Orchestrator sammelt Befunde aller Prüfblöcke
- AP-006: Schreibende Korrekturhilfen mit gesammeltem Bestätigungsdialog,
  CorrectionExecutionService, FilesystemResourceCreationAdapter
- AP-007: Automatische deutsche Standard-Prompt-Datei-Erzeugung,
  Default-Pfad neben der .properties-Datei, klare Fehlermeldung bei
  nicht beschreibbarem Zielpfad
- AP-008: Regressionstests für Gesamttest ohne Frühabbruch, ungespeicherte
  Editorzustände, Korrekturdialog, Prompt-Erzeugung, Windows-Pfade

Hexagonale Architektur durchgehend eingehalten, Domain und Application
bleiben infrastrukturfrei. Threadingmodell konsequent umgesetzt.
Naming-Regel und JavaDoc-Standard eingehalten.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-04-20 21:57:06 +02:00
parent aa067a3165
commit 1bb7a42735
53 changed files with 7410 additions and 47 deletions
@@ -21,6 +21,9 @@ import de.gecheckt.pdf.umbenenner.adapter.in.gui.GuiConfigurationFileWriter;
import de.gecheckt.pdf.umbenenner.adapter.in.gui.GuiConfigurationLoadException;
import de.gecheckt.pdf.umbenenner.adapter.in.gui.GuiStartupContext;
import de.gecheckt.pdf.umbenenner.bootstrap.adapter.AiModelCatalogDispatcher;
import de.gecheckt.pdf.umbenenner.application.validation.editor.EditorConfigurationValidator;
import de.gecheckt.pdf.umbenenner.application.validation.technicaltest.ProviderTechnicalTestService;
import de.gecheckt.pdf.umbenenner.application.validation.technicaltest.TechnicalTestOrchestrator;
import de.gecheckt.pdf.umbenenner.bootstrap.adapter.GuiConfigurationPropertiesWriter;
import de.gecheckt.pdf.umbenenner.adapter.out.modelcatalog.ClaudeModelCatalogAdapter;
import de.gecheckt.pdf.umbenenner.adapter.out.modelcatalog.OpenAiCompatibleModelCatalogAdapter;
@@ -47,6 +50,7 @@ import de.gecheckt.pdf.umbenenner.adapter.out.sqlite.SqliteDocumentRecordReposit
import de.gecheckt.pdf.umbenenner.adapter.out.sqlite.SqliteProcessingAttemptRepositoryAdapter;
import de.gecheckt.pdf.umbenenner.adapter.out.sqlite.SqliteSchemaInitializationAdapter;
import de.gecheckt.pdf.umbenenner.adapter.out.sqlite.SqliteUnitOfWorkAdapter;
import de.gecheckt.pdf.umbenenner.adapter.out.pathcheck.FilesystemPathCheckAdapter;
import de.gecheckt.pdf.umbenenner.adapter.out.targetcopy.FilesystemTargetFileCopyAdapter;
import de.gecheckt.pdf.umbenenner.adapter.out.targetfolder.FilesystemTargetFolderAdapter;
import de.gecheckt.pdf.umbenenner.application.config.RuntimeConfiguration;
@@ -623,6 +627,17 @@ public class BootstrapRunner {
AiModelCatalogPort modelCatalogPort = buildModelCatalogDispatcher();
de.gecheckt.pdf.umbenenner.application.validation.editor.ApiKeyResolutionPort apiKeyResolutionPort =
new de.gecheckt.pdf.umbenenner.adapter.out.validation.EnvironmentApiKeyResolutionAdapter();
ProviderTechnicalTestService providerTechnicalTestService =
new ProviderTechnicalTestService(modelCatalogPort, apiKeyResolutionPort);
de.gecheckt.pdf.umbenenner.application.validation.technicaltest.PathCheckPort pathCheckPort =
new FilesystemPathCheckAdapter();
TechnicalTestOrchestrator technicalTestOrchestrator = new TechnicalTestOrchestrator(
new EditorConfigurationValidator(),
pathCheckPort,
providerTechnicalTestService);
de.gecheckt.pdf.umbenenner.application.validation.technicaltest.CorrectionExecutionService correctionExecutionService =
new de.gecheckt.pdf.umbenenner.application.validation.technicaltest.CorrectionExecutionService(
new de.gecheckt.pdf.umbenenner.adapter.out.resourcecreation.FilesystemResourceCreationAdapter());
if (configPathOverride.isEmpty()) {
return new GuiStartupContext(
@@ -631,7 +646,11 @@ public class BootstrapRunner {
loader,
writer,
modelCatalogPort,
apiKeyResolutionPort);
apiKeyResolutionPort,
providerTechnicalTestService,
pathCheckPort,
technicalTestOrchestrator,
correctionExecutionService);
}
Path configPath = Paths.get(configPathOverride.get());
@@ -645,14 +664,19 @@ public class BootstrapRunner {
loader,
writer,
modelCatalogPort,
apiKeyResolutionPort);
apiKeyResolutionPort,
providerTechnicalTestService,
pathCheckPort,
technicalTestOrchestrator,
correctionExecutionService);
}
LOG.info("GUI startup: configuration file confirmed at: {}", configPath.toAbsolutePath());
try {
GuiConfigurationEditorState loadedState = loadGuiConfigurationState(configPath);
return new GuiStartupContext(loadedState, Optional.empty(), loader, writer,
modelCatalogPort, apiKeyResolutionPort);
modelCatalogPort, apiKeyResolutionPort, providerTechnicalTestService, pathCheckPort,
technicalTestOrchestrator, correctionExecutionService);
} catch (GuiConfigurationLoadException e) {
LOG.error("GUI startup: configuration could not be loaded, starting without it: {}",
e.getMessage(), e);
@@ -662,7 +686,11 @@ public class BootstrapRunner {
loader,
writer,
modelCatalogPort,
apiKeyResolutionPort);
apiKeyResolutionPort,
providerTechnicalTestService,
pathCheckPort,
technicalTestOrchestrator,
correctionExecutionService);
}
}