.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>
11 KiB
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)
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()inProgram.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.
# 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
IngestResolvedServicewischt Gerbils/Litters/Contacts/Photos/Health/Weights/ SaleContracts und lädt ausresolved_import.jsonneu. Importierte SaleContracts sind Teil des Payloads → werden bei jedem Ingest neu erzeugt (idempotent, IDs deterministisch).- Feedback überlebt den Ingest (wird nicht gewischt) — daher hat
Feedbacknur lose, nullable Guid-Spalten ohne FK (GerbilId/LitterId/ContactId). Dieses Muster für alles nutzen, was Re-Ingests überleben soll. resolved_import.jsonist gitignored (Runtime-Output);review-report.mdist 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):
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:
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):
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
mainwird gearbeitet (Remote:http://truenas:13000/Gulum/GerbilManager.git). Commit-Messages auf Deutsch, Formatfeat(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_plausibleim Import; verwirft unplausible Eltern-Links). - Geschwisterverpaarung (Vollgeschwister als Eltern): erkannt, wenn Vater & Mutter
dieselbe
litterIdODER 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 viabuild_entity_provenance/_build_*_history(chronologische, datei- attribuiertehistory[], inkl. „⚠ … verworfen — Grund; … verwendet"). - Fehler melden (Feedback):
src/components/ReportErrorDialog.tsx,src/api/feedback.ts, BackendEndpoints/FeedbackEndpoints.cs+Models/Feedback.cs. - Verträge:
Models/SaleContract.cs,Endpoints/ContractEndpoints.cs,ContractGenerator.cs, Frontendsrc/pages/Vertraege*; Import:extract_contracts.pyenrich_from_contractsinmerge_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"
npx tsc --noEmit,npx vitest run,npx eslintsauber.- Betroffene
npx playwright test-Specs grün. dotnet build+dotnet testgrün.- Bei Import-Änderungen:
python test_*.pygrün +resolved_import.jsonplausibel (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-Servermempalace-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 Hooksmempalace hook run --hook {session-start,stop,precompact} --harness claude-code: SessionStart lädt relevanten Kontext automatisch, Stop/PreCompact persistieren.- Voraussetzung:
mempalaceist installiert und auf PATH (~/.local/bin). Nachgit cloneggf. 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(vorhermempalace_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 gerbilmanagerentfernt 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.