Commit Graph

327 Commits

Author SHA1 Message Date
78da534c7c FEAT-13: e2e an strukturierte Kontaktfelder angepasst + 2 Abdeckungstests (drops on rebase once Kelly commits the same patch) 2026-06-06 07:46:51 +02:00
42718606a9 Merge feature/ops-1: TrueNAS deployment (compose + backup sidecar + nginx proxy + prod Dockerfiles), Gitea CI draft, German ops guide [god-QA: 18/18+47/47+e2e 48/48] 2026-06-06 07:42:18 +02:00
d6bf6c6fe3 OPS-1: fix e2e regression -- API_BASE_URL conditional on import.meta.env.PROD
Dev (Vite dev server / e2e mock mode): falls back to 'http://localhost:5179' so
Playwright route interception on http://localhost:5179/** keeps working.
Production (npm run build -> PROD=true): falls back to '/api' so nginx proxy
strips the prefix without any hostname baked in at build time.
VITE_API_BASE_URL (set by Aspire in dev, injected LAN IP) always wins over both.

Evidence: npm run e2e 48/48 PASS (mock mode, both viewports).

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-06-06 07:39:33 +02:00
04f9e087aa Merge feature/feat-12a-backend: provider-agnostic AI sale-ad endpoint (Gemini/Groq/Mistral/Ollama via OpenAI-compat, env config, graceful 503) [god-QA: 37/37] 2026-06-06 07:39:26 +02:00
95ecb1c0ee FEAT-12a: provider setup docs (env vars per provider incl. TrueNAS compose placement) 2026-06-06 07:37:42 +02:00
36c97e8a7a FEAT-12a: tests - prompt assembly, 503-unconfigured matrix, stub-provider parsing/auth, completions-URL config matrix (Gemini/Groq/Mistral/Ollama) 2026-06-06 07:37:42 +02:00
d9e5a757e9 FEAT-12a: POST /gerbils/sale-ad endpoint (503 AiKeyMissing when unconfigured, 502 AiUpstreamError) + DI wiring 2026-06-06 07:37:42 +02:00
f6bb13ca2f FEAT-12a: provider-agnostic sale-ad AI core - AiOptions (env-only), German prompt builder w/ few-shot, OpenAI-compatible chat-completions client (no SDK) 2026-06-06 07:37:42 +02:00
a221e366e6 FEAT-13: singular-aware contract count text (1 Vertrag / n Vertraege)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 07:34:25 +02:00
3ec4f660b0 FEAT-13: Abgabe wizard (/vertraege/neu, 4 steps, ?tiere= prefill), Vertraege list w/ download+delete, /einstellungen Zuchtprofil form, contracts/settings API clients, nav entries, detail-page entry point + replace orphaned contactInfo with email/phone/address across Kontakt pages
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 07:34:25 +02:00
daa6683405 FEAT-13: SaleContract + BreederSettings entities (additive migration, join table justified in code docs), /contracts + /settings/breeder-profile Minimal-API endpoints w/ Abgabe-completion transaction + SQLite-backed endpoint round-trip tests (21/21)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 07:34:25 +02:00
69a0279bb7 OPS-1: TrueNAS compose, backup sidecar, Gitea CI draft, ops docs
deploy/truenas/compose.yaml:
  - 4 services: db (postgres:17), api (.NET), frontend (nginx), backup sidecar
  - Named volumes as NAS bind-mounts (paths configured in .env)
  - Healthchecks: db pg_isready, api /health, frontend waits on api
  - ANTHROPIC_API_KEY placeholder for FEAT-12a AI stub

deploy/truenas/.env.example: POSTGRES_PASSWORD, PORT, REGISTRY, dataset paths

deploy/truenas/scripts/:
  - entrypoint.sh: installs daily 03:00 cron, starts crond in foreground
  - backup.sh: pg_dump -> .sql + tar czf photos -> .tar.gz + rotation
  - restore.sh: psql < dump + tar xzf photos; confirmation prompt (-f to skip)
  Predecessor logic (commit 6a37f9e) translated from PowerShell to POSIX sh
  for Alpine containers. Same pg_dump/restore semantics, same KEEP_DAYS rotation.

.gitea/workflows/ci.yml (DRAFT -- inactive until Julian confirms Actions):
  dotnet test + npm test/build on push/PR to main;
  docker build+push to Gitea registry on main push only

docs/ops.md:
  German ops guide -- architecture diagram, first-install checklist,
  start/stop/update commands, backup runbook (manual + auto), ZFS-snapshot
  layering strategy, CI activation steps, open questions, troubleshooting table

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-06-06 07:31:19 +02:00
2f2e5b1f56 OPS-1: Dockerfiles (net10 API + nginx frontend) + production config
- GerbilManagerWebAPI/Dockerfile: net7->net10 multi-stage; build context=repo
  root (includes ServiceDefaults); port 8080 (.NET 10 container default)
- gerbil-manager-web/Dockerfile: drop VITE_API_BASE_URL build-arg; nginx proxies
  /api/* to api:8080 (strip prefix), /scalar, /openapi/ -- one published port 80
- gerbil-manager-web/src/api/client.ts: default API_BASE_URL /api (relative),
  no hostname coupling at build time; Aspire still injects absolute LAN URL in dev
- GerbilManagerWebAPI/Program.cs: run EF Migrate() at startup always (not Dev-only)
- GerbilManager.ServiceDefaults/Extensions.cs: expose /health + /alive in all
  environments (compose healthcheck requires them in Production)

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-06-06 07:31:19 +02:00
adea82a0e7 QA-1: document e2e usage (mock/live modes, viewports) in web README 2026-06-06 07:21:27 +02:00
ebd61d73a5 QA-1: smoke specs - Navigation, Tiere CRUD+Tabs, Becken/Kontakte+409, Wuerfe+Jungtier, Probeverpaarung+SCHECKE-Warnung, Stammbaum re-root+print, Statistik (24 flows x 2 viewports, German assertions) 2026-06-06 07:16:52 +02:00
ec5e755e72 QA-1: stateful in-memory mock API per route interception (DATA-2 contract: Gridify paging, camelCase DTOs, 409 delete-conflicts) + fixtures 2026-06-06 07:16:52 +02:00
8d7999c4a5 QA-1: Playwright e2e harness - config (phone 390px + desktop projects, mock/live via E2E_BASE_URL), npm run e2e, vitest excludes e2e/ 2026-06-06 07:16:43 +02:00
c9723d2fc8 Merge feature/feat-12a: Abgeben flow — multi-select ForSale, /abgabe group composer, paste-package, AI stub [god-QA: 47/47 + build] 2026-06-06 07:16:26 +02:00
07dd5c9b8e FEAT-12a: multi-select bulk 'Zur Abgabe stellen' on the Tiere list 2026-06-06 07:13:30 +02:00
aa79f9dbe5 Revert OPS-1 Windows-plan commits (dada3af, 6a37f9e): superseded by TrueNAS deployment target; re-landed on main against GIT-3 — content preserved on Dwight's branch-to-be 2026-06-06 07:12:20 +02:00
3b3497079b Merge feature/feat-13: Abgabevertrag generator phase A (template + pure OpenXml generator + 10 tests) [god-QA: 18/18] 2026-06-06 07:11:30 +02:00
dada3af968 OPS-1: startup scripts, autostart task, backup task, ops README, production config
- appsettings.Production.json: Photos:RootPath -> C:\gerbil-data\photos so
  photo files land on a stable host path when ASPNETCORE_ENVIRONMENT=Production
- Start-GerbilManager.ps1: creates data dirs, sets Production env, launches
  AppHost minimised; saves PID for Stop script
- Stop-GerbilManager.ps1: kills AppHost + Vite node processes by PID / port
- Register-AutoStart.ps1: Windows Scheduled Task on user logon (RunLevel Highest)
- Register-BackupTask.ps1: daily 03:00 Scheduled Task for Backup script
- deploy/README.md: Julian ops guide — start/stop commands, phone URL, DHCP
  reservation, firewall rule (Public-profile Wi-Fi), backup/restore procedures,
  prerequisites checklist, troubleshooting table (German)

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-06-06 07:11:09 +02:00
6a37f9e46e OPS-1: fix backup/restore scripts — ASCII-only + array coerce for Count
- Replace em dashes (UTF-8 multi-byte) with ASCII hyphens; PowerShell 5.1
  reads ps1 files as CP1252 by default so any non-ASCII in source causes
  cascading parse errors
- Extract POSTGRES_PASSWORD from container env (Aspire uses scram-sha-256;
  peer/trust auth does not work) and pass as PGPASSWORD env var to pg_dump
  and psql in both Backup and Restore scripts
- @() wrap on Get-ChildItem result to force array before .Count under
  Set-StrictMode -Version Latest (single-item returns a bare object in PS5)
- Restore-test evidence: 73 ColorVarieties -> DELETE 12 -> 61 -> pg_restore
  -> 73 confirmed (run 2026-06-06 07:09 against postgres-gatkzrgq)

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-06-06 07:09:53 +02:00
44f306d18f FEAT-12a: Abgabe page — Becken-default grouping + per-group listing composer, clipboard/zip export, AI stub 2026-06-06 07:09:48 +02:00
cbe77c927a FEAT-13: ContractGenerator (pure OpenXml, embedded template, per-animal table cloning) + BreederProfile/ContractData records + 10 xUnit tests incl. schema validation & PII guard
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 07:09:07 +02:00
e4b7558abd FEAT-12a: ForSale scaffolding — status+ForSale, abgabe strings, /abgabe route+nav, sale-ad API stub, detail action, jszip 2026-06-06 01:07:43 +02:00
188b33618e DATA-2: amendments — GerbilStatus.ForSale, Contact structured fields, 73-variety seed
- GerbilStatus += ForSale ("Abzugeben", FEAT-12 sale listing); enum-as-string, no DB change.
- Contact: contactInfo -> structured email/phone/address (FEAT-13 sale contracts); name/notes kept.
- ColorVariety seed 18 -> 73 from Kevin's GEN-2 colorVarietySeed.generated.json (18 frozen first).
- Regenerated InitialCreate migration (Contacts email/phone/address cols, 73 seed rows).
2026-06-06 01:07:19 +02:00
f3b1ecb7a3 FEAT-13: Abgabevertrag placeholder template from her sample contract (18 {{tokens}}, PII scrubbed incl. docProps/mailto-rel, animal photos removed, Zucht logo kept, boilerplate verbatim)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 01:03:25 +02:00
7627468b82 DATA-2: optional list params + normalize frontend's '==' Gridify operator
- GridifyParams wrapper: nullable page/pageSize/filter/orderBy so list endpoints
  work with no query params (Gridify's non-nullable int Page made [AsParameters]
  treat them as required -> 400). Defaults page=1,pageSize=20.
- Normalize incoming filter '==' -> '=' : the frontend gridify.ts emits '==' for
  equals (its convention) but Gridify's equals is '='. Safe (values are escaped;
  != >= <= =* contain no '=='). Fixes status==Active (frontend default that 500'd).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 01:00:35 +02:00
c937b6d5a8 GEN-2: add generated ColorVariety seed (73 rows: name, canonicalGenotype, sortOrder, image) for DATA-2
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 01:00:33 +02:00
6cc007ba55 GEN-2: surface Farbschlag images (FarbschlagImage component) in breeding results, animal detail, form picker
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 00:58:28 +02:00
7ea2f97e72 FEAT-8b: bake Julian's authoritative Wurfchronik semantics into the extractor
- survivedToGoHome: unlabeled Tabelle1 col E detected positionally; value-
  adaptive row parsing recovers it from schema-shifted Tabelle2 rows too
  (118 recovered, 79 confirmed by the E=F-TG-s identity)
- breakdown G -> males/females/stillborn/diedLater ('s' = died before Abgabe)
- validation: E = F - TG - s; 113 mismatches as German review-report warnings
- (name, Zucht) canonicalisation: [brackets] == of/von suffix ([ZdkC] ==
  von den Kleinen Chaoten); Zucht = dedup discriminator (0 splits in data)
- animal->litter matching via DOB+(Vater,Mutter): 95 high-confidence,
  40 date-only, 9 ambiguous; litterRef in animals.json
- regenerated report: 889 raw -> 574 unique (279 dated), 32 conflicts

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 00:56:14 +02:00
a9778ad1d2 GEN-2: expand Farbschlag catalog 18->73 (baseportal.de) + images + collision-aware tests
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 00:55:35 +02:00
263ba32e3c DATA-2: fresh Npgsql InitialCreate migration + ColorVariety seed (18)
8 tables (Gerbils, Litters, Contacts, Enclosures, ColorVarieties, GerbilPhotos,
HealthRecords, WeightRecords); enums as text columns; ColorVariety HasData seed
of the 18 GEN-1 base varieties. Replaces the prior pre-DATA-2 InitialCreate.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 00:54:56 +02:00
180d53b203 DATA-2: new schema entities + Minimal API endpoints + Scalar + DAL teardown
- Entities: Breeder->Contact, +Enclosure/ColorVariety/GerbilPhoto/HealthRecord/WeightRecord;
  Gerbil expanded (single Genotype text col, Status/Gender enums-as-string, FK ids,
  ImportSource/ExternalRef provenance); Litter Strength->TotalBorn +ExpectedGoHomeDate/Notes.
  ColorVariety HasData seed = 18 from GEN-1 catalog. Gerbil<->Litter cycle handled
  (SetNull/Restrict). Enums stored as strings.
- Minimal API (no controllers): Endpoints/*.cs MapGroup+TypedResults for gerbils, litters,
  contacts, enclosures, color-varieties, health/weight-records, inbreeding (converted from
  controller, same routes/shapes), photos (Oscar contract: GET array/POST multipart/DELETE,
  url /photos/files/{fileName}). Gridify paged {items,totalCount,page,pageSize}, camelCase,
  409 conflict-deletes, flat FK ids, litter parent-gender validation (400 {code,...}).
- Scalar replaces Swashbuckle (AddOpenApi/MapOpenApi + MapScalarApiReference at /scalar);
  launchUrl swagger->scalar. GenericRepository/UnitOfWork/Converters deleted; DbContext direct.
- InbreedingService reads real FK props now; pure calculator + 8 tests untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 00:53:49 +02:00
a47fbef785 FEAT-7: AppShell 'Mehr' overflow nav (phone: 4 tabs + Mehr sheet; desktop: all 7) + de.nav.more
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 00:47:07 +02:00
7ab463d47e UI: hand-drawn gerbil favicon (sitting Agouti, warm palette, tufted tail) 2026-06-06 00:46:46 +02:00
27299e225c HOTFIX: useMutation.run returns MutationOutcome (no throw); sweep all 7 call sites + README convention
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 00:44:56 +02:00
3476b71525 FEAT-7: thin population curve to <=60 points so the line is not beaded over long date ranges
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 00:43:48 +02:00
34911fdee1 FEAT-7: Statistik page - Wuerfe/Jahr + avg Wurfstaerke bars, Farbschlag h-bars (FEAT-4 chip colors), Bestandsentwicklung line, Verluste/Jahr + /statistik route & nav entry (Mehr overflow follows via Kevin)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 00:41:21 +02:00
1b776cd994 FEAT-8b: spreadsheet import tooling (stages 1-2) + review report
tools/import/ (Python, zero-dep migration tooling, not product code):
- xlsx_util.py: dependency-free .xlsx reader (shared strings, cells, drawing anchors)
- genotype.py: notation -> frozen 8-locus mapping + verbatim rawGenotype + unmappedTokens; '-' -> '?'
- extract.py: 10 Stammbaum charts + Wurfchronik -> animals.json/litters.json + anchor-mapped photos;
  dedup on normalise(name)+DOB -> German review-report.md (no DB load)

Run: 889 raw -> 587 unique animals, 24 conflicts, 310 ambiguous, 123 photos, 752 litters.
Output gitignored except review-report.md. Re-runnable per file (Wurfchronik Teil2+).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 00:40:54 +02:00
016b5a1521 FEAT-7: statistics aggregation module - litters/year, avg litter size, Farbschlag distribution, population curve, losses (9 tests)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 00:37:58 +02:00
c6699a9592 FEAT-3: fix unhandled ApiError rejections (catch in form submits + dev unhandledrejection guard, ApiError carries path)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 00:36:14 +02:00
e76554342b FEAT-3: Zuchtpaar-Übersicht tab (derive pairs from litters) + ?vater/&mutter pair prefill in Probeverpaarung
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 00:32:44 +02:00
79f260d62e FEAT-3: Wurf detail workspace (parents, juveniles, Jungtier erfassen prefill, expected Farbschlag via breed)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 00:31:19 +02:00
74ac6ddb5a FEAT-4: sync inbreeding DTO to FEAT-1b InbreedingResult + anchor root card left so parents are visible on phone at load
Verified end-to-end against a DATA-2-contract mock (5-gen family, shared ancestor): phone/desktop, re-root, lazy expand, zoom/fit, print Ahnentafel, 404 state.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 00:30:14 +02:00
d3550bbc16 FEAT-3: Wurf create/edit form (parent pickers, auto +35d go-home date, validation)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 00:29:52 +02:00
784d3d3f40 FEAT-3: Würfe list page (year filter, sort by date, paging, parent names)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 00:28:50 +02:00
cd4328cef8 FEAT-6: wire tab content into animal detail (Fotos/Gesundheit/Gewicht) + profile photo in header + tab styles 2026-06-06 00:28:31 +02:00
87250ba007 FEAT-3: litter type+CRUD, Zucht strings, /wuerfe nested routes (retire LittersPage)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 00:27:29 +02:00