133 lines
7.4 KiB
Markdown
133 lines
7.4 KiB
Markdown
<!-- status: done -->
|
||
<!-- started: 2026-04-09 -->
|
||
<!-- component: gateway -->
|
||
|
||
# Gateway: Doppelte Klassennamen bereinigen
|
||
|
||
## Beschreibung und Kontext
|
||
|
||
Beim Aufräumen der `@i18nModel`-Migration (Phase 2) wurde festgestellt, dass mehrere Python-Klassen im Gateway **denselben Namen** tragen, obwohl sie in verschiedenen Modulen leben. Das ist problematisch, weil:
|
||
|
||
1. **i18n-Kollision:** `@i18nModel` registriert nach `cls.__name__` in einem globalen Dict — bei gleichem Namen überschreibt der letzte Import den ersten.
|
||
2. **Lesbarkeit:** Import-Aliase (`from ... import TaskResult as WorkflowTaskResult`) sind fragil und leicht vergessen.
|
||
3. **Tooling:** IDE-Suche, Debugging-Stacktraces und `getModelClasses()` liefern mehrdeutige Treffer.
|
||
|
||
**Business-Treiber:** Saubere Klassennamen verhindern stille Label-Fehler in der UI und reduzieren Wartungsaufwand bei zukünftigen Erweiterungen.
|
||
|
||
---
|
||
|
||
## Vollständige Liste der Duplikate
|
||
|
||
Ermittelt per AST-Scan über `gateway/modules/` (nur Klassen, die in **mehr als einer Datei** vorkommen):
|
||
|
||
### Kritisch: Pydantic-Modelle mit `@i18nModel` (i18n-Dict-Kollision)
|
||
|
||
| Klassenname | Datei 1 | Datei 2 | Beschreibung |
|
||
|-------------|---------|---------|--------------|
|
||
| **`TaskResult`** | `datamodels/datamodelChat.py` | `datamodels/datamodelWorkflow.py` | Chat: Aufgabenergebnis mit Status/Feedback. Workflow: Minimales Ergebnis mit `actionResult`. Beide haben `@i18nModel("Aufgaben-Ergebnis")`. |
|
||
| **`RequestContext`** | `datamodels/datamodelWorkflow.py` (Pydantic `BaseModel`) | `auth/authentication.py` (plain `class`) | Workflow: Normalisierter Benutzer-Input. Auth: Request-Kontext mit User/Mandate/Rollen. Kein i18n-Konflikt (Auth-Klasse ist kein Pydantic-Modell), aber Name ist irreführend. |
|
||
|
||
### Mittel: Lokale Hilfsklassen (kein i18n, aber verwirrend)
|
||
|
||
| Klassenname | Datei 1 | Datei 2 | Beschreibung |
|
||
|-------------|---------|---------|--------------|
|
||
| **`AiResponse`** | `datamodels/datamodelWorkflow.py` (Pydantic) | `serviceAi/subStructureFilling.py` (inline `class` in try/except, 4×) | Workflow: Vollständiges AI-Antwort-Modell. StructureFiller: Minimaler Wrapper `AiResponse(content)` als Fallback bei Parse-Fehlern. |
|
||
| **`TableData`** | `datamodels/datamodelDocument.py` (Pydantic) | `neutralization/.../subProcessList.py` (`@dataclass`) | Document: Strukturierte Tabelle mit Headers/Rows/Caption. Neutralization: Einfache Tabelle mit `source_type`. |
|
||
| **`Token`** | `datamodels/datamodelSecurity.py` (Pydantic `PowerOnModel`) | `shared/jsonContinuation.py` (`@dataclass`) | Security: DB-Token (JWT, Refresh etc.). JsonContinuation: JSON-Parser-Token (internes Parsing). |
|
||
|
||
### Niedrig: Architektur-Helfer (domänengetrennt, kaum Verwechslungsgefahr)
|
||
|
||
| Klassenname | Dateien | Beschreibung |
|
||
|-------------|---------|--------------|
|
||
| `ChatObjects` | `features/chatbot/interfaceFeatureChatbot.py`, `interfaces/interfaceDbChat.py` | Identische Rolle (Chat-Objekt-Container), ggf. zusammenführbar. |
|
||
| `ConnectionHelper` | `workflows/methods/methodOutlook/helpers/connection.py`, `workflows/methods/methodSharepoint/helpers/connection.py` | Jeweils Outlook- bzw. SharePoint-spezifisch; Name ist generisch, aber Module sind klar getrennt. |
|
||
| `DocumentParsingHelper` | `workflows/methods/methodJira/helpers/documentParsing.py`, `workflows/methods/methodSharepoint/helpers/documentParsing.py` | Jira- bzw. SharePoint-spezifisch; gleiche Situation wie `ConnectionHelper`. |
|
||
| `StructureGenerator` | `serviceAi/subStructureGeneration.py`, `serviceGeneration/subStructureGenerator.py` | Zwei Services mit ähnlicher Aufgabe; ggf. Konsolidierung prüfen. |
|
||
| `_ResolverDbAdapter` | `features/graphicalEditor/routeFeatureGraphicalEditor.py`, `features/workspace/routeFeatureWorkspace.py` | Interner Adapter (`_`-Prefix); lebt nur im jeweiligen Route-Modul. |
|
||
| `_ServicesAdapter` | 4× in `serviceCenter/services/*/main*.py` | Interner Adapter pro Service; bewusst gleichnamig, nie cross-importiert. |
|
||
|
||
---
|
||
|
||
## Lösungsvorschlag
|
||
|
||
### 1. `TaskResult` → Umbenennung (Priorität: hoch)
|
||
|
||
**Problem:** Beide Klassen haben `@i18nModel("Aufgaben-Ergebnis")` — der letzte Import gewinnt im Label-Dict.
|
||
|
||
**Lösung:**
|
||
|
||
| Aktuell | Neu | Modul |
|
||
|---------|-----|-------|
|
||
| `TaskResult` in `datamodelChat.py` | **`ChatTaskResult`** | Chat-Domäne: Status, Feedback, Error |
|
||
| `TaskResult` in `datamodelWorkflow.py` | **`WorkflowTaskResult`** | Workflow-Domäne: taskId + actionResult |
|
||
|
||
**Betroffene Imports (5 Dateien):**
|
||
|
||
- `workflows/processing/modes/modeBase.py` — importiert aus `datamodelChat`
|
||
- `workflows/processing/modes/modeDynamic.py` — importiert aus `datamodelChat`
|
||
- `workflows/processing/modes/modeAutomation.py` — importiert aus `datamodelChat` + `datamodelWorkflow` (bereits `as WorkflowTaskResult`)
|
||
- `workflows/workflowManager.py` — importiert aus `datamodelWorkflow` (bereits `as WorkflowTaskResult`)
|
||
- `workflows/processing/workflowProcessor.py` — importiert aus `datamodelWorkflow`
|
||
- `tests/unit/datamodels/test_workflow_models.py` — importiert aus `datamodelWorkflow`
|
||
|
||
**i18n-Labels anpassen:**
|
||
|
||
- `ChatTaskResult`: `@i18nModel("Chat-Aufgabenergebnis")`
|
||
- `WorkflowTaskResult`: `@i18nModel("Workflow-Aufgabenergebnis")`
|
||
|
||
**Aufwand:** Klein (6 Dateien, reine Umbenennung + Import-Anpassung).
|
||
|
||
### 2. `AiResponse` in `subStructureFilling.py` → Inline-Klasse eliminieren (Priorität: mittel)
|
||
|
||
**Problem:** 4× identische `class AiResponse` inline in try/except-Blöcken als Fallback-Wrapper.
|
||
|
||
**Lösung:** Eine private Klasse `_AiResponseFallback` am Modulanfang definieren, die 4 Inline-Definitionen ersetzen.
|
||
|
||
```python
|
||
@dataclass
|
||
class _AiResponseFallback:
|
||
content: Any
|
||
```
|
||
|
||
**Aufwand:** Klein (1 Datei, 4 Stellen).
|
||
|
||
### 3. `TableData` in `subProcessList.py` → Umbenennen (Priorität: mittel)
|
||
|
||
**Lösung:** `TableData` in `subProcessList.py` → **`NeutralizationTableData`** (oder `_ParsedTableData`). Wird nur modulintern verwendet.
|
||
|
||
**Aufwand:** Minimal (1 Datei).
|
||
|
||
### 4. `Token` in `jsonContinuation.py` → Umbenennen (Priorität: niedrig)
|
||
|
||
**Lösung:** `Token` → **`JsonToken`** (passend zu `TokenType` → `JsonTokenType`). Wird nur modulintern verwendet.
|
||
|
||
**Aufwand:** Minimal (1 Datei, rein intern).
|
||
|
||
### 5. `RequestContext` — Kein Handlungsbedarf
|
||
|
||
Die Auth-`RequestContext` ist kein Pydantic-Modell und hat kein `@i18nModel`. Die Workflow-`RequestContext` ist ein Pydantic-Modell mit `@i18nModel`. Es gibt **keine Import-Überschneidung** (Auth wird nie aus `datamodelWorkflow` importiert und umgekehrt). Kein Refactoring nötig.
|
||
|
||
### 6. Niedrige Kategorie — Kein Handlungsbedarf
|
||
|
||
`ChatObjects`, `ConnectionHelper`, `DocumentParsingHelper`, `StructureGenerator`, `_ResolverDbAdapter`, `_ServicesAdapter` leben in klar getrennten Domänen und werden nie cross-importiert. Umbenennung wäre kosmetisch.
|
||
|
||
---
|
||
|
||
## Umsetzungsreihenfolge
|
||
|
||
| Schritt | Was | Dateien | Aufwand |
|
||
|---------|-----|---------|---------|
|
||
| 1 | `TaskResult` → `ChatTaskResult` / `WorkflowTaskResult` | 8 | 30 min |
|
||
| 2 | Inline `AiResponse` → `_AiResponseFallback` | 1 | 10 min |
|
||
| 3 | `TableData` → `NeutralizationTableData` | 1 | 5 min |
|
||
| 4 | `Token` → `JsonToken` | 1 | 5 min |
|
||
|
||
**Gesamtaufwand:** ~50 min, kein Risiko für Laufzeitverhalten (reine Umbenennungen).
|
||
|
||
---
|
||
|
||
## Validierung
|
||
|
||
- `python -c "import app"` muss fehlerfrei durchlaufen
|
||
- Bestehende Tests (`tests/unit/datamodels/test_workflow_models.py`) anpassen und grün halten
|
||
- `getModelAttributeDefinitions` für betroffene Modelle prüfen (Labels eindeutig)
|