V1.1 Änderungen
This commit is contained in:
107
docs/betrieb.md
107
docs/betrieb.md
@@ -53,39 +53,98 @@ Vorlagen für lokale und Test-Konfigurationen befinden sich in:
|
||||
- `config/application-local.example.properties`
|
||||
- `config/application-test.example.properties`
|
||||
|
||||
### Pflichtparameter
|
||||
### Pflichtparameter (allgemein)
|
||||
|
||||
| Parameter | Beschreibung |
|
||||
|------------------------|--------------|
|
||||
| `source.folder` | Quellordner mit OCR-PDFs (muss vorhanden und lesbar sein) |
|
||||
| `target.folder` | Zielordner für umbenannte Kopien (wird angelegt, wenn nicht vorhanden) |
|
||||
| `sqlite.file` | SQLite-Datenbankdatei (übergeordnetes Verzeichnis muss existieren) |
|
||||
| `api.baseUrl` | Basis-URL des KI-Dienstes (z. B. `https://api.openai.com/v1`) |
|
||||
| `api.model` | Modellname (z. B. `gpt-4o-mini`) |
|
||||
| `api.timeoutSeconds` | HTTP-Timeout für KI-Anfragen in Sekunden (ganzzahlig, > 0) |
|
||||
| `max.retries.transient`| Maximale transiente Fehlversuche pro Dokument (ganzzahlig, >= 1) |
|
||||
| `max.pages` | Maximale Seitenzahl pro Dokument (ganzzahlig, > 0) |
|
||||
| `max.text.characters` | Maximale Zeichenanzahl des Dokumenttexts für KI-Anfragen (ganzzahlig, > 0) |
|
||||
| `prompt.template.file` | Pfad zur externen Prompt-Datei (muss vorhanden sein) |
|
||||
| Parameter | Beschreibung |
|
||||
|-------------------------|--------------|
|
||||
| `source.folder` | Quellordner mit OCR-PDFs (muss vorhanden und lesbar sein) |
|
||||
| `target.folder` | Zielordner für umbenannte Kopien (wird angelegt, wenn nicht vorhanden) |
|
||||
| `sqlite.file` | SQLite-Datenbankdatei (übergeordnetes Verzeichnis muss existieren) |
|
||||
| `ai.provider.active` | Aktiver KI-Provider: `openai-compatible` oder `claude` |
|
||||
| `max.retries.transient` | Maximale transiente Fehlversuche pro Dokument (ganzzahlig, >= 1) |
|
||||
| `max.pages` | Maximale Seitenzahl pro Dokument (ganzzahlig, > 0) |
|
||||
| `max.text.characters` | Maximale Zeichenanzahl des Dokumenttexts für KI-Anfragen (ganzzahlig, > 0) |
|
||||
| `prompt.template.file` | Pfad zur externen Prompt-Datei (muss vorhanden sein) |
|
||||
|
||||
### Provider-Parameter
|
||||
|
||||
Nur der **aktive** Provider muss vollständig konfiguriert sein. Der inaktive Provider wird nicht validiert.
|
||||
|
||||
**OpenAI-kompatibler Provider** (`ai.provider.active=openai-compatible`):
|
||||
|
||||
| Parameter | Beschreibung |
|
||||
|-----------|--------------|
|
||||
| `ai.provider.openai-compatible.baseUrl` | Basis-URL des KI-Dienstes (z. B. `https://api.openai.com/v1`) |
|
||||
| `ai.provider.openai-compatible.model` | Modellname (z. B. `gpt-4o-mini`) |
|
||||
| `ai.provider.openai-compatible.timeoutSeconds` | HTTP-Timeout in Sekunden (ganzzahlig, > 0) |
|
||||
| `ai.provider.openai-compatible.apiKey` | API-Schlüssel (Umgebungsvariable `OPENAI_COMPATIBLE_API_KEY` hat Vorrang) |
|
||||
|
||||
**Anthropic Claude-Provider** (`ai.provider.active=claude`):
|
||||
|
||||
| Parameter | Beschreibung |
|
||||
|-----------|--------------|
|
||||
| `ai.provider.claude.baseUrl` | Basis-URL (optional; Standard: `https://api.anthropic.com`) |
|
||||
| `ai.provider.claude.model` | Modellname (z. B. `claude-3-5-sonnet-20241022`) |
|
||||
| `ai.provider.claude.timeoutSeconds` | HTTP-Timeout in Sekunden (ganzzahlig, > 0) |
|
||||
| `ai.provider.claude.apiKey` | API-Schlüssel (Umgebungsvariable `ANTHROPIC_API_KEY` hat Vorrang) |
|
||||
|
||||
### Optionale Parameter
|
||||
|
||||
| Parameter | Beschreibung | Standard |
|
||||
|----------------------|--------------|---------|
|
||||
| `api.key` | API-Schlüssel (alternativ: Umgebungsvariable `PDF_UMBENENNER_API_KEY`) | – |
|
||||
| `runtime.lock.file` | Lock-Datei für Startschutz | `pdf-umbenenner.lock` im Arbeitsverzeichnis |
|
||||
| `log.directory` | Log-Verzeichnis | `./logs/` |
|
||||
| `log.level` | Log-Level (`DEBUG`, `INFO`, `WARN`, `ERROR`) | `INFO` |
|
||||
| `log.ai.sensitive` | KI-Rohantwort und Reasoning ins Log schreiben (`true`/`false`) | `false` |
|
||||
| Parameter | Beschreibung | Standard |
|
||||
|---------------------|--------------|---------|
|
||||
| `runtime.lock.file` | Lock-Datei für Startschutz | `pdf-umbenenner.lock` im Arbeitsverzeichnis |
|
||||
| `log.directory` | Log-Verzeichnis | `./logs/` |
|
||||
| `log.level` | Log-Level (`DEBUG`, `INFO`, `WARN`, `ERROR`) | `INFO` |
|
||||
| `log.ai.sensitive` | KI-Rohantwort und Reasoning ins Log schreiben (`true`/`false`) | `false` |
|
||||
|
||||
### API-Schlüssel
|
||||
|
||||
Der API-Schlüssel kann auf zwei Wegen gesetzt werden:
|
||||
Pro Provider-Familie existiert eine eigene Umgebungsvariable, die Vorrang vor dem Properties-Wert hat:
|
||||
|
||||
1. **Umgebungsvariable `PDF_UMBENENNER_API_KEY`** (empfohlen, hat Vorrang)
|
||||
2. Property `api.key` in `config/application.properties`
|
||||
| Provider | Umgebungsvariable |
|
||||
|---|---|
|
||||
| `openai-compatible` | `OPENAI_COMPATIBLE_API_KEY` |
|
||||
| `claude` | `ANTHROPIC_API_KEY` |
|
||||
|
||||
Die Umgebungsvariable hat immer Vorrang über die Properties-Datei.
|
||||
Schlüssel verschiedener Provider-Familien werden niemals vermischt.
|
||||
|
||||
---
|
||||
|
||||
## Migration älterer Konfigurationsdateien
|
||||
|
||||
Ältere Konfigurationsdateien, die noch die flachen Schlüssel `api.baseUrl`, `api.model`,
|
||||
`api.timeoutSeconds` und `api.key` verwenden, werden beim ersten Start **automatisch**
|
||||
in das aktuelle Schema überführt.
|
||||
|
||||
### Was passiert
|
||||
|
||||
1. Die Anwendung erkennt die veraltete Form anhand der flachen `api.*`-Schlüssel.
|
||||
2. **Vor jeder Änderung** wird eine Sicherungskopie der Originaldatei angelegt:
|
||||
- Standardfall: `config/application.properties.bak`
|
||||
- Falls `.bak` bereits existiert: `config/application.properties.bak.1`, `.bak.2`, …
|
||||
- Bestehende Sicherungen werden **niemals überschrieben**.
|
||||
3. Die Datei wird in-place in das neue Schema überführt:
|
||||
- `api.baseUrl` → `ai.provider.openai-compatible.baseUrl`
|
||||
- `api.model` → `ai.provider.openai-compatible.model`
|
||||
- `api.timeoutSeconds` → `ai.provider.openai-compatible.timeoutSeconds`
|
||||
- `api.key` → `ai.provider.openai-compatible.apiKey`
|
||||
- `ai.provider.active=openai-compatible` wird ergänzt.
|
||||
- Alle übrigen Schlüssel bleiben unverändert.
|
||||
4. Die migrierte Datei wird über eine temporäre Datei (`*.tmp`) und atomischen
|
||||
Move/Rename geschrieben. Das Original wird niemals teilbeschrieben.
|
||||
5. Die migrierte Datei wird sofort neu eingelesen und validiert.
|
||||
|
||||
### Bei Migrationsfehler
|
||||
|
||||
Schlägt die Validierung der migrierten Datei fehl, bricht die Anwendung mit Exit-Code `1` ab.
|
||||
Die Sicherungskopie (`.bak`) bleibt in diesem Fall erhalten und enthält die unveränderte
|
||||
Originaldatei. Die Konfiguration muss dann manuell korrigiert werden.
|
||||
|
||||
### Betreiber-Hinweis
|
||||
|
||||
Die Umgebungsvariable `PDF_UMBENENNER_API_KEY` des Vorgängerstands wird **nicht** automatisch
|
||||
umbenannt. Falls dieser Wert bislang verwendet wurde, muss er auf `OPENAI_COMPATIBLE_API_KEY`
|
||||
umgestellt werden.
|
||||
|
||||
---
|
||||
|
||||
|
||||
149
docs/workpackages/V1.1 - Abschlussnachweis.md
Normal file
149
docs/workpackages/V1.1 - Abschlussnachweis.md
Normal file
@@ -0,0 +1,149 @@
|
||||
# V1.1 – Abschlussnachweis
|
||||
|
||||
## Datum und betroffene Module
|
||||
|
||||
**Datum:** 2026-04-09
|
||||
|
||||
**Betroffene Module:**
|
||||
|
||||
| Modul | Art der Änderung |
|
||||
|---|---|
|
||||
| `pdf-umbenenner-application` | Neue Konfigurationstypen (`MultiProviderConfiguration`, `ProviderConfiguration`, `AiProviderFamily`) |
|
||||
| `pdf-umbenenner-adapter-out` | Neuer Anthropic-Adapter (`AnthropicClaudeHttpAdapter`), neuer Parser (`MultiProviderConfigurationParser`), neuer Validator (`MultiProviderConfigurationValidator`), Migrator (`LegacyConfigurationMigrator`), Schema-Migration (`ai_provider`-Spalte), aktualisierter OpenAI-Adapter (`OpenAiHttpAdapter`), aktualisierter Properties-Adapter (`PropertiesConfigurationPortAdapter`) |
|
||||
| `pdf-umbenenner-bootstrap` | Provider-Selektor (`AiProviderSelector`), aktualisierter `BootstrapRunner` (Migration, Provider-Auswahl, Logging) |
|
||||
| `pdf-umbenenner-adapter-in-cli` | Keine fachliche Änderung |
|
||||
| `pdf-umbenenner-domain` | Keine Änderung |
|
||||
| `config/` | Beispiel-Properties-Dateien auf neues Schema aktualisiert |
|
||||
| `docs/betrieb.md` | Abschnitte KI-Provider-Auswahl und Migration ergänzt |
|
||||
|
||||
---
|
||||
|
||||
## Pflicht-Testfälle je Arbeitspaket
|
||||
|
||||
### AP-001 – Konfigurations-Schema einführen
|
||||
|
||||
| Testfall | Klasse | Status |
|
||||
|---|---|---|
|
||||
| `parsesNewSchemaWithOpenAiCompatibleActive` | `MultiProviderConfigurationTest` | grün |
|
||||
| `parsesNewSchemaWithClaudeActive` | `MultiProviderConfigurationTest` | grün |
|
||||
| `claudeBaseUrlDefaultsWhenMissing` | `MultiProviderConfigurationTest` | grün |
|
||||
| `rejectsMissingActiveProvider` | `MultiProviderConfigurationTest` | grün |
|
||||
| `rejectsUnknownActiveProvider` | `MultiProviderConfigurationTest` | grün |
|
||||
| `rejectsMissingMandatoryFieldForActiveProvider` | `MultiProviderConfigurationTest` | grün |
|
||||
| `acceptsMissingMandatoryFieldForInactiveProvider` | `MultiProviderConfigurationTest` | grün |
|
||||
| `envVarOverridesPropertiesApiKeyForActiveProvider` | `MultiProviderConfigurationTest` | grün |
|
||||
| `envVarOnlyResolvesForActiveProvider` | `MultiProviderConfigurationTest` | grün |
|
||||
| Bestehende Tests bleiben grün | `PropertiesConfigurationPortAdapterTest`, `StartConfigurationValidatorTest` | grün |
|
||||
|
||||
### AP-002 – Legacy-Migration mit `.bak`
|
||||
|
||||
| Testfall | Klasse | Status |
|
||||
|---|---|---|
|
||||
| `migratesLegacyFileWithAllFlatKeys` | `LegacyConfigurationMigratorTest` | grün |
|
||||
| `createsBakBeforeOverwriting` | `LegacyConfigurationMigratorTest` | grün |
|
||||
| `bakSuffixIsIncrementedIfBakExists` | `LegacyConfigurationMigratorTest` | grün |
|
||||
| `noOpForAlreadyMigratedFile` | `LegacyConfigurationMigratorTest` | grün |
|
||||
| `reloadAfterMigrationSucceeds` | `LegacyConfigurationMigratorTest` | grün |
|
||||
| `migrationFailureKeepsBak` | `LegacyConfigurationMigratorTest` | grün |
|
||||
| `legacyDetectionRequiresAtLeastOneFlatKey` | `LegacyConfigurationMigratorTest` | grün |
|
||||
| `legacyValuesEndUpInOpenAiCompatibleNamespace` | `LegacyConfigurationMigratorTest` | grün |
|
||||
| `unrelatedKeysSurviveUnchanged` | `LegacyConfigurationMigratorTest` | grün |
|
||||
| `inPlaceWriteIsAtomic` | `LegacyConfigurationMigratorTest` | grün |
|
||||
|
||||
### AP-003 – Bootstrap-Provider-Auswahl und Umstellung des bestehenden OpenAI-Adapters
|
||||
|
||||
| Testfall | Klasse | Status |
|
||||
|---|---|---|
|
||||
| `bootstrapWiresOpenAiCompatibleAdapterWhenActive` | `AiProviderSelectorTest` | grün |
|
||||
| `bootstrapFailsHardWhenActiveProviderUnknown` | `AiProviderSelectorTest` | grün |
|
||||
| `bootstrapFailsHardWhenSelectedProviderHasNoImplementation` | `AiProviderSelectorTest` | grün |
|
||||
| `openAiAdapterReadsValuesFromNewNamespace` | `OpenAiHttpAdapterTest` | grün |
|
||||
| `openAiAdapterBehaviorIsUnchanged` | `OpenAiHttpAdapterTest` | grün |
|
||||
| `activeProviderIsLoggedAtRunStart` | `BootstrapRunnerTest` | grün |
|
||||
| `existingDocumentProcessingTestsRemainGreen` | `BatchRunEndToEndTest` | grün |
|
||||
| `legacyFileEndToEndStillRuns` | `BootstrapRunnerTest` | grün |
|
||||
|
||||
### AP-004 – Persistenz: Provider-Identifikator additiv
|
||||
|
||||
| Testfall | Klasse | Status |
|
||||
|---|---|---|
|
||||
| `addsProviderColumnOnFreshDb` | `SqliteAttemptProviderPersistenceTest` | grün |
|
||||
| `addsProviderColumnOnExistingDbWithoutColumn` | `SqliteAttemptProviderPersistenceTest` | grün |
|
||||
| `migrationIsIdempotent` | `SqliteAttemptProviderPersistenceTest` | grün |
|
||||
| `existingRowsKeepNullProvider` | `SqliteAttemptProviderPersistenceTest` | grün |
|
||||
| `newAttemptsWriteOpenAiCompatibleProvider` | `SqliteAttemptProviderPersistenceTest` | grün |
|
||||
| `newAttemptsWriteClaudeProvider` | `SqliteAttemptProviderPersistenceTest` | grün |
|
||||
| `repositoryReadsProviderColumn` | `SqliteAttemptProviderPersistenceTest` | grün |
|
||||
| `legacyDataReadingDoesNotFail` | `SqliteAttemptProviderPersistenceTest` | grün |
|
||||
| `existingHistoryTestsRemainGreen` | `SqliteAttemptProviderPersistenceTest` | grün |
|
||||
|
||||
### AP-005 – Nativer Anthropic-Adapter implementieren und verdrahten
|
||||
|
||||
| Testfall | Klasse | Status |
|
||||
|---|---|---|
|
||||
| `claudeAdapterBuildsCorrectRequest` | `AnthropicClaudeHttpAdapterTest` | grün |
|
||||
| `claudeAdapterUsesEnvVarApiKey` | `AnthropicClaudeHttpAdapterTest` | grün |
|
||||
| `claudeAdapterFallsBackToPropertiesApiKey` | `AnthropicClaudeHttpAdapterTest` | grün |
|
||||
| `claudeAdapterFailsValidationWhenBothKeysMissing` | `AnthropicClaudeHttpAdapterTest` | grün |
|
||||
| `claudeAdapterParsesSingleTextBlock` | `AnthropicClaudeHttpAdapterTest` | grün |
|
||||
| `claudeAdapterConcatenatesMultipleTextBlocks` | `AnthropicClaudeHttpAdapterTest` | grün |
|
||||
| `claudeAdapterIgnoresNonTextBlocks` | `AnthropicClaudeHttpAdapterTest` | grün |
|
||||
| `claudeAdapterFailsOnEmptyTextContent` | `AnthropicClaudeHttpAdapterTest` | grün |
|
||||
| `claudeAdapterMapsHttp401AsTechnical` | `AnthropicClaudeHttpAdapterTest` | grün |
|
||||
| `claudeAdapterMapsHttp429AsTechnical` | `AnthropicClaudeHttpAdapterTest` | grün |
|
||||
| `claudeAdapterMapsHttp500AsTechnical` | `AnthropicClaudeHttpAdapterTest` | grün |
|
||||
| `claudeAdapterMapsTimeoutAsTechnical` | `AnthropicClaudeHttpAdapterTest` | grün |
|
||||
| `claudeAdapterMapsUnparseableJsonAsTechnical` | `AnthropicClaudeHttpAdapterTest` | grün |
|
||||
| `bootstrapSelectsClaudeWhenActive` | `AiProviderSelectorTest` | grün |
|
||||
| `claudeProviderIdentifierLandsInAttemptHistory` | `AnthropicClaudeAdapterIntegrationTest` | grün |
|
||||
| `existingOpenAiPathRemainsGreen` | alle `OpenAiHttpAdapterTest`-Tests | grün |
|
||||
|
||||
### AP-006 – Regression, Smoke, Doku, Abschlussnachweis
|
||||
|
||||
| Testfall | Klasse | Status |
|
||||
|---|---|---|
|
||||
| `smokeBootstrapWithOpenAiCompatibleActive` | `BootstrapSmokeTest` | grün |
|
||||
| `smokeBootstrapWithClaudeActive` | `BootstrapSmokeTest` | grün |
|
||||
| `e2eMigrationFromLegacyDemoConfig` | `ProviderIdentifierE2ETest` | grün |
|
||||
| `regressionExistingOpenAiSuiteGreen` | `ProviderIdentifierE2ETest` | grün |
|
||||
| `e2eClaudeRunWritesProviderIdentifierToHistory` | `ProviderIdentifierE2ETest` | grün |
|
||||
| `e2eOpenAiRunWritesProviderIdentifierToHistory` | `ProviderIdentifierE2ETest` | grün |
|
||||
| `legacyDataFromBeforeV11RemainsReadable` | `ProviderIdentifierE2ETest` | grün |
|
||||
|
||||
---
|
||||
|
||||
## Belegte Eigenschaften
|
||||
|
||||
| Eigenschaft | Nachweis |
|
||||
|---|---|
|
||||
| Zwei Provider-Familien unterstützt | `AiProviderSelectorTest`, `BootstrapSmokeTest` |
|
||||
| Genau einer aktiv pro Lauf | `MultiProviderConfigurationTest`, `BootstrapSmokeTest` |
|
||||
| Kein automatischer Fallback | keine Fallback-Logik in `AiProviderSelector` oder Application-Schicht |
|
||||
| Fachlicher Vertrag (`NamingProposal`) unverändert | `AiResponseParser`, `AiNamingService` unverändert; beide Adapter liefern denselben Domain-Typ |
|
||||
| Persistenz rückwärtsverträglich | `SqliteAttemptProviderPersistenceTest`, `legacyDataFromBeforeV11RemainsReadable` |
|
||||
| Migration nachgewiesen | `LegacyConfigurationMigratorTest`, `e2eMigrationFromLegacyDemoConfig` |
|
||||
| `.bak`-Sicherung nachgewiesen | `LegacyConfigurationMigratorTest.createsBakBeforeOverwriting`, `e2eMigrationFromLegacyDemoConfig` |
|
||||
| Aktiver Provider wird geloggt | `BootstrapRunnerTest.activeProviderIsLoggedAtRunStart` |
|
||||
| Keine Architekturbrüche | kein `Application`- oder `Domain`-Code kennt OpenAI- oder Claude-spezifische Typen |
|
||||
| Keine neuen Bibliotheken | Anthropic-Adapter nutzt Java HTTP Client und `org.json` (beides bereits im Repo etabliert) |
|
||||
|
||||
---
|
||||
|
||||
## Betreiberaufgabe
|
||||
|
||||
Wer bisher die Umgebungsvariable `PDF_UMBENENNER_API_KEY` oder eine andere eigene Variable für den
|
||||
OpenAI-kompatiblen API-Schlüssel eingesetzt hat, muss diese auf **`OPENAI_COMPATIBLE_API_KEY`** umstellen.
|
||||
Die Anwendung akzeptiert nur diese kanonische Umgebungsvariable; ältere proprietäre Namen werden
|
||||
nicht automatisch ausgewertet.
|
||||
|
||||
---
|
||||
|
||||
## Build-Ergebnis
|
||||
|
||||
Build-Kommando:
|
||||
|
||||
```
|
||||
.\mvnw.cmd clean verify -pl pdf-umbenenner-domain,pdf-umbenenner-application,pdf-umbenenner-adapter-out,pdf-umbenenner-adapter-in-cli,pdf-umbenenner-bootstrap --also-make
|
||||
```
|
||||
|
||||
Build-Status: **ERFOLGREICH** — alle Tests grün, Mutationstests in allen Modulen ausgeführt.
|
||||
Reference in New Issue
Block a user