Commit Graph

459 Commits

Author SHA1 Message Date
ea3596ca0d REVIEW-FIXES-2: DB-4 (Deutsche Collation ä/ö/ü) + DB-5 (Litter.ExternalRef)
DB-4 (medium): ICU German collation de-x-icu auf deutschen Textspalten
  Gerbil.Name, Gerbil.NameSearch, Gerbil.OriginBreeder, ColorVariety.Name,
  Contact.Name. Korrekte ä/ö/ü-Sortierung + locale-aware lower() in Postgres.
  Nur bei Npgsql (Database.ProviderName check) — SQLite-Testhost kennt keine
  eigenen Collation-Namen und wuerde EnsureCreated fail lassen.
  Migration AddGermanCollation (ALTER COLUMN ... TYPE text COLLATE de-x-icu).

DB-5 (low): Litter.ExternalRef + filtered unique index + Importer-Anbindung
  Litter.ExternalRef (string?, nullable) = stable import source id (sl.Id).
  Filtered unique index WHERE ExternalRef IS NOT NULL (wie DB-1 fuer Gerbil).
  Migration AddLitterExternalRef.
  Importer (ImportService.cs): setzt ExternalRef = sl.Id beim Litter-Insert;
  prueft existingLitterExtRefSet als PRIMAEREN Idempotenz-Key (ExternalRef),
  Name+Date-Key als Fallback fuer Wuerfe ohne ExternalRef aus frueheren Laeufen.
  +Test DB5_Litter_ExternalRef_set_and_used_for_idempotency (mutiert den Namen
  nach erstem Import, prueft dass Re-Import via ExternalRef erkennt).

GATE: 140/140 C#, has-pending=No.
2026-06-06 19:49:50 +02:00
e6b513ed5d Merge feature/genotype-notation (GEN-3h): Genotyp-Anzeige in Zuechterin-Schreibweise
Some checks failed
CI / Frontend Tests (Node/Vite) (push) Successful in 9m33s
CI / Docker Build & Push (push) Has been skipped
CI / Backend Tests (.NET) (push) Failing after 49s
- Bracket-Notation im Display: e[f]/c[chm]/c[h] (Storage bleibt frozen symbols)
- E-Locus-Reihenfolge: e VOR e[f] ('ee[f]' nicht 'efe')
- CR-1a: ee[-] (Silvain) Parser-Fix (lookbehind)
- C zeigt jetzt 'aa C- D- ee[f] Gg Pp spsp rere'
vitest 92/92 (inkl. ee[-] + C/Zuleika/Milka-Orakel), e2e 148, build/eslint. Frontend-only (src/genetics/).
HINWEIS: generated.json canonicalGenotype jetzt Klammer-Notation = DISPLAY; Backend-Seed bleibt frozen (Matching).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 18:27:45 +02:00
52303b90b2 CR-1a: ee[-] Parser-Fix (Silvain) — lookbehind trennt e[-] vom führenden Allel
normalizeToken: lookbehind-Regex /(?<=[A-Za-z])e\[-\]/→'?' greift wenn e[-]
von einem Buchstaben (erstes Allel) gefolgt wird (ee[-] → e?); standalone e[-]
fällt durch auf die generische \[-\]→? Regel (→ e?). Beide Pfade liefern
splitToken 2 Allele [e,?]. Vorher: ee[-]→ee?→ 3 Allele → Fehler.
Fixture: Silvain 'aa c[chm]c[chm] Dd ee[-] Gg Pp Spsp' → E=[e,?] ✓.
Gate: build ✓  eslint ✓  vitest 92/92 ✓  e2e 126/126 ✓
2026-06-06 18:24:06 +02:00
4b6a07544d GEN-3h: Breeder bracket-notation display + E-locus e-vor-e[f] Sortierung
- genotype.ts: toDisplayString zeigt ef→e[f], cchm→c[chm], ch→c[h] (Display-only;
  Storage-Contract unverändert). E-Locus Display-Rank E>e>ef: {ef,e} Paar
  rendert als ee[f] statt e[f]e (Züchterin-Konvention, Julian-Feedback).
- genotype.ts: normalizeToken akzeptiert Klammer-Eingabe (e[f], c[chm], c[h],
  [-]) → interne Symbole; vollständiger Round-Trip Display→Parse.
- genetics.test.ts: Katalog-Regex auf [A-Za-z[\]?-]+ erweitert; GEN-3h
  Notation-Fixtures (C/Zuleika/Milka-Orakel, Klammer-Round-Trip, E-Sortierung).
- colorVarietySeed.generated.json: neu generiert (66 Zeilen mit Klammer-Notation).
Gate: build ✓  eslint ✓  vitest 91/91 ✓  e2e 120/120 ✓
2026-06-06 18:24:06 +02:00
8f90821081 Merge feature/ci-drift-check (DB-3): CI EF-Migrations-Drift-Check
Some checks failed
CI / Backend Tests (.NET) (push) Failing after 50s
CI / Frontend Tests (Node/Vite) (push) Successful in 9m33s
CI / Docker Build & Push (push) Has been skipped
.gitea/workflows/ci.yml: nach Build zwei Steps (dotnet-ef install + has-pending-model-changes)
→ faengt Snapshot/Migrations-Drift im Runner (EnsureCreated-SQLite-Testhost sieht das nie).
Automatisiert die manuelle MERGE-GATE-Regel. Nur CI-Config, kein Code/Schema.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 18:06:07 +02:00
9dda78b28a DB-3: EF Migrations Drift-Check in CI (has-pending-model-changes)
Nach dem Build-Schritt in test-backend: dotnet-ef 10.0.* global installieren,
dann `dotnet ef migrations has-pending-model-changes` ausführen. Schlaegt fehl
wenn Code-Änderungen an Entities/OnModelCreating keine passende Migration haben.
Fängt genau den Drift, den der SQLite-EnsureCreated-Testhost nicht sieht.
2026-06-06 18:05:15 +02:00
865b3831c8 Merge feature/ops-fixes: DataProtection-Key-Persistenz (AR-3) + prod-compose AI-Env (AR-4)
Some checks failed
CI / Backend Tests (.NET) (push) Successful in 52s
CI / Docker Build & Push (push) Has been cancelled
CI / Frontend Tests (Node/Vite) (push) Has been cancelled
- AR-3: AddDataProtection().PersistKeysToFileSystem + compose keys-Volume → Gmail-App-Passwort
  ueberlebt Redeploy (war ephemer → Inbox waere still gebrochen). Dev-Fallback .data-protection-keys.
- AR-4: prod compose.yaml ANTHROPIC_API_KEY → AI__BaseUrl/ApiKey/Model + .env.example aktualisiert.
139/139, has-pending=No, kein Schema-Change. [god-QA: config/Program.cs only, disjunkt]

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 18:03:20 +02:00
1b0d3286db OPS-FIXES-1: AR-3 Data Protection Key-Persistenz + AR-4 AI-Env-Korrekte
AR-3 (P1): PersistKeysToFileSystem + persistentes Volume
  Program.cs: AddDataProtection().PersistKeysToFileSystem(keyRingPath).SetApplicationName(GerbilManager)
  Pfad konfigurierbar via DataProtection:KeyRingPath (env DataProtection__KeyRingPath);
  Fallback = ContentRoot/.data-protection-keys (Aspire-Dev-ephemeral, ok).
  compose.yaml: DataProtection__KeyRingPath: /data/keys + Volume-Mount keys:/data/keys.
  Volumes: neues 'keys' Volume (Bind-Mount auf NAS-Dataset KEYS_PATH=/mnt/SSD/gerbil/keys).
  .gitignore: .data-protection-keys/ ignoriert (Dev-only ephemeral keys).
  Verhindert: Gmail-App-Passwort wird nach Image-Redeploy unlesbar (bisher stilles inbox-fail).

AR-4 (P1): compose.yaml + .env.example: AI__* statt ANTHROPIC_API_KEY
  compose.yaml: ANTHROPIC_API_KEY entfernt (Code liest es nicht). Korrekte Vars:
    AI__BaseUrl: ${AI__BaseUrl:-}
    AI__ApiKey: ${AI__ApiKey:-}
    AI__Model: ${AI__Model:-gemini-2.0-flash}
  .env.example: AI__BaseUrl/ApiKey/Model + KEYS_PATH hinzugefuegt; ANTHROPIC_API_KEY entfernt.
  Quelle: docs/ai-provider.md (war korrekt, compose war falsch).
  Verhindert: alle 4 KI-Features (Verkaufstext, Inbox-Entwurf) blieben in prod stumm.

GATE: 139/139 C#-Tests, build gruen (using Microsoft.AspNetCore.DataProtection; framework-included).
2026-06-06 18:01:57 +02:00
de1d9460b3 Merge feature/review-fixes-backend: CR-9/CR-10/CR-11 + DB-1 (ExternalRef unique)
Some checks failed
CI / Backend Tests (.NET) (push) Successful in 56s
CI / Docker Build & Push (push) Has been cancelled
CI / Frontend Tests (Node/Vite) (push) Has been cancelled
- CR-9: Import-Lookup TryGetValue + ExternalRef-Fallback (kein throw bei name/DOB-Drift)
- CR-11: Farbschlag aus Genotyp ableiten (fill-NULL-only, nur vollstaendige Genotypen ≥8/kein ?? → keine False-Positives); Plan-Loop + Post-Sweep fuer Bestandstiere
- CR-10: conflict-decision validiert Genotyp-Override (ungueltig → skip+Warnung, Konflikt trotzdem geloest)
- DB-1: filtered unique index ExternalRef IS NOT NULL + Migration UniqueExternalRef
Gate 139/139 C# + python all pass, ef has-pending=No. KEIN Farbschlag-Overwrite (fill-NULL).
[god-QA: disjunkt zu frontend-Merges]

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 17:55:55 +02:00
259dd96c0e Merge feature/ui-polish-2: '(ohne Namen)'-Platzhalter in Stammbaum + VertragWizard + WurfForm
Some checks failed
CI / Backend Tests (.NET) (push) Successful in 52s
CI / Docker Build & Push (push) Has been cancelled
CI / Frontend Tests (Node/Vite) (push) Has been cancelled
Namenlose Stub-Tiere zeigen jetzt ueberall '(ohne Namen)' statt leer: Flagship-Stammbaum
(Karten+Druck+Header), Vertrags-Assistent, Wurf-Formular. +2 e2e (namenloser Ahne im Stammbaum).
vitest 82, e2e 148, build clean. Kein EF.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 17:54:33 +02:00
615abfa510 REVIEW-FIXES-BACKEND: CR-9 + CR-11 + CR-10 + DB-1
CR-9 (major): gidByNameDob TryGetValue + ExternalRef-Fallback
  Verhindert KeyNotFoundException wenn Name/DOB zwischen zwei Laeufen driftet
  (z.B. correctDob-Remap oder UI-Umbenennung). Fallback: ExternalRef-Dict-Lookup;
  bei Miss: sauberes Ueberspringen + Note statt 500. +Test CR9_NameDOB_drift.

CR-11 (major): Farbschlag aus Genotyp ableiten (fill-NULL-only)
  Deep-Band-Tiere (gen>=2, kein Farbschlag-Feld) landen nicht laenger mit null
  ColorVariety. GenotypePotentiallyMatches() vergleicht locus-pair-weise (??=wildcard,
  case-insensitive). Nur vollstaendige Genotypen (8 Loci, kein ??) loesen Ableitung aus.
  Plan-Loop: fuellt colorVarietyId bei null + vollstaendigem Genotyp.
  Post-Sweep: bestehende DB-Tiere mit null ColorVarietyId werden nachgefuellt.
  AnimalSummary.FarbschlagDerivedFromGenotype = Zaehler. +Test CR11_ColorVariety_from_geno.

CR-10 (major, Python): malformed Override-Genotyp wird nicht angewendet
  apply_conflict_decisions validiert mapped8locus nach gt.parse(). Leeres Ergebnis
  = Genotyp unveraendert + decisionWarning statt stillem Blanken. Konflikt wird
  trotzdem aufgeloest (Entscheidung gilt, nur Genotyp-Override ausgelassen).
  +5 Python-Tests (CR-10-Block in test_extract.py).

DB-1 (high): filtered unique index auf Gerbil.ExternalRef
  WHERE ExternalRef IS NOT NULL — verhindert doppelten Import bei Race-Conditions
  oder Lauf-Ueberschneidungen. Migration UniqueExternalRef. SQLite-Testhost:
  HasFilter() wird via EnsureCreated appliziert (SQLite unterstuetzt Partial-Indexes).
  PartialUpdateTests externalRef-Assertion auf NotNull geaendert (name-hash unique).

GATE: 139/139 C# + Python ALL PASS, ef has-pending=No.
2026-06-06 17:54:06 +02:00
69ffe58d6b UI-POLISH-2: '(ohne Namen)' Platzhalter in Stammbaum, Vertrag-Wizard, Wurf-Formular
- StammbaumPage: PedigreeCard-Name + PrintCell-Name + beide titleFor()-Aufrufe → g.name || nameless
- VertragWizardPage: wizard-pick__name + join(', ')-Tierliste → g.name || nameless
- WurfFormPage: fatherName/motherName in Prefill (nameById.get || nameless) + Picker-Auswahl (g.name || nameless)

e2e: neuer Test stammbaum.spec — namenloser Ahne zeigt Platzhalter in Karte + Titel

Gate: vitest 82/82, e2e 148/148, tsc clean
2026-06-06 17:53:24 +02:00
d7c0698c44 Merge feature/form-fields: Herkunft (originBreeder) + 'Gehoerlos' (isDeaf) im Tier-Formular editierbar
Some checks failed
CI / Backend Tests (.NET) (push) Successful in 54s
CI / Docker Build & Push (push) Has been cancelled
CI / Frontend Tests (Node/Vite) (push) Has been cancelled
GerbilFormPage: originBreeder-Freitextfeld + isDeaf-Tristate-Select (Ja/Nein/Unbekannt),
round-trip laden/speichern. types.ts isDeaf, de.ts Labels. +4 e2e round-trip. Komponiert
mit CR-2 PATCH-Semantik (ausgelassene Felder bleiben). vitest 82, e2e 146, build clean. Kein EF.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 17:47:57 +02:00
db49150206 FORM-FIELDS-1: originBreeder + isDeaf in GerbilFormPage
- types.ts: isDeaf?: boolean|null in Gerbil + CreateGerbil (UpdateGerbil erbt via Partial)
- de.ts: fields.originBreeder, fields.isDeaf; form.isDeafUnknown/Yes/No
- GerbilFormPage: originBreeder Freitext-Input (neben originContactId-Dropdown); isDeaf Tristate-Select (Unbekannt/Ja/Nein); round-trip load→display→save

e2e: 2 neue Tests (originBreeder Freitext + isDeaf Tristate round-trip)

Gate: vitest 82/82, e2e 146/146, tsc clean
Rebase auf Pams CR-2 folgt nach deren Merge.
2026-06-06 17:47:25 +02:00
f6a4025d71 Merge feature/fix-cr2-partial-update: P0 BLOCKER — PUT /gerbils PATCH-Semantik (kein Datenverlust mehr)
Some checks failed
CI / Backend Tests (.NET) (push) Successful in 53s
CI / Docker Build & Push (push) Has been cancelled
CI / Frontend Tests (Node/Vite) (push) Has been cancelled
CR-2: Apply() behaelt ausgelassene Felder (?? g.X fuer alle); Name/Gender nullable;
ForSale-Toggle + Charakterbogen-Save + Edit-Form nullen keine anderen Felder mehr.
+4 Regressionstests (PartialUpdateTests.cs). Gate 137/137, ef has-pending=No, kein Schema-Change.
[god-QA: backend-only, disjunkt zu ui-polish]

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 17:41:32 +02:00
8175b150f7 CR-2 FIX: PUT /gerbils PATCH-Semantik — partielle Updates zerstoeren keine Felder mehr
GerbilInput.Name + Gender auf nullable geaendert. Apply() wendet fuer alle Felder
?? g.X an (omittierte/null Felder behalten den DB-Wert). g.Name aus dem PUT-Handler
in Apply() verschoben. Verhindert stillen Datenverlust bei partiellen Frontend-Calls
(ForSale-Toggle schickt nur {status}, Charakterbogen-Save schickt nur {traits,note}).

+4 Regressionstests (PartialUpdateTests): ForSale-Toggle, Charakterbogen-Save,
EditForm-ohne-Import-Felder, minimaler POST — alle grueen (137/137 gesamt).
2026-06-06 17:40:15 +02:00
319aca7608 Merge feature/ui-polish: namenlose Tiere Platzhalter '(ohne Namen)' + Leerwert-'—'-Konsistenz
Some checks failed
CI / Backend Tests (.NET) (push) Successful in 56s
CI / Docker Build & Push (push) Has been cancelled
CI / Frontend Tests (Node/Vite) (push) Has been cancelled
- de.ts nameless + GerbilsPage/GerbilDetailPage/AnimalPicker zeigen '(ohne Namen)' statt leer
- causeOfDeath/notes via || null → Rows zeigen '—' konsistent (Herkunft war schon korrekt)
- +4 e2e (Platzhalter Liste+Detail x2 Viewports). vitest 82, e2e 130, build clean. Kein EF.
[god-QA: disjunkt zu qa-regression+import-backfill-Merges]

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 17:39:15 +02:00
4d9e901139 Merge feature/import-backfill: toleranter KC-Matcher + Herkunft-Backfill (fill-NULL) + Farbschlag-Zaehler
Some checks failed
CI / Backend Tests (.NET) (push) Successful in 52s
CI / Docker Build & Push (push) Has been cancelled
CI / Frontend Tests (Node/Vite) (push) Has been cancelled
- extract.py: norm_zucht-Regex-Fix (trailing \b nach '.'), is_clan_zucht() — alle KC-Schreibvarianten → canon 'kleinechaote'
- ImportService: Herkunft-Backfill (OriginBreeder NULL+resident → aus Eltern, sonst 'Zucht der Kleinen Chaoten'); fixt C bei naechstem Import-execute; ueberschreibt nie non-null
- FarbschlagWouldRebackfill no-op-Zaehler (Overwrite-Pfad gated auf Julian A/B/C)
- Keine Schema-Aenderung. Gate 133/133 C# + 57/57 python, ef has-pending=No
[god-QA: disjunkt zu qa-regression-Merge; Herkunft-Backfill laeuft nur bei Import-execute = REIMPORT-3 supervised]

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 17:33:58 +02:00
01781f23d6 Merge feature/qa-regression: e2e-Regressionsnetz fuer gehege/wurf-link/herkunft
Some checks failed
CI / Docker Build & Push (push) Has been cancelled
CI / Frontend Tests (Node/Vite) (push) Has been cancelled
CI / Backend Tests (.NET) (push) Successful in 53s
gehege-regression.spec.ts (12 Tests, 6x2 Viewports): /becken→/gehege Redirect (auch /neu),
Nav zeigt Gehege/kein Becken/kein Start, '/' → /rennmaeuse, 404-Link landet auf Tierliste.
WURF-LINK + Herkunft waren bereits in tiere.spec abgedeckt. e2e-only, kein EF.
[god-QA: 0 behind main, single new file]

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 17:32:28 +02:00
55c298ad1f UI-POLISH-1: namenlose Tiere + Leerwert-Konsistenz
- de.ts: nameless = '(ohne Namen)' (neuer Platzhalter-String)
- GerbilsPage: g.name || t.nameless in Karten-Name + Checkbox-Aria
- GerbilDetailPage: g.name || nameless im h2-Header; g.causeOfDeath/notes via || null (leer-string-sicher wie Herkunft)
- AnimalPicker: g.name || nameless im Picker-Button

e2e: +1 nameless-stub in mock-data; 2 neue Tests (Liste + Detail-Header)

Gate: vitest 82/82, e2e 130/130, tsc clean
2026-06-06 17:32:26 +02:00
e1e088f041 QA-REGRESSION-1: GEHEGE-RENAME Regressions-Netz (Redirect /becken→/gehege, Nav-Negativ, Landing /rennmaeuse) 2026-06-06 17:30:31 +02:00
358e30db1f IMPORT-BACKFILL: toleranter KC-Matcher + Herkunft-Backfill + FarbschlagWouldRebackfill-Zaehler
1) TOLERANTER KC-MATCHER (extract.py norm_zucht): trailing \b nach '.' greift nicht
   zwischen two non-word-chars (z.B. nach '.' vor ' '). Fix: r\bv\.\s?d\. (kein \b
   am Ende). Alle Schreibvarianten ('Zucht der Kleinen Chaoten', 'kleinen Chaoten',
   'v.d. Kleinen Chaoten', '[ZdkC]') -> canon 'kleinechaote'. +is_clan_zucht() helper.
   +11 Python-Tests (Regression + neue Varianten). FIX-1-Entscheidungs-Matching
   unberuehrt (canon_pair loest v.d. bereits via split_name_zucht).

2) HERKUNFT-BACKFILL (ImportService.cs, fill-NULL-only): POST-Sweep ueber alle
   DB-Tiere mit OriginBreeder==null && IsResident==true. Leitet OriginBreeder aus
   dem Elterntier (FatherId/MotherId -> OriginBreeder) ab; Fallback 'Zucht der
   Kleinen Chaoten'. NIEMALS ueberschreibt nicht-leeren OriginBreeder. Trocken-Lauf
   zaehlt HerkunftBackfilled; Execute schreibt. Fixt Tier 'C' (OriginBreeder null).

3) FARBSCHLAG-WOULD-REBACKFILL (no-op Zaehler): zaehlt bereits-importierte Tiere,
   bei denen der aktuelle Extraktor einen anderen Farbschlag liefert als in der DB.
   Kein Overwrite (Sicherheitsmechanismus ausstehend auf god/Julian-Freigabe);
   Optionen A/B/C an god gemeldet, Empfehlung: Option B (Timestamp-basiert).

4) ResidencySummary um HerkunftBackfilled + FarbschlagWouldRebackfill erweitert.
   ImportReport-Notizen fuer beide neuen Zaehler.

GATE: 133/133 C#-Tests, 57 Python-Tests, ef has-pending=No.
2026-06-06 17:29:02 +02:00
0b9b03eb2d Merge feature/wurf-link: Wurf auf Tier-Detailseite als Hyperlink
Some checks failed
CI / Backend Tests (.NET) (push) Successful in 52s
CI / Frontend Tests (Node/Vite) (push) Successful in 9m31s
CI / Docker Build & Push (push) Failing after 9s
GerbilDetailPage: Wurf-Feld → <Link to=/wuerfe/{litterId}> wenn litterId+Name aufloesbar,
sonst plain '—' (kein toter Link). +e2e tiere.spec (Link klickbar, navigiert zur Wurf-Detail).
Frontend-only, kein EF. [god-QA: disjunkt zu gehege-rename]

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 17:01:26 +02:00
d4c9be23c8 Merge feature/gehege-rename: Becken→Gehege + Terrarium-Icon + Start-Nav raus, /rennmaeuse = Landing
- UI-Begriff 'Becken' → 'Gehege' (de.ts, Becken-Pages, Abgabe/Hilfe), Route /becken→/gehege+Redirect
- Nav-Icon Badewanne → Terrarium; 'Start'-Nav-Eintrag entfernt
- Index-Route '/' → Navigate /rennmaeuse (Landing Page), HomePage.tsx geloescht
- e2e navigation/becken-kontakte angepasst
Frontend-only, kein EF. [god-QA: disjunkt zu main-Commits, Home-Assertions nur in navigation.spec (selbst gefixt), live-data.spec referenziert kein '/']

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 17:01:09 +02:00
f6bfc0ebab WURF-LINK-Addendum: Herkunft-Zeile zeigt originBreeder + Kontaktlink
- originContactId gesetzt → Link /kontakte/{id} mit Kontaktname (Priorität)
- Sonst originBreeder (Freitext) gesetzt → plain text
- Sonst '—' (bisheriges Fallback)
Behebt: 74 Tiere mit originBreeder sahen '—' obwohl Daten vorhanden

e2e: 2 neue Tests (originBreeder-Text + Kontaktlink)

Gate: vitest 82/82, e2e 126/126, build+tsc clean
2026-06-06 17:00:32 +02:00
3160b66697 WURF-LINK: Wurf-Feld auf Tier-Detailseite als Link zur Wurf-Detailseite (/wuerfe/{id})
- GerbilDetailPage: Wurf-Feld zeigt Link wenn litterId + Name auflösbar; sonst bisheriger '—'-Fallback (kein toter Link)
- e2e: neuer Test verifiziert Link sichtbar + Navigation zu Wurf-Detail

Gate: vitest 82/82, e2e 122/122, build+tsc clean
2026-06-06 16:56:54 +02:00
39767cef0f Merge feature/qa-livedata: QA-LIVE-DATA Live-Test-Suite (50/50 grün)
Some checks failed
CI / Backend Tests (.NET) (push) Successful in 51s
CI / Frontend Tests (Node/Vite) (push) Successful in 9m31s
CI / Docker Build & Push (push) Failing after 8s
live-data.spec.ts (neu, 44 Tests: 22 Phone 390px + 22 Desktop) — tiefer QA-Lauf
gegen echte 325 Tiere/865 Wuerfe; 0 JS-Errors, 0 Page-Overflow, app uebergabebereit.
M-1+M-2 Fix: deterministischer Wurf-ID-Link statt nth, fixtures mainNavigation strict.
Test-only (e2e), kein App-/Backend-/EF-Code. [god-QA: Branch direkt vor main, M-2-aria-label verifiziert]

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 16:50:45 +02:00
162a0fafb1 GEHEGE-RENAME Addendum: /rennmaeuse = Landing Page, 'Start'-Nav entfernt
- AppShell.tsx: Start-Eintrag (/) aus PRIMARY entfernt; /rennmaeuse ist
  nun erste Kachel und Landing Page
- App.tsx: index-Route → <Navigate to="/rennmaeuse" replace>;
  HomePage-Import entfernt
- HomePage.tsx: gelöscht (nicht mehr referenziert, via git wiederherstellbar)
- de.ts: nav.home + pages.home entfernt (nur von AppShell/HomePage genutzt)
- e2e/navigation.spec.ts: HomePage-Assertions → de.pages.gerbils.title
Gate: build ✓  eslint ✓  vitest 82/82 ✓  e2e 120/120 ✓
2026-06-06 16:49:21 +02:00
c26ac5c6dd QA-LIVE-DATA: Fix M-1+M-2 — fixtures.ts mainNavigation strict, live.spec.ts deterministischer Wurf-ID-Link 2026-06-06 16:46:12 +02:00
2bbdfe2b71 GEHEGE-RENAME: UI-Begriff Becken → Gehege + Route /gehege + Icon 🏜️
- de.ts: alle nutzer-sichtbaren 'Becken'-Strings → 'Gehege' (nav, fields,
  titles, buttons, validation, delete, hilfe sections)
- AppShell.tsx: route /becken → /gehege, icon 🛁🏜️ (Wüsten-Habitat)
- App.tsx: <Route path="gehege"> + <Route path="becken/*"> redirect (bewahrt
  Bookmarks; BeckenRedirect leitet Unterseiten 1:1 weiter)
- BeckenPage/DetailPage/FormPage: interne Links /becken → /gehege
- HilfePage.tsx: hartcodierte 'Becken'-Prosa → 'Gehege'
- e2e/becken-kontakte.spec.ts: goto('/becken') → goto('/gehege')
Gate: build ✓  eslint ✓  vitest 82/82 ✓  e2e 120/120 ✓
2026-06-06 16:45:29 +02:00
2c3f342905 QA-LIVE-DATA: Playwright live-data suite (44 Tests, 22 Phone + 22 Desktop, alle gruen) 2026-06-06 16:38:51 +02:00
b165916dfb docs(HUMANQUESTION): Zahlen auf Re-Import #2.5 aktualisiert (325 Tiere/865 Wuerfe/138 Fotos); Enya/Ella/Zac geladen -> nur noch D6 (5 Konflikte) offen
Some checks failed
CI / Frontend Tests (Node/Vite) (push) Successful in 9m33s
CI / Docker Build & Push (push) Failing after 9s
CI / Backend Tests (.NET) (push) Successful in 54s
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 16:19:40 +02:00
797b38df34 docs(HUMANQUESTION): A5b erledigt - Gitea Actions LIVE (Runner aktiv, Tests gruen); neu A5b2: REGISTRY_USER/REGISTRY_TOKEN Secrets fuer Docker-Push-Job
Some checks failed
CI / Backend Tests (.NET) (push) Successful in 53s
CI / Frontend Tests (Node/Vite) (push) Successful in 9m31s
CI / Docker Build & Push (push) Failing after 8s
2026-06-06 16:05:03 +02:00
c34d63e0fd Merge feature/web-6a: Oeffentliche Webseite launch-ready (mobile-first Design, Abgabetiere-Gruppenkarten, Grundseiten-Seeds) [god-QA validated]
Some checks failed
CI / Backend Tests (.NET) (push) Successful in 53s
CI / Docker Build & Push (push) Has been cancelled
CI / Frontend Tests (Node/Vite) (push) Has been cancelled
2026-06-06 16:01:27 +02:00
a2bdf9626c Merge feature/ux-mobile-2: Genotyp-Tabellen horizontal scrollbar (overflow-x-Wrapper + nowrap) + app-main overflow-x:hidden gegen Page-Overflow [god-QA validated]
Some checks failed
CI / Backend Tests (.NET) (push) Successful in 54s
CI / Frontend Tests (Node/Vite) (push) Successful in 9m32s
CI / Docker Build & Push (push) Failing after 10s
2026-06-06 15:43:43 +02:00
0d4b560df8 Merge feature/seed-hell: Backend-Seed 61->66 append-only (IDs 62-66, bestehende ID->Name-Bindung unveraendert, Drift-Regressionstest) [god-QA validated]
Some checks failed
CI / Backend Tests (.NET) (push) Successful in 53s
CI / Docker Build & Push (push) Has been cancelled
CI / Frontend Tests (Node/Vite) (push) Has been cancelled
2026-06-06 15:42:36 +02:00
d116b8d8f1 UX-MOBILE-2: Genotyp-Tabellen-Overflow behoben (scrollbar statt page-overflow)
- BreedingResultView: <table class="genotype-table"> in <div class="genotype-table-scroll"> gewrapped.
- index.css: .genotype-table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch }.
  .genotype-table td { white-space: nowrap } → Tabelle scrollt statt Zellen umzubrechen.
  width: 100% entfernt (Tabelle auto-sized to content).
- index.css: .app-main { overflow-x: hidden } → verhindert, dass breite Inhalte
  den Page-Body horizontal überlaufen lassen (document.scrollWidth == clientWidth).
- e2e/genotype-table.spec.ts (4 Tests): Wrapper sichtbar, Wrapper selbst scrollbar
  (scrollWidth > clientWidth), keine Page-Overflow auf 390px. Beide Viewports.
- Vitest 78 / e2e 106 grün.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-06-06 15:41:59 +02:00
8dfad32918 SEED-HELL v2: 5 CP-*-Hell ans Ende haengen (IDs 62-66, kein ID-Name-Drift)
Erster Ansatz (Rename-in-Place-Shift) wuerde 17 Hand-zugewiesene
Gerbil.ColorVarietyId-FKs still verfaelschen (1 Tier auf CP-Fuchs live
bestaetigt). Stattdessen: 5 neue Eintraege ans ENDE gehaengt (IDs 62-66),
die 61 bestehenden Eintraege unveraendert.

Migration ReseedColorVarietiesGen3g: NUR 5 InsertData (IDs 62-66),
kein UpdateData, kein DeleteData, keine FK-Drift moeglich.

Neuer Test SeedGen3g_existing_varieties_preserve_id_name_binding:
asserts CP-Fuchs (ID 58) bleibt CP-Fuchs, alle 5 neuen IDs 62-66
haben korrekte Namen, Gesamtzahl = 66.

Gate: 127/127 C#-Tests, has-pending-model-changes = No.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-06-06 15:40:57 +02:00
1ee176a24a SEED-HELL: Backend-ColorVariety-Seed 61->66 (GEN-3g CP-*-Hell)
Kevin GEN-3g fuegt 5 CP-*-Hell-Varianten ein (hell = cchmch):
CP-Agouti-Hell, CP-Silberagouti-Hell, CP-Algierfuchs-Hell,
CP-Polarfuchs-Hell, CP-Orangeschimmel-Hell.

Eintraege 0-53 (PEW..CP-Agouti) unveraendert. Eintraege 54-61 werden
durch UpdateData in den bestehenden IDs 55-61 umgeschrieben (EF-Rename-
in-Place-Shift): CP-Silberagouti/Algierfuchs/Polarfuchs/Fuchs/Fuchs-Hell/
Blaufuchs/Orangeschimmel ruecken um +1 bis +4 Positionen. 5 echte Neu-
Eintraege als InsertData in IDs 62-66.

Migration: 7 UpdateData + 5 InsertData, keine DeleteData, kein Datenverlust
ausser theoretischer Gerbil.ColorVarietyId-FK-Drift fuer die CP-Varianten
(ON DELETE SET NULL + Re-Import re-matcht per Name).

Gate: 126/126 C#-Tests, has-pending-model-changes = No.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-06-06 15:36:16 +02:00
a2f5e848d1 Merge feature/qa-2: Verbatim-few-shots (POLISH-2), CI-Flake-Fix, skipUnlessLive+Live-Smoke, Abgabe-Wizard-e2e [god-QA validated]
Some checks failed
CI / Backend Tests (.NET) (push) Successful in 52s
CI / Docker Build & Push (push) Has been cancelled
CI / Frontend Tests (Node/Vite) (push) Has been cancelled
2026-06-06 15:34:38 +02:00
de293904bb Merge feature/ux-mobile-1: FilterPanel (mobil: Suche sichtbar, Filter im Drawer mit Aktiv-Badge; Desktop inline) auf rennmaeuse/wuerfe/anfragen + e2e phone-coverage [god-QA validated]
Some checks failed
CI / Backend Tests (.NET) (push) Successful in 52s
CI / Docker Build & Push (push) Has been cancelled
CI / Frontend Tests (Node/Vite) (push) Has been cancelled
2026-06-06 15:31:24 +02:00
68447896ee QA-2: Fix smart-quote raw-string delimiters in SaleAdPromptBuilder (POLISH-2 BOUNCE) 2026-06-06 15:30:46 +02:00
5f26594a12 Merge feature/gen-3g: 'hell'-Regel (cchm/ch = -Hell-Variante, cchm/cchm = Basis) + CP-Fuchs-Sammelbegriff ratifiziert, Katalog 61->66 (5 -Hell-Restaurationen), Seed regeneriert [god-QA validated]
Some checks failed
CI / Backend Tests (.NET) (push) Successful in 52s
CI / Docker Build & Push (push) Has been cancelled
CI / Frontend Tests (Node/Vite) (push) Has been cancelled
2026-06-06 15:29:26 +02:00
6eb82da90c UX-MOBILE-1: FilterPanel — einklappbare Filter auf Mobil (390px)
Neues FilterPanel-Muster (src/components/FilterPanel.tsx + filterPanel.css):
- Mobil (<768px): Suchfeld immer sichtbar; alle weiteren Filter hinter einem
  'Filter (N)'-Button eingeklappt (Badge = Anzahl aktiver Nicht-Default-Filter).
  Tippen öffnet/schließt den Drawer. 'Filter zurücksetzen' im Drawer.
- Desktop (>=768px): Toggle versteckt, Drawer als display:contents → alle Controls
  inline in der bestehenden .filters-Flexzeile, wie bisher.
Auf GerbilsPage, WuerfeListPage und AnfragenPage ausgerollt.
BeckenPage/KontaktePage nur ein Suchfeld → kein Panel nötig.

e2e: filter-panel.spec.ts (8 Tests, phone+desktop); bestand/tiere/anfragen-Specs
erhalten openFilterPanel-Aufruf vor Drawer-Controls; fixtures.ts +openFilterPanel().
Vitest 78 / e2e 102 grün.

Mobil-Pass (390px, Durchsicht): Hauptproblem behoben. Beobachtete Restpunkte
für god (nicht selbst gefixed):
- .genotype-table in Genetik/Probeverpaarung: Genotyp-Strings können eng werden
- Stammbaum (react-d3-tree SVG): kein explizites mobile Viewport-Handling
- BreedingResultView Genotyp-Detail-Tabelle: ggf. horizontal scrollbar-los

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-06-06 15:28:13 +02:00
0a1e63bec6 Merge feature/import-counter: 31 undatierte Wurfchronik-Eintraege ehrlich als WithoutDate gezaehlt statt als Phantom-created (+latente litterIdMap-FK-Falle entschaerft) [god-QA validated]
Some checks failed
CI / Backend Tests (.NET) (push) Successful in 53s
CI / Docker Build & Push (push) Has been cancelled
CI / Frontend Tests (Node/Vite) (push) Has been cancelled
2026-06-06 15:25:51 +02:00
5b30407257 IMPORT-COUNTER-BUG: undatierte Wuerfe als WithoutDate zaehlen, nicht als Created
31 undatierte Wurfchronik-Eintraege (leeres Datumsfeld) wurden bei jedem Lauf
als littersCreated++ gezaehlt, weil ihr Idempotenz-Key (kein Datum) nie in
existingLitterKeySet stand -- aber kein DB-Insert folgte, da date is DateOnly d
false war. Das verfaelschte Arithmetik und Julians Bericht (752 vs 723).

Fix: undatierte Eintraege werden am Schleifenanfang uebersprungen
(littersWithoutDate++, continue) bevor sie in litterIdMap oder den
Created-Zaehler einfliessen. Execute-Block ohne redundante date-Pruefung.
Neues Feld LitterSummary.WithoutDate; Report-Notiz wenn WithoutDate > 0.

Gate: 126/126 C#-Tests, has-pending-model-changes = No.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-06-06 15:24:55 +02:00
c357a18418 QA-2: Fix Abgabe-e2e Selektoren + ForSale in enc-leer (no Becken-Konflikt) + charakter scoped 2026-06-06 15:22:34 +02:00
791e9f91cc QA-2: Abgabe-Wizard e2e (ForSale-Seed, sale-ad+contracts Mock, abgabe.spec.ts) 2026-06-06 15:16:38 +02:00
97acaf6b10 WEB-6a: Oeffentliche Webseite — Gestaltung & Grundseiten
- SiteRenderer: neues warmes, mobile-first CSS (Georgia-Headings, Scrollnav,
  site-footer-nav mit Impressum/Datenschutz-Links)
- AbgabetiereList: Gruppen-Karten statt Einzelkarten (Becken-Gruppierung,
  Geschlecht-Label, Verfuegbar-Badge, Foto-Strip, pro-Tier-Detail-Zeilen
  mit Farbschlag + geboren-am + Persoenlichkeit/CharacterNote)
- SiteSnapshotService: ForSale-Snapshot um gender, dateOfBirth, characterNote
  erweitert
- Migration AddImpressumDatenschutzPages: Impressum + Datenschutz als
  Platzhalter-Seiten (footer-only, kein navOrder-Eintrag)
- SeedCms: Impressum/Datenschutz auch in HasData (SQLite-Tests)
- Tests: CmsTests angepasst (8 Seiten), 6 neue SiteRendererTests
  (Gruppen-Karte, Geschlecht, Badge, DateOfBirth, Solo-Tier,
   Impressum/Datenschutz, Footer-Links)
Gate: dotnet 131/131 + vitest 78/78 + e2e 94/94 + build clean
2026-06-06 15:15:54 +02:00
efce79b3fa GEN-3g: CP colourpoint het-naming rule — '-Hell' == cchm/ch (breeder C9 answer)
- colourpointName(): A- cchm/ch now yields 'CP-<base>-Hell' (was 'CP-<base>');
  A- cchm/cchm unchanged. Non-agouti branch (Marder/Siam/Zobel/Zobel-Hell)
  unchanged — already used the het token.
- Added 5 new catalog entries: CP-Agouti-Hell, CP-Silberagouti-Hell,
  CP-Algierfuchs-Hell, CP-Polarfuchs-Hell, CP-Orangeschimmel-Hell.
  CP-Fuchs-Hell was already present. Catalog 61 -> 66.
- Regenerated colorVarietySeed.generated.json (66 rows for Pam DATA-2 re-seed).
- Tests: 82 -> 82 (reworded het case) + 1 new GEN-3g describe block. All pass.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-06-06 15:14:23 +02:00