chore: OpenWiki-Dokumentation einrichten, AGENTS.md ergänzen

Fügt OpenWiki-Setup (Workflow, Seiten, CLAUDE.md-Verweis) und AGENTS.md
hinzu, damit wiederkehrende Code-Dokumentation automatisch gepflegt wird.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-23 14:22:57 +02:00
parent 881d890e81
commit 4733ea6b82
12 changed files with 1426 additions and 685 deletions
+113
View File
@@ -0,0 +1,113 @@
---
type: Architecture Overview
title: Architektur-Überblick
description: PySide6-Mixin-Architektur, UI-Pattern (generierte UI vs. Implementierung), Thread-Modell und Konfigurationssystem von DocuMentor.
tags: [architektur, pyside6, mixins, threads, konfiguration]
---
# Architektur-Überblick
## Technologie-Stack
| Schicht | Technologie | Zweck |
|---------|------------|------|
| GUI | PySide6 (Qt 6) | Native Desktop-Oberfläche |
| Konfiguration | Pydantic + pydantic-settings | Typsichere Datenmodelle, JSON/YAML-Persistenz |
| Datenverarbeitung | Polars + ConnectorX | PostgreSQL-Abfragen, DataFrames |
| XSL-Parsing | lxml | XSL-Abhängigkeitsgraph |
| Hashing | hashlib (blake2b) | Duplikatserkennung |
| Build | PyInstaller + WiX/Inno Setup | Windows-Distribution |
| Paketverwaltung | uv | Dependency-Management |
## Einstiegspunkt
Die Anwendung startet in `src/main.py`:
1. Logging konfigurieren (Datei + Konsole, 24h Auto-Cleanup)
2. `QApplication` erstellen, App-Icon setzen
3. `MainWindow` instanziieren und anzeigen
4. Bei fehlender Tool-Konfiguration `AppSettingsDlg` modal öffnen
5. Qt-Event-Loop starten
## MainWindow Mixin-Architektur
`MainWindow` (`src/ui/MainWindow.py`) ist die zentrale Klasse und erbt von mehreren Mixins, um Funktionalität zu trennen:
```
MainWindow
├── IconRefreshMixin (src/icons.py) Theme-Wechsel → Icons neu einfärben
├── QMainWindow (PySide6) Qt-Basisfenster
├── TreeManagerMixin (mixins/tree_manager.py) Baum-Widget, Kontextmenüs, Node-Operationen
├── PdfViewerMixin (mixins/pdf_viewer.py) PDF-Rendering, Alpha-Blending, Zoom
├── WorkerPoolMixin (mixins/worker_pool.py) Saxon/FOP Worker-Pool Lebenszyklus
├── DatabaseMixin (mixins/database.py) PostgreSQL-Abfragen, Obsolete-Erkennung
├── DragDropMixin (mixins/drag_drop.py) Drag-and-Drop für XML-Dateien
├── HashCalculationMixin (mixins/hash_calculation.py) blake2b-Hash-Berechnung, Duplikatserkennung
└── TransformationMixin (mixins/transformation.py) XSL-Transformations-Ausführung
```
Jedes Mixin erwartet bestimmte Attribute (`self.ui`, `self.project`, `self.pdf_project`) und Methoden von anderen Mixins. Die Mixins sind in `src/ui/mixins/__init__.py` gebündelt.
### Mixin-Abhängigkeiten
`TransformationMixin` benötigt Methoden aus `WorkerPoolMixin` (`_initialize_saxon_worker_pool`, `_shutdown_saxon_worker_pool`) und `TreeManagerMixin` (`_collect_parent_params`, `_create_centered_progress_bar`). `HashCalculationMixin` und `DragDropMixin` benötigen `_save_project_settings()` und `_load_nodes_to_tree()` von MainWindow.
## UI-Pattern: Generierte UI vs. Implementierung
DocuMentor folgt einem strikten PySide6-Pattern:
1. **UI-Definitionsdateien** (`*_ui.py`, z.B. `MainWinddow_ui.py`): Aus `.ui`-Dateien von einer VS Code Extension generiert. Enthalten nur Widget-Layout-Definitionen als Klasse (`Ui_MainWindow`). **Nicht manuell bearbeiten.**
2. **Implementierungsdateien** (ohne `_ui`-Suffix, z.B. `MainWindow.py`): Importieren die UI-Klasse, instanziieren sie als `self.ui` und fügen Business-Logik hinzu.
```python
class JavaVmConfigDialog(QDialog):
def __init__(self, parent=None):
super().__init__(parent)
self.ui = Ui_JavaVmConfigDialog()
self.ui.setupUi(self)
# Signale NACH setupUi() verbinden
self.ui.browseButton.clicked.connect(self._browse_file)
```
**Regeln:**
- UI-Klassen niemals direkt erben, nur als `self.ui`-Member verwenden
- Alle Widgets über `self.ui.widgetName` zugreifen
- Signal-Verbindungen immer nach `setupUi()`
## Thread-Modell
Asynchrone Operationen verwenden `QThread`-Subklassen aus `src/ui/threads.py`:
| Thread-Klasse | Zweck | Signale |
|---------------|------|---------|
| `XmlHashCalculatorThread` | blake2b-Hash-Berechnung für XML-Dateien | `hash_calculated`, `calculation_finished`, `error_occurred` |
| `XmlBatchProcessingThread` | Batch-Verarbeitung: Hash + Duplikatserkennung + Dateikopieren | `progress_update`, `file_processed`, `processing_finished` |
| `TransformationThread` | Ausführung der XSL-Transformations-Pipeline | Fortschritts- und Abschluss-Signale |
| `DatabaseQueryThread` | Asynchrone PostgreSQL-Abfragen (in `mixins/database.py`) | `query_completed` (DataFrame), `query_failed` |
**Wichtig:** Threads immer mit `.start()` starten, nie `.run()` direkt aufrufen.
## Konfigurationssystem
Die Konfiguration ist in [Datenmodelle & Konfiguration](../data-models.md) detailliert beschrieben. Zusammenfassung:
- **`AppSettings`** (`src/conf.py`): Globales Singleton (`app_settings`), gespeichert als JSON. Enthält Tool-Listen, UI-Zustand, Worker-Pool-Einstellungen.
- **`ProjectData`** (`src/conf.py`): Projektspezifisch, gespeichert als `project.yaml` im Projektverzeichnis. Enthält die Baumstruktur (`TreeNode → XslFile → XmlFile`).
## Icon-System
Icons werden über `src/icons.py` verwaltet:
- Feather Icons aus dem Qt-Ressource-System (`:/icons/<name>.svg`)
- Einmaliges Rendern bei 64px, Qt skaliert für 16/24/32px
- Theme-reactiv: Färbung nach `QPalette.WindowText`, Cache-Schlüssel enthält Theme-Farbe
- `IconRefreshMixin` erlaubt Theme-Wechsel zur Laufzeit ohne manuellen Cache-Reset
## XSL-Abhängigkeitsgraph
`src/xsl_dependencies.py` (`XslDependencyGraph`) parst XSL-Dateien mit lxml und baut einen Abhängigkeitsgraph für `<xsl:import/>` und `<xsl:include/>`. Der Graph wird über Datei-mtime automatisch invalidiert. Visualisiert wird er im Dialog `src/ui/XslDependencyDialog.py` via vis.js.
Der Abhängigkeitsgraph ist auch für die [Transformations-Pipeline](../workflows/transformation-pipeline.md) relevant: wenn eine importierte XSL-Datei neuer ist als das Output-PDF, gilt die Transformation als veraltet.
## Obsolete-Erkennung
`src/obsolete_detector.py` enthält reine Analyselogik (ohne Qt-Abhängigkeit) zum Finden veralteter `XslFile`-Einträge nach Datenbank-Import. Wird vom `DatabaseMixin` nach dem DB-Laden aufgerufen und im `ObsoleteEntriesDialog` (`src/ui/ObsoleteEntriesDialog.py`) angezeigt.