.claude/settings.json (committet) verdrahtet die MemPalace-Hooks (session-start lädt Kontext, stop/precompact persistieren) → künftige Claude- Sessions in diesem Ordner nutzen MemPalace automatisch (zusammen mit .mcp.json, das die 19 MCP-Tools bereitstellt; aktiv nach Claude-Neustart). CLAUDE.md: Abschnitt „Gedächtnis (MemPalace)" + Memory-Policy (WANN/WIE/WO eine Memory angelegt wird: durable & nicht-offensichtlich → Palast; kanonisch & projektweit → zusätzlich CLAUDE.md; Veraltetes per kg_invalidate beenden statt löschen). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
204 lines
11 KiB
Markdown
204 lines
11 KiB
Markdown
# 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 <dateien> # 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 <Name> --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 <container> psql -U postgres -d gerbilmanager <<'SQL' … SQL`.
|
|
Passwort: `docker exec <container> 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`.
|
|
|
|
## Gedächtnis (MemPalace) — IMMER nutzen
|
|
|
|
Dieses Projekt nutzt **MemPalace** als KI-Langzeitgedächtnis (lokal, kein API-Key).
|
|
Die Anbindung ist im Repo persistiert und lädt automatisch:
|
|
- `.mcp.json` (committet) registriert den MCP-Server `mempalace-mcp` → **19 MCP-Tools**
|
|
(`mempalace_search`, `mempalace_kg_query/add/invalidate/timeline`, `mempalace_add_drawer`,
|
|
`mempalace_diary_*` …). Aktiv ab Claude-Neustart (MCP-Server einmal bestätigen).
|
|
- `.claude/settings.json` (committet) verdrahtet die Hooks
|
|
`mempalace hook run --hook {session-start,stop,precompact} --harness claude-code`:
|
|
**SessionStart** lädt relevanten Kontext automatisch, **Stop/PreCompact** persistieren.
|
|
- Voraussetzung: `mempalace` ist installiert und auf PATH (`~/.local/bin`). Nach `git clone`
|
|
ggf. MemPalace installieren; `mempalace.yaml` (Raum-Config) ist bewusst **gitignored**
|
|
(per-project, lokal). Der Palast selbst liegt lokal unter `~/.mempalace` (nicht im Repo).
|
|
|
|
**Arbeitsweise pro Session:** zu Aufgabenbeginn relevantes Wissen abrufen
|
|
(`mempalace_search` / `mempalace_kg_query`), bevor du im Code suchst; am Ende neue
|
|
durable Erkenntnisse ablegen.
|
|
|
|
### Memory-Policy — WANN / WIE / WO eine Memory anlegen
|
|
|
|
**WANN** (anlegen): nur **dauerhaft** nützliches, **nicht-offensichtliches** Wissen, das
|
|
künftige Sessions braucht — Architektur-/Design-Entscheidungen und ihr *Warum*, Domänenregeln
|
|
(z. B. 6-Jahre-Lebensspanne, Geschwisterverpaarung), Konventionen, Stolperfallen, bestätigte
|
|
Nutzer-Präferenzen, wiederkehrende Workflows.
|
|
**NICHT anlegen**: transienter Task-Status; was Code/Git/CLAUDE.md ohnehin festhalten;
|
|
Dinge, die nur für das aktuelle Gespräch zählen.
|
|
|
|
**WIE** (anlegen/pflegen):
|
|
- Fakt mit Gültigkeit → `mempalace_kg_add`. Freitext-Notiz/Erkenntnis → `mempalace_add_drawer`
|
|
(vorher `mempalace_check_duplicate`).
|
|
- Ändert/erledigt sich ein Fakt → `mempalace_kg_invalidate` (setzt End-Datum, **nicht löschen** —
|
|
der Graph ist temporal). So bleibt nichts veraltet stehen.
|
|
- Repo-Dateien werden über `mempalace mine <dir>` automatisch gefilet; `mempalace sync --apply
|
|
--wing gerbilmanager` entfernt Drawers gelöschter/verschobener Dateien.
|
|
|
|
**WO** (welcher Speicher):
|
|
- **MemPalace-Palast** (`~/.mempalace`, lokal): reichhaltiges, durchsuchbares Recall — der Default
|
|
für Memories.
|
|
- **CLAUDE.md** (Repo, committet): die **kanonischen** Projektfakten/Konventionen, die geteilt und
|
|
versioniert sein müssen. Wichtige durable Erkenntnisse hier spiegeln, damit sie im Repo (nicht nur
|
|
lokal) liegen.
|
|
|
|
Faustregel: durable + projektweit kanonisch → **CLAUDE.md** *und* Palast; sonstiges durable Wissen →
|
|
Palast; veraltetes → invalidieren, nicht stehen lassen.
|