---
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.
