Import-Logik: - Externe Gründer (Zooladen/„von Privat"/„from …, <Land>") bekommen keine erfundenen Chart-Eltern mehr → Bill, Cooky, Zadar haben korrekt unbekannte Eltern (is_external_origin). [#5,#13,#28] - Hagrid: externe Zucht wird nicht mehr als Bestand markiert (isResident=false) + Leerhüllen-Dedup → ein Datensatz mit Eltern Snickers × Milka. [#17,#18,#20a] - Gender-Index: eindeutiges Geschlecht schlägt unbekanntes Duplikat → Rollen- Auflösung repariert (Vance→Mutter Enya, Zac→Vater Vance/Mutter Dorie). [#33,#35] - „Eltern: X + Y"-Wurfnotizen werden geparst (~46 Würfe); v.d.↔von-den-Namens- kanon (Theodore→BlackFire). [#9,#11,#30] Daten-Overrides (conflict-decisions.json, jetzt auch Gender + exakte Eltern): - Mozart→weiblich [#2], Yuki=Camaro×Izumi [#23], Gold-Mutter=Chelsea [#36], Arya=Vance×Sansa (Geschwisterverpaarung) [#16], Tony→Sammy [#12], Odelia [#15], Jamie→Danny [#31], Silver=Taro×Beatrice [#11]. Frontend: GerbilDetailPage blendet für isResident=false Würfe + Charakter aus (Hinweis nonResidentNote). [#17,#20b] Tests: test_extract/test_merge_resolve erweitert; vitest 135, playwright tiere 34 grün. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
gerbil-manager-web
Frontend des Rennmaus-Managers — React + TypeScript + Vite, mobile-first (Smartphone und Laptop).
Entwicklung
npm install
npm run dev
Erwartet die laufende GerbilManagerWebAPI unter http://localhost:5179
(Profil http in GerbilManagerWebAPI/Properties/launchSettings.json).
Konfiguration
| Variable | Standard | Beschreibung |
|---|---|---|
VITE_API_BASE_URL |
http://localhost:5179 |
Basis-URL der GerbilManagerWebAPI |
Konventionen
- Alle für Benutzer sichtbaren Texte sind Deutsch und liegen zentral in
src/strings/de.ts— keine Texte direkt in Komponenten hartkodieren. - API-Zugriffe laufen über
src/api/client.ts. - Routen werden in
src/App.tsxregistriert, Seiten liegen insrc/pages/. - Mutationen (
useMutationaussrc/hooks/useApi.ts):run()wirft NIE, sondern liefert einMutationOutcome<T>—{ ok: true, value }oder{ ok: false, error, cause }. Aufrufer MÜSSEN verzweigen:const r = await m.run(x); if (r.ok) navigate(r.value.id).m.errortreibt die Inline-Anzeige; für Spezialfälle (z. B. HTTP 409)r.causeprüfen (r.cause instanceof ApiError && r.cause.status === 409). So sind unbehandelte Promise-Rejections an Aufrufstellen ausgeschlossen (siehe auchsrc/dev/unhandledRejectionGuard.ts).
Build
npm run build
npm run preview
Farbschlag-Katalog (AR-5)
Der Katalog lebt in src/genetics/catalog.ts (Single Source of Truth).
Nach jeder Änderung dort den Generator laufen lassen:
npm run gen:catalog
Erzeugt zwei Artefakte und committet beide:
| Datei | Notation | Verwendung |
|---|---|---|
src/genetics/colorVarietySeed.generated.json |
Klammer (e[f], c[chm]) |
UI-Dropdowns, Frontend-Suche |
src/genetics/colorVarietySeed.backend.json |
Frozen symbols (ef, cchm) |
EF-Seed-Migrationen (Pam, DATA-Lane) |
Der vitest-Drift-Guard (catalog-drift.test.ts) schlägt fehl, wenn
generated.json nach einer Katalog-Änderung nicht aktualisiert wurde.
E2E-Tests (QA-1, Playwright)
npm run e2e # Mock-Modus: startet Vite auf :5199, API wird gemockt
npx playwright test --project=phone # nur Smartphone-Viewport (390px)
- Mock-Modus (Standard): kein Backend nötig.
e2e/mock-api.tsfängt alle API-Aufrufe ab (DATA-2-Vertrag: Gridify-Paging, camelCase, 409-Konflikte) mit frischem Datenbestand pro Test (e2e/mock-data.ts). - Live-Modus: dieselbe Suite gegen den echten Stack —
$env:E2E_BASE_URL = 'http://localhost:5173'; npm run e2e(vorher AppHost starten). Tests, die Mock-Seed-Daten voraussetzen, überspringen sich selbst; die übrigen legen eigene Datensätze an. - Beide Viewports (Smartphone 390px, Laptop 1280px) laufen für jede Spec;
alle Assertions prüfen die deutschen Oberflächentexte direkt aus
src/strings/de.ts.