CLAUDE.md Dokumentation hinzugefügt und Konfigurationspfad-Handling verbessert

- CLAUDE.md mit umfassender Projektdokumentation für Claude Code hinzugefügt
- Beschreibt Architektur, Datenmodelle, UI-Muster und Entwicklungsworkflows
- Konfigurationspfad-Verarbeitung in src/conf.py robuster gemacht:
  - os.path durch pathlib.Path ersetzt
  - Validierung für Schreibrechte und Verzeichnisexistenz hinzugefügt
  - Besseres Error-Handling mit sys.exit(1) bei fehlenden Berechtigungen

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-10-11 13:00:32 +02:00
parent 5c91836d87
commit 2e86a4befb
2 changed files with 174 additions and 6 deletions
+163
View File
@@ -0,0 +1,163 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Projektübersicht
DocuMentor (ehemals xsl-validator) ist eine PySide6-basierte Desktop-Anwendung zur Verwaltung und Validierung von XSL-Transformationen mit XML-Dateien. Sie bietet eine GUI zur Konfiguration von Transformations-Toolchains (Saxon, Apache FOP, diff-pdf) und zur Verwaltung von PDF-Generierungsprojekten mit PostgreSQL-Datenbankintegration.
## Entwicklungskommandos
### Paketverwaltung
Dieses Projekt verwendet den `uv` Paketmanager (nicht pip oder poetry):
```bash
uv sync # Abhängigkeiten installieren
uv run python src/main.py # Anwendung starten
uv run python test_hash_implementation.py # Hash-Tests ausführen
```
### Linting
```bash
uv run ruff check # Code-Style prüfen (Zeilenlänge: 120)
uv run ruff format # Code formatieren
```
## Architektur
### Konfigurationssystem (src/conf.py)
Die Anwendung verwendet ein zentralisiertes Konfigurationsmodell mit Pydantic:
- **AppSettings**: Globales Singleton (`app_settings`), das die gesamte Anwendungskonfiguration speichert
- Wird an plattformspezifischen Orten gespeichert:
- Linux: `~/.config/DocuMentor/config.json`
- Windows: `%APPDATA%\DocuMentor\config.json`
- macOS: `~/Library/Application Support/DocuMentor/config.json`
- Enthält Listen von Tools: `java_vms`, `saxon_jars`, `apache_fops`, `diff_pdfs`, `xsl_dirs`, `postgresql_dbs`
- **ProjectData**: Projektspezifische Einstellungen, die in `project.yaml` im jeweiligen Projektverzeichnis gespeichert werden
- Enthält hierarchische Baumstruktur von Transformationsknoten
- Verwendet `TreeNode` und `XslFile` zur Organisation
- Jede `XmlFile` hat eine optionale `hashsum` (blake2b) zur Änderungsverfolgung
### Wichtige Datenmodelle
1. **Tool-Konfigurationsmodelle** (JavaVm, SaxonJar, ApacheFop, DiffPdf, XslDir, PostgreSqlDb):
- Jedes hat eine `id` und `version`
- Speichert Pfade zu Binärdateien/Verzeichnissen
2. **Project-Modell**:
- Referenziert Tool-Konfigurationen über ID
- Verlinkt zu einem Projektverzeichnis mit `project.yaml`
- Hat Hilfsmethoden wie `getXsl()`, `getJavaVm()` um IDs in Namen/Versionen aufzulösen
3. **Baumstruktur** (TreeNode → XslFile → XmlFile):
- Hierarchische Organisation von Transformations-Workflows
- `TreeNode`: Organisationseinheit mit `xslt_params` und Kindknoten/-dateien
- `XslFile`: XSL-Stylesheet mit zugehörigen XML-Dateien und XSLT-Parametern
- `XmlFile`: XML-Eingabedatei mit optionalem blake2b-Hash
### UI-Architektur (src/ui/)
Die Anwendung folgt einem spezifischen PySide6-Muster:
1. **UI-Definitionsdateien** (`*_ui.py`): Automatisch generiert aus UI-Designer-Dateien
- Diese Dateien definieren die UI-Struktur als Klassen (z.B. `Ui_MainWindow`)
- Sollten NICHT manuell bearbeitet werden
2. **Implementierungsdateien** (ohne `_ui` Suffix): Tatsächliche Dialog-/Fenster-Implementierungen
- Importieren und verwenden die entsprechende `*_ui.py` Datei
- Enthalten Business-Logik und Signal/Slot-Verbindungen
- Beispiel: `MainWindow.py` verwendet `Ui_MainWindow` aus `MainWinddow_ui.py`
Beim Erstellen neuer Dialoge:
- Immer zuerst eine entsprechende UI-Datei erstellen
- Die UI-Datei wird automatisch als `.py`-Datei von einer VS Code Extension generiert
- Die generierte UI-Klasse in der Implementierungsdatei importieren und verwenden
### Hauptfenster (src/ui/MainWindow.py)
Zentrale Schaltstelle der Anwendung mit mehreren wichtigen Verantwortlichkeiten:
1. **Projektverwaltung**:
- Öffnet und verwaltet PDF-Transformationsprojekte
- Lädt/speichert `ProjectData` aus `project.yaml` Dateien
2. **Tree Widget**: Zeigt hierarchische Struktur von Transformationsknoten an
- Kontextmenüs zum Hinzufügen/Bearbeiten/Löschen von Knoten, XSL-Dateien und XML-Dateien
- Drag-and-Drop-Unterstützung für XML-Dateien
3. **PDF-Vergleichsansicht**:
- Drei-Panel-Ansicht (Referenz, Diff, Neu)
- Alpha-Blending für visuellen Vergleich
- Zoom- und Pan-Funktionalität
4. **Asynchrone Operationen**:
- `XmlHashCalculatorThread`: Hintergrund-blake2b-Hash-Berechnung für XML-Dateien
- `DatabaseTestThread` (in PostgreSqlConfigDialog): Asynchrones Testen von Datenbankverbindungen
### Hash-Berechnungssystem
Die Anwendung verwendet blake2b-Hashing zur Verfolgung von XML-Dateiänderungen:
- **Automatisch**: Hashes werden berechnet, wenn Projekte geladen werden (nur für Dateien ohne existierenden Hash)
- **Asynchron**: Hintergrund-Thread (`XmlHashCalculatorThread`) um die UI reaktionsfähig zu halten
- **Format**: `blake2b:<64-Zeichen-Hexdigest>`
- **Speicherung**: Persistiert in `project.yaml` innerhalb jedes `XmlFile`-Objekts
- **Details**: Siehe `docs/blake2b_hash_implementation.md`
### Theme-System
Die Anwendung unterstützt mehrere Qt-Themes:
- Theme-Auswahlmenü wird dynamisch aus `QStyleFactory.keys()` befüllt
- Theme-Präferenz wird in `AppSettings.theme` gespeichert
- Dark-Theme-Unterstützung via `qdarktheme` Paket (aktuell in main.py auskommentiert)
### Datenbankintegration
PostgreSQL-Integration mit Polars und ConnectorX:
- Konfiguration wird im `PostgreSqlDb`-Modell mit SSL-Modus-Unterstützung gespeichert
- SQL-Abfragen werden via `_execute_sql_query()` im MainWindow ausgeführt
- Ergebnisse werden in Polars DataFrames geladen
## Wichtige Konventionen
### Deutsche Sprache
Die Codebasis verwendet Deutsch für:
- UI-Texte und Labels
- Kommentare und Dokumentation
- Variablennamen wo kontextuell passend
- Log-Meldungen
### Pfadbehandlung
- Immer `pathlib.Path`-Objekte verwenden, keine Strings
- `expanduser()` und `expandvars()` für Benutzer-/Umgebungspfade verwenden
- Projektrelative Pfade werden als relativ gespeichert, zur Laufzeit gegen `project_dir` aufgelöst
### ID-basierte Lookups
Konfigurationsentitäten (Tools, Datenbanken) werden in Projekten über ID referenziert. Die Hilfsmethoden des `Project`-Modells (`getXsl()`, `getJavaVm()`, etc.) verwenden, um IDs in Anzeigewerte aufzulösen.
### Einstellungspersistenz
- Globale Einstellungen: `app_settings.save()` nach Änderungen aufrufen
- Projekteinstellungen: `project_data.writeSettings(project_dir)` nach Änderungen aufrufen
## Arbeiten mit der Codebasis
### Neue Tool-Konfigurationen hinzufügen
1. Modell zu `conf.py` hinzufügen (ähnlich wie `JavaVm`, `SaxonJar`)
2. Listenfeld zu `AppSettings` hinzufügen
3. Konfigurationsdialog in `src/ui/` erstellen (UI-Datei + Implementierung)
4. Zu `AppSettings.py` Tabs hinzufügen
5. `Project`-Modell aktualisieren, falls das Tool projektspezifisch sein soll
### Neue Baumoperationen hinzufügen
1. Aktion zum Kontextmenü in `_create_context_menu_for_type()` hinzufügen
2. Handler-Methode implementieren nach Namensschema `_action_tree_node()`, `_action_xsl_file()`, etc.
3. Baum nach Änderungen mit `_load_nodes_to_tree()` aktualisieren
4. `self.project_data.writeSettings(self.project.project_dir)` aufrufen um Änderungen zu persistieren
### Projektstruktur modifizieren
Das `ProjectData`-Modell ist die Quelle der Wahrheit. Alle Änderungen an der Baumstruktur müssen:
1. Die `project_data.nodes` Liste modifizieren
2. `project_data.writeSettings()` aufrufen um zu persistieren
3. Baum mit `_load_nodes_to_tree()` neu laden um Änderungen in der UI zu reflektieren
+11 -6
View File
@@ -1,4 +1,5 @@
from os import path import os
import sys
from pathlib import Path from pathlib import Path
from sys import platform from sys import platform
from typing import Tuple, Type from typing import Tuple, Type
@@ -18,15 +19,15 @@ app_name = "DocuMentor"
if platform == "win32": if platform == "win32":
config_path = f"%APPDATA%\\{app_name}\\config.json" tmp_config_path = f"%APPDATA%\\{app_name}\\config.json"
elif platform in ("linux", "linux2"): elif platform in ("linux", "linux2"):
config_path = f"~/.config/{app_name}/config.json" tmp_config_path = f"~/.config/{app_name}/config.json"
elif platform == "darwin": elif platform == "darwin":
config_path = f"~/Library/Application Support/{app_name}/͏͏͏͏config.json" tmp_config_path = f"~/Library/Application Support/{app_name}/͏͏͏͏config.json"
else: else:
config_path = f"~/.config/{app_name}/config.json" tmp_config_path = f"~/.config/{app_name}/config.json"
config_path = Path(path.expandvars(config_path)).expanduser() config_path = Path(os.path.expandvars(tmp_config_path)).expanduser()
class JavaVm(BaseModel): class JavaVm(BaseModel):
@@ -158,6 +159,10 @@ class AppSettings(BaseSettings):
# Ordner existert nicht # Ordner existert nicht
if not config_path.parent.exists(): if not config_path.parent.exists():
config_path.parent.mkdir(parents=True, exist_ok=True) config_path.parent.mkdir(parents=True, exist_ok=True)
if not config_path.parent.is_dir() or not os.access(config_path.parent, os.W_OK):
logger.exception(f"{config_path.parent} ist kein Verzeichnis oder es gibt keine Schreibrechte")
sys.exit(1)
# Konfiguration speichern # Konfiguration speichern
with open(config_path, "wb") as c: with open(config_path, "wb") as c: