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
+178
View File
@@ -0,0 +1,178 @@
---
type: Data Model
title: Datenmodelle & Konfiguration
description: Alle Pydantic-Modelle von DocuMentor AppSettings, Project, ProjectData, TreeNode/XslFile/XmlFile, Tool-Konfigurationen, Hash-System und PostgreSQL-Integration.
tags: [datenmodelle, pydantic, konfiguration, hash, postgresql]
---
# Datenmodelle & Konfiguration
Alle Modelle sind in `src/conf.py` definiert und verwenden Pydantic für Typsicherheit und Validierung.
## Globale Konfiguration: AppSettings
`AppSettings` ist ein `BaseSettings`-Singleton (`app_settings`), das als JSON gespeichert wird. Der Pfad ist plattformabhängig (siehe [Schnellstart](quickstart.md)).
### Tool-Konfigurationen
Jedes Tool-Modell hat eine `id` (int) und eine `version` bzw. `name`:
| Modell | Felder | Zweck |
|--------|--------|------|
| `JavaVm` | `id`, `version`, `path_to_binary_file` | Pfad zur Java-Executable |
| `SaxonJar` | `id`, `version`, `path_to_jar_file`, `output_file_extension` ("fo") | Pfad zur Saxon-JAR |
| `ApacheFop` | `id`, `version`, `path_to_dir`, `output_file_extension` ("pdf") | FOP-Installationsverzeichnis |
| `DiffPdf` | `id`, `version`, `path_to_binary_file`, `default_params`, `output_file_extension` ("pdf") | diff-pdf-Binary + Standardparameter |
| `XslDir` | `id`, `name`, `path_to_root_dir` | Wurzelverzeichnis der XSL-Dateien |
| `PostgreSqlDb` | `id`, `name`, `host`, `port` (5432), `database`, `username`, `password`, `ssl_mode`, `timeout` (10) | Datenbankverbindung |
### AppSettings-Listen
```python
java_vms: list[JavaVm] = []
diff_pdfs: list[DiffPdf] = []
saxon_jars: list[SaxonJar] = []
apache_fops: list[ApacheFop] = []
xsl_dirs: list[XslDir] = []
pdf_projects: list[Project] = []
postgresql_dbs: list[PostgreSqlDb] = []
```
### Worker-Pool-Einstellungen
| Feld | Standard | Beschreibung |
|------|----------|-------------|
| `max_workers` | 8 | Anzahl paralleler Worker pro Pool |
| `use_saxon_worker_pool` | True | Saxon-Pool aktivieren (benötigt JDK) |
| `saxon_xslt_version` | `XSLT_2_0_3_0` | XSLT-Version: `1.0` (JAXP) oder `2.0/3.0` (s9api) |
| `use_fop_worker_pool` | True | FOP-Pool aktivieren (benötigt JDK) |
### UI-Zustand
| Feld | Typ | Beschreibung |
|------|-----|-------------|
| `theme` | `str \| None` | Qt-Theme-Name |
| `window_geometry` | `tuple[int,int,int,int] \| None` | (x, y, width, height) |
| `splitter_sizes` | `list[int] \| None` | Splitter-Positionen |
| `tree_column_widths` | `list[int] \| None` | TreeWidget-Spaltenbreiten |
| `graph_layout_settings` | `GraphLayoutSettings` | vis.js Layout-Parameter |
### Speichern
`app_settings.save()` serialisiert das gesamte Modell als JSON (`model_dump_json(indent=4)`) an den plattformspezifischen Konfigurationspfad.
## Projekt-Modell: Project
`Project` referenziert Tool-Konfigurationen über IDs:
```python
class Project(BaseModel):
id: int
name: str
project_dir: Path
java_vm_id: int # → app_settings.java_vms
diff_pdf_id: int # → app_settings.diff_pdfs
saxon_jar_id: int # → app_settings.saxon_jars
apache_fop_id: int # → app_settings.apache_fops
xsl_dir_id: int # → app_settings.xsl_dirs
postgre_sql_db_id: int # → app_settings.postgresql_dbs
fop_config_dir: Path | None
xslt_params: dict[str, str] # Projektweite XSLT-Parameter
```
Hilfsmethoden (`getXsl()`, `getJavaVm()`, `getSaxon()`, `getApacheFop()`, `getDiffPdf()`, `getPostgreSqlDb()`) lösen IDs in Anzeigewerte auf.
## Projektdaten: ProjectData
`ProjectData` wird pro Projekt in `project.yaml` gespeichert:
```python
class ProjectData(BaseModel):
nodes: list[TreeNode] = []
expanded_nodes: list[tuple] | None = None
```
Die Methode `writeSettings(project_dir)` serialisiert das Modell als YAML in `{project_dir}/project.yaml`.
## Baumstruktur: TreeNode → XslFile → XmlFile
```
TreeNode
├── children: list[TreeNode | XslFile]
├── id: tuple # Eindeutige ID als Tuple
├── bez: str # Bezeichnung
└── xslt_params: dict[str, str] # Knotenspezifische XSLT-Parameter
XslFile
├── id: tuple
├── bez: str
├── xsl_file: Path # Pfad zur XSL-Datei (absolut)
├── xslt_params: dict[str, str]
└── xmls: list[XmlFile]
XmlFile
├── xml: Path # Pfad zur XML-Datei (relativ zu project_dir)
└── hashsum: str | None # blake2b-Hash oder None
```
Die `id` als Tuple ermöglicht hierarchische Adressierung z.B. `(1, 2, 3)` für den dritten XSL-Knoten unter dem zweiten TreeNode unter dem ersten Root-Knoten.
### XSLT-Parameter-Vererbung
XSLT-Parameter werden hierarchisch vererbt: Projektweite Parameter (`Project.xslt_params`) werden von Knoten-Parametern (`TreeNode.xslt_params`) überschrieben, die wiederum von XSL-Datei-Parametern (`XslFile.xslt_params`) überschrieben werden. Die Methode `_collect_parent_params()` im `TreeManagerMixin` sammelt alle Parameter entlang des Pfades.
## Hash-System (blake2b)
### Berechnung
`calculate_blake2b_hash()` in `src/utils.py`:
- Verwendet `hashlib.blake2b()`
- Format: `blake2b:<64-Zeichen-Hexdigest>`
- Wird beim Projekt-Laden für alle XML-Dateien ohne existierenden Hash berechnet
- Asynchron via `XmlHashCalculatorThread` (`src/ui/threads.py`)
### Duplikatserkennung
Beim Zuordnen von XML-Dateien zu XSL-Knoten (Drag-and-Drop oder Dialog):
1. Hash der neuen Datei berechnen
2. Existierender Hash in `XmlFile.hashsum` wird verglichen
3. Bei Übereinstimmung wird die Datei als Duplikat erkannt und nicht erneut zugewiesen
4. Hashes werden in `project.yaml` persistiert
Details: `docs/blake2b_hash_implementation.md` und `docs/xml_hash_duplicate_detection.md`
## PostgreSQL-Integration
### Verbindungsaufbau
`PostgreSqlDb` unterstützt SSL-Modi:
| Enum-Wert | Bedeutung |
|-----------|-----------|
| `DISABLE` | Kein SSL |
| `ALLOW` | SSL optional |
| `PREFER` | SSL bevorzugt (Standard) |
| `REQUIRE` | SSL erforderlich |
| `VERIFY_CA` | SSL mit CA-Zertifikat-Verifikation |
| `VERIFY_FULL` | SSL mit vollständiger Verifikation |
### Abfrage-Ausführung
`DatabaseQueryThread` (`src/ui/mixins/database.py`):
- Verwendet `polars.read_database_uri()` mit `engine="connectorx"`
- Connection-String wird aus `PostgreSqlDb`-Feldern gebaut
- Ergebnis wird als Polars DataFrame sortiert nach `reporttyp_bez`, `report_bez`, `repfile_bez`
### Obsolete-Erkennung
Nach dem DB-Import vergleicht `obsolete_detector.py` die geladenen XslFile-IDs mit den Projekt-Einträgen. Veraltete Einträge (im Projekt, aber nicht mehr in der DB) werden im `ObsoleteEntriesDialog` angezeigt und können entfernt werden.
## Enums
| Enum | Werte | Verwendung |
|------|-------|------------|
| `XsltVersion` | `XSLT_1_0`, `XSLT_2_0_3_0` | Auswahl der Saxon-API (JAXP vs s9api) |
| `SSLMode` | `DISABLE` bis `VERIFY_FULL` | PostgreSQL-SSL-Modus |
| `GraphLayout` | `BARNES_HUT`, `FORCE_ATLAS2`, `REPULSION`, `HIERARCHICAL` | vis.js Layout-Modus |
| `HierarchicalDirection` | `UD`, `DU`, `LR`, `RL` | Hierarchisches Layout: Richtung |
| `HierarchicalSortMethod` | `HUBSIZE`, `DIRECTED` | Hierarchisches Layout: Sortierung |