From e1299a1a63ba001c6e28b1bd5d4cabb7bcc51005 Mon Sep 17 00:00:00 2001 From: Gulum Date: Mon, 22 Jun 2026 17:44:18 +0200 Subject: [PATCH] =?UTF-8?q?docs:=20CLAUDE.md=20mit=20Architektur,=20Import?= =?UTF-8?q?-Workflow,=20Konventionen=20&=20Dom=C3=A4nenwissen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Leitfaden für künftige Arbeit: Projekt-/Architektur-Überblick, Start über Aspire (Ports/Dashboard/persistentes Volume), 3-stufiger Import→DB-Workflow (Ingest wischt+lädt, Feedback überlebt), Build/Test je Schicht, Konventionen (de.ts, Migrationen, Provenance-JSON, FK-freie Survivor-Spalten), Domänenwissen (Lebensspanne/Geschwisterverpaarung/Genotyp/Chart-Layout), Stolperfallen (Aspire-Container vs. Volume, Migrations-Historie-Mismatch, psql-Quoting) und eine Feature-Landkarte. Co-Authored-By: Claude Opus 4.8 --- CLAUDE.md | 158 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..0199d3d --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,158 @@ +# CLAUDE.md — GerbilManager + +Leitfaden für die Arbeit an diesem Repo. Bitte vor Änderungen lesen. + +## Was ist das? + +Verwaltungs-App für eine **Rennmaus-Zucht** („Zucht der kleinen Chaoten"): Tiere, +Würfe, Stammbäume/Ahnentafeln, Genetik (Farbschläge/Genotypen), Gehege, Kontakte +(Züchter/Abnehmer), Abgabeverträge, Statistik und eine öffentliche CMS-Webseite. +Single-User (die Züchterin), Daten größtenteils aus bestehenden Quelldateien +importiert. + +## Architektur / Projekte + +| Projekt | Zweck | +|---|---| +| `GerbilManager.AppHost` | **.NET Aspire** Orchestrator — startet PostgreSQL (Container) + WebAPI | +| `GerbilManagerWebAPI` | Backend: ASP.NET **Minimal API**, EF Core + Postgres, Endpoints in `Endpoints/`, Entities in `Models/`, DTOs in `Dtos/` | +| `GerbilManager.ServiceDefaults` | Aspire-Defaults (Telemetry/Health) | +| `GerbilManager.Tests` | Backend-Tests (xUnit) | +| `gerbil-manager-web` | Frontend: **React + Vite + TypeScript** (React Router, react-d3-tree für den Stammbaum) | +| `tools/import` | **Python**-Import-Pipeline (zero-dep), wandelt Quelldateien → `resolved_import.json` | + +## App starten (IMMER über Aspire, nicht nur die WebAPI) + +```bash +dotnet run --project GerbilManager.AppHost +``` +- WebAPI: http://localhost:5179 · OpenAPI: `/openapi/v1.json` +- Aspire-Dashboard: https://localhost:17004 (Login-Token steht im AppHost-Log) +- EF-Migrationen werden beim Start automatisch angewandt (`db.Database.Migrate()` in `Program.cs`). +- Postgres läuft als Container (Name wechselt pro Run, z. B. `postgres-xxxx`); die + **Daten liegen in einem persistenten Volume** → überleben Neustarts. DB-Name: `gerbilmanager`. + +## Import → DB (3-stufig, WICHTIG) + +Die DB wird **nicht** direkt von Python beschrieben. Nach jeder Import-Code-Änderung +neu generieren UND neu einspielen, sonst zeigt die App den alten Stand. + +```bash +# 1. Stammbäume + Wurfchronik → animals.json/litters.json (+ Fotos) +python tools/import/extract.py +# 2. Abgabeverträge (DOCX) → contracts.json +python tools/import/extract_contracts.py +# 3. Dedup, Eltern-Resolver, Provenance, Vertrags-Anreicherung → resolved_import.json +python tools/import/merge_and_resolve.py +# 4. In die laufende DB laden (API muss laufen): WISCHT + lädt neu +curl -X POST http://localhost:5179/import/ingest-resolved +``` + +- **`IngestResolvedService` wischt** Gerbils/Litters/Contacts/Photos/Health/Weights/ + **SaleContracts** und lädt aus `resolved_import.json` neu. Importierte SaleContracts + sind Teil des Payloads → werden bei jedem Ingest neu erzeugt (idempotent, IDs deterministisch). +- **Feedback überlebt den Ingest** (wird nicht gewischt) — daher hat `Feedback` nur + **lose, nullable Guid-Spalten ohne FK** (GerbilId/LitterId/ContactId). Dieses Muster + für alles nutzen, was Re-Ingests überleben soll. +- `resolved_import.json` ist **gitignored** (Runtime-Output); `review-report.md` ist getrackt. +- Deterministische GUIDs via `generate_guid("...")` → stabile IDs über Re-Ingests. + +### Quelldateien (lokal/Netzwerk) +- Stammbäume: `C:\Users\gulum\dev\Sttammbäume\*.xlsx` +- Wurfchronik: `C:\Users\gulum\dev\Wurfchronik der Kleine Chaoten Teil1.xlsx` +- Abgabeverträge: `\\truenas\Datengrab\Rennmäuse\Verträge\*.docx` (~1,4k; kann zeitweise offline sein) + +## Build & Test + +**Frontend** (`cd gerbil-manager-web`): +```bash +npx tsc --noEmit # Typecheck (muss sauber sein) +npx vitest run # Unit-Tests +npx eslint # Lint +npx playwright test [spec]# e2e (Projekte: desktop + phone), läuft gegen Mock-API +``` +- e2e nutzt einen **Mock-Modus** (`e2e/mock-api.ts` + `e2e/mock-data.ts`), kein echtes Backend. + Neue API-Routen/Felder dort spiegeln. `skipUnlessMock()` am Testanfang. + +**Backend**: +```bash +dotnet build +dotnet test # GerbilManager.Tests +dotnet ef migrations add --project GerbilManagerWebAPI # neue Migration +``` +- Zum Bauen muss eine laufende WebAPI ggf. gestoppt werden (Datei-Lock auf `bin`). + +**Python** (`cd tools/import`, zero-dep, exit 0 = pass): +```bash +python test_extract.py test_extract_docx.py test_genotype.py test_merge_resolve.py test_extract_contracts.py +``` + +## Konventionen (bitte einhalten) + +- **Alle deutschen UI-Texte in `gerbil-manager-web/src/strings/de.ts`** — niemals in + Komponenten hartkodieren. +- **EF-Migration** für jede Schema-Änderung; wird beim Aspire-Start angewandt. +- **Provenance/Datenherkunft** liegt als **JSON-Text-Spalte** (`Provenance`) auf + Gerbil/Contact/Litter → JSON-Feld-Erweiterungen brauchen **keine** Migration. +- **Lose nullable Guid-Spalten ohne FK** für Tabellen, die den Ingest-Wipe überleben. +- Commits: nur wenn der Nutzer es verlangt; auf `main` wird gearbeitet (Remote: `http://truenas:13000/Gulum/GerbilManager.git`). Commit-Messages auf Deutsch, Format `feat(scope): …`. +- Subagenten committen NICHT — Haupt-Loop verifiziert und committet. + +## Domänenwissen (Rennmaus-Zucht) + +- **Lebensspanne ~6 Jahre** → ein Elternteil kann max. ~6 Jahre älter als sein Kind + sein und muss vorher geboren sein (`parent_age_plausible` im Import; verwirft + unplausible Eltern-Links). +- **Geschwisterverpaarung** (Vollgeschwister als Eltern): erkannt, wenn Vater & Mutter + **dieselbe `litterId`** ODER **dasselbe Geburtsdatum** teilen (gleiches DOB = starkes + Indiz). UI: Diagramm führt den Vorfahren-Ast zusammen (Verweis-Knoten); Akte zeigt + „⚭ Geschwisterverpaarung"-Chip. +- **Box-Farbe im Stammbaum-xlsx = Geschlecht**: weiß = weiblich, blau = männlich. +- **Genotyp/Farbschlag**: 8-Locus-Notation (siehe `tools/import/genotype.py`, + `gerbil-manager-web/src/genetics`). Unbekanntes Allel = `-` (nicht `?`). + E-Locus: `ee`=Fuchs, `eef`=Fuchsschimmel, `efef`=Schimmel. +- **Stammbaum-Charts**: Generationen = Spaltenbänder (Proband links in Spalte B/2, + je Generation +3 Spalten); Eltern-Position: Vater oben, Mutter unten. Fotos liegen + je nach Datei links/auf der Namenszelle — die Seite wird heuristisch über die + geringste Spalten-Fehlausrichtung bestimmt (`extract._attach_photos`). + +## Stolperfallen + +- **Aspire-Containername wechselt** pro Run, das Daten-Volume bleibt → DB-Inhalt + überlebt Neustarts (auch alte Schema-Stände → Migrationskonflikte möglich, s. u.). +- **Migrations-Historie vs. committete Migration-IDs**: Wird eine Migration angewandt + und danach mit neuem Zeitstempel neu generiert, sieht EF sie als „pending" und der + Start crasht („column … already exists"). Schema ist dann korrekt — nur die + `__EFMigrationsHistory`-IDs müssen an die committeten Dateinamen angeglichen werden. +- **PowerShell + psql**: PascalCase-Identifier (`"__EFMigrationsHistory"`) über + PowerShell→docker→psql zerschießen das Quoting. Stattdessen Bash-Heredoc: + `docker exec -i -e PGPASSWORD=$PW psql -U postgres -d gerbilmanager <<'SQL' … SQL`. + Passwort: `docker exec printenv POSTGRES_PASSWORD`. +- **Direkte DB-Schreibzugriffe** (psql) werden vom Auto-Mode-Classifier blockiert — + vorher beim Nutzer rückversichern. +- Bash-Tool ist **Git-Bash (POSIX)**, das andere Tool ist **PowerShell** — je eigene Syntax. + +## Wo liegt was (Feature-Landkarte) + +- **Stammbaum-Viewer**: `gerbil-manager-web/src/pages/StammbaumPage.tsx`, + `src/pedigree/*` (build.ts = Baum-Aufbau + Geschwister-Erkennung; types.ts). + Desktop passt den ganzen Baum ein; Touch: Long-Press öffnet das Kontextmenü + (ID kopieren / Fehler melden). +- **Datenherkunft/Nachverfolgung**: `src/components/ProvenanceDialog.tsx`; erzeugt im + Import via `build_entity_provenance`/`_build_*_history` (chronologische, datei- + attribuierte `history[]`, inkl. „⚠ … verworfen — Grund; … verwendet"). +- **Fehler melden (Feedback)**: `src/components/ReportErrorDialog.tsx`, + `src/api/feedback.ts`, Backend `Endpoints/FeedbackEndpoints.cs` + `Models/Feedback.cs`. +- **Verträge**: `Models/SaleContract.cs`, `Endpoints/ContractEndpoints.cs`, + `ContractGenerator.cs`, Frontend `src/pages/Vertraege*`; Import: `extract_contracts.py` + + `enrich_from_contracts` in `merge_and_resolve.py`. +- **Import-Kernlogik**: `tools/import/merge_and_resolve.py` (Dedup, Eltern-Resolver mit + Gender-/Alters-Plausibilität, Litter-/Sibling-Dedup, Provenance, Vertrags-Anreicherung). + +## Verifikations-Checkliste vor „fertig" + +1. `npx tsc --noEmit`, `npx vitest run`, `npx eslint` sauber. +2. Betroffene `npx playwright test`-Specs grün. +3. `dotnet build` + `dotnet test` grün. +4. Bei Import-Änderungen: `python test_*.py` grün + `resolved_import.json` plausibel + (Stichprobe), danach App neu starten + `POST /import/ingest-resolved`.