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