c35a6eca04
GEN-3c: fix 'Unbekannter Farbschlag' — unknown=wildcard in matches() + E-pair-aware family fallback (eef=Fuchsschimmel)
2026-06-06 10:45:16 +02:00
2e20df624f
GEN-3c: unknown allele displays as '-' (storage stays '?'); parser accepts '-' and skips fully-unknown tokens; de.ts hints
2026-06-06 10:45:15 +02:00
a57b481a7e
Merge feature/inbox-2: POST /api/requests/{id}/draft (AI German reply draft, never auto-send), extract OpenAiChatClient to Ai/, privacy stripping, 8 tests [god-QA pending]
2026-06-06 10:37:56 +02:00
27424c574f
Merge feature/feat-14c: Charakterbogen as preferred AI character source (suppress admin notes, weave traits to prose), +4 tests [god-QA pending]
2026-06-06 10:37:45 +02:00
fd28b2a954
INBOX-2: 8 Tests - Stripping, Prompt-Privacy (keine Mailadresse zum Anbieter), 503, Endpoint-Round-Trip mit Stub (Entwurf gespeichert+geliefert); ApiFactory.ConfigureTestServices-Hook (init-Property, xUnit-fixturefest)
2026-06-06 10:36:02 +02:00
8aab9d34f7
INBOX-2: POST /api/requests/{id}/draft - deutscher KI-Antwortentwurf (Datenminimierung: nur Anfragetext+ForSale-Liste, Zitat/Signatur-Stripping, 503 AiKeyMissing / 502 Upstream, speichert DraftReply)
2026-06-06 10:36:02 +02:00
6dabb5572c
INBOX-2: extract provider-agnostic OpenAiChatClient from SaleAdService (shared AI wire, public surface unchanged)
2026-06-06 10:36:01 +02:00
36db013b76
Merge feature/gen-3b: genotype.py+extract.py normalization (Uw→G, Sls, flags), conflicts 32→27, Gerbil.IsDeaf additive migration [god-QA pending]
2026-06-06 10:32:57 +02:00
60d034cde4
Merge feature/gen-3a: Uw=G+G-display, Sls 2nd locus+lethal, flag tolerance, Schimmel catalog fix (no Schwarzschimmel, efef=Orangeschimmel) [god-QA pending]
2026-06-06 10:32:52 +02:00
5ec04984c9
FEAT-14c: Charakterbogen im Sale-Ad-Prompt - Traits+Notiz als bevorzugte Charakterquelle (Notizen-Fallback), Webe-Regel statt Stichwortliste im Systemprompt; 4 Tests
2026-06-06 10:29:38 +02:00
e2fd32ea12
GEN-3a: test that Uw input renders as canonical G (never echoed back)
2026-06-06 10:27:08 +02:00
2f089a902d
GEN-3b: import notation normalization (Uw=G, Sls, deaf flag, tags)
...
genotype.py:
- Uw/uw aliased to G/g (same locus) so the D2 conflict group + pure-Uw
cases stop being conflicts (Gg == Uwuw).
- Sls/WP recognized as a SECOND spotting locus (S(l)s(l)=WP het); carried
into mapped8locus alongside Sp (Sp+Sls = Superschecke).
- dea/Dea/taub/hörend -> hearing/deaf phenotype FLAG (not a locus).
- WFNZ/RV/GV/DP -> provenance/breeding tags (not genotype, not conflicts).
- test_genotype.py: zero-dep unit tests for all four.
extract.py: surface deaf+tags on animals; dedup conflict detection now
compares the NORMALIZED genotype key (mapped8locus) instead of the raw
string, so Uw=G no longer triggers a conflict. Result: Konflikte 32 -> 27,
Zucht-Splits stays 0. Dedup identity = name + DOB + Zucht.
Backend: Gerbil.IsDeaf (bool?) + additive migration AddGerbilDeafFlag
(has-pending-model-changes clean) + GerbilDto/GerbilInput round-trip.
ImportService sets IsDeaf from animal.deaf and preserves Sls + tags + deaf
in RawImportData (kept out of the 8-locus compact Genotype contract until
GEN-3a adopts them).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-06 10:26:01 +02:00
7aac59f3e5
GEN-3a: de.ts warning texts (SLS_LETHAL/SUPERSCHECKE_DEAF) + genetics tests (Uw alias, Sls het/lethal, Superschecke, flag tolerance, Schimmel fix)
2026-06-06 10:25:48 +02:00
a0b720df73
GEN-3a: Schimmel catalog fix (breeder C5) — remove Schwarzschimmel, efef base=Orangeschimmel, Silberschimmel wins efef-gg, +CP-Orangeschimmel; regenerate ColorVariety seed
2026-06-06 10:25:48 +02:00
1e7dc8f91d
GEN-3a: Uw=G alias, second spotting locus Sls (SlSl lethal), Sp×Sls Superschecke, flag/metadata token tolerance (dea/WFNZ/DP/RV/GV)
2026-06-06 10:25:48 +02:00
c93c24f37c
docs(HUMANQUESTION): C5 answered — no Schwarzschimmel (catalog error); correct Schimmel types (efef=Orange/efef pp=Rotaugen/efef gg=Silber/cchm efef=CP-Orange) + source note
2026-06-06 10:11:48 +02:00
bd9cc83205
docs(HUMANQUESTION): C4 answered — Wurfchronik Teil 2 exists, being revised, will be imported when delivered
2026-06-06 10:08:50 +02:00
8d0fc43c0a
docs(HUMANQUESTION): C3 answered — auto-merge OK but require matching Zuchtname (Name+DOB+Zucht = same animal)
2026-06-06 10:07:46 +02:00
98596b5586
Merge feature/feat-13-followup: /hilfe Vertrag+Zuchtprofil sections + verified Abgabe->wizard handoff [god-QA: 80/47/e2e 64]
2026-06-06 10:06:28 +02:00
9013ff488e
docs(HUMANQUESTION): C2 answered — '-' = unknown allele (confirmed)
2026-06-06 10:06:28 +02:00
2a1c4a9eb7
docs(HUMANQUESTION): C1 answered (Uw=G, Sls=WP, DP=Darkpatch, Dea/dea=hearing/deaf, WFNZ/RV/GV=annotations); D2 conflict group resolved
2026-06-06 09:59:33 +02:00
d79f039b8b
FEAT-13-Followup: /hilfe sections for Abgabevertrag wizard + Zuchtprofil (du-Form, de.ts-referenced labels) + finish-step in Abgabe section
...
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-06 09:58:04 +02:00
8202dfc0e4
Merge feature/inbox-3: Gmail SMTP send + reply threading (In-Reply-To/References/Re:), MailNotConfigured/MailAuthFailed handling [god-QA: 80 + snapshot clean]
2026-06-06 09:51:32 +02:00
68366ad8c9
INBOX-3: SMTP send + Gmail threading (POST /api/requests/{id}/send)
...
- IGmailMailSender (mockable) + MailKit GmailMailSender (smtp.gmail.com:587 STARTTLS, App
Password). SendReplyService builds a threaded reply: In-Reply-To = original Message-Id,
References = stored chain + original (deduped), Subject = 'Re: ' (no double-prefix); sends,
then sets Status=Answered + AnsweredAt + stores sent body in DraftReply. Never auto-sends.
- POST /api/requests/{id}/send {body}: 200 updated RequestDto; 404 unknown; 503 MailNotConfigured;
502 MailAuthFailed (UI hint: re-enter App Password). No entity change (no migration).
- Tests (fake SMTP): threading headers, Answered transition, no-double-Re, not-configured +
auth-failure keep status; BuildMimeMessage header mapping. Live send gated on App Password.
2026-06-06 09:50:24 +02:00
dcf849cfa7
Merge feature/inbox-0: Gmail request inbox backend (MailKit reader, Request entity, MailSettings, sync/triage endpoints) [god-QA: 75 + snapshot clean]
2026-06-06 09:44:42 +02:00
958a2dbac0
INBOX-0: regenerate AddRequestsAndMailSettings migration after rebase onto WEB-0 (clean snapshot: CMS + INBOX, Up adds only Requests+MailSettings)
2026-06-06 09:43:01 +02:00
5d7cbc66bf
INBOX-0: Gmail request inbox backend (MailKit) + Request entity + sync/triage endpoints
...
- Request entity (GmailMessageId unique, ThreadId, threading headers, From*, Subject, BodyText,
ReceivedAt, Status enum-as-string New|InProgress|Assigned|Answered|Abandoned, AssignedContactId? FK,
DraftReply?, AnsweredAt?). MailSettings singleton (GmailAddress, AppPassword ENCRYPTED via Data
Protection, PollInterval, Folder, LastUid). Migration AddRequestsAndMailSettings.
- IGmailMailReader (mockable) + MailKit GmailMailReader (imap.gmail.com:993 SSL, envelope+X-GM-THRID
+body). RequestSyncService: dedup on Message-Id, track LastUid. MailKit 4.17.0.
- Endpoints: POST /api/requests/sync, GET /api/requests (Gridify, filter status), GET /api/requests/{id},
PUT triage (status+assignedContactId), GET/PUT /api/mail-settings (App Password never returned).
- Tests (in-memory DB + canned reader): sync dedup/idempotency/config-guard, HTTP sync->triage->assign,
mail-settings secrecy. + gitignore the runtime photo-storage/ dir (god housekeeping).
2026-06-06 09:39:36 +02:00
84181ed74d
docs: HUMANQUESTION.md — fully German + 'nicht selbst bearbeiten, an Michael antworten' banner at top (wife reads this)
2026-06-06 09:37:25 +02:00
d510b0f822
Merge test/search-variations: 9 backend search-variation tests (all green) [god-QA: 70]
2026-06-06 09:33:51 +02:00
3716dcb1f3
test: SearchVariationsTests — 9 search variations (contains, case-insensitive, separator-insensitive nameSearch, umlauts, OriginBreeder filter, /breeders distinct, paging, combined). Fills the gap where SEARCH-1's tests never reached main.
2026-06-06 09:33:40 +02:00
d6e35f40ec
Merge feature/search-2b: Herkunft filter -> originBreeder + /gerbils/breeders; name search -> nameSearch (separator-insensitive) [god-QA: 47/build/e2e 62]
2026-06-06 09:27:40 +02:00
70f7c88419
Merge feature/web-0: CMS model (Site/Page/Block/Media) + /api/site-snapshot (Abgabetiere auto from ForSale) + Page/Block CRUD [god-QA: 61]
2026-06-06 09:27:12 +02:00
acd7f4c386
docs: HUMANQUESTION.md — open questions/data requests for Julian + wife (incl. 32 conflict animals, blockers per item)
2026-06-06 09:25:32 +02:00
f73ac0d4d8
WEB-0: CMS endpoint tests — snapshot shape/nav, Abgabetiere resolves ForSale (Becken group), block CRUD+reorder (SQLite host)
2026-06-06 09:21:20 +02:00
94f055f9bf
WEB-0: CMS content model + /api/site-snapshot + Page/Block CRUD
...
- Entities: Site (singleton, navOrder JSON), Page (slug/title/seoDescription/status enum),
Block (single table, Type enum + Data JSON; RichText=Markdown), Media. Migration
AddCmsEntities, seeds 6 Jimdo-mirror pages (placeholder Heading each; abgabetiere also an
auto AbgabetiereList block) + Site singleton nav.
- GET /api/site-snapshot: one JSON doc (site nav + pages + ordered blocks {id,order,type,data});
AbgabetiereList(auto) resolved from live ForSale gerbils -> {name, farbschlag, group(=Becken),
photos[urls], aiSaleText:null} (no price per god). SiteSnapshotService.
- CRUD: GET/POST/PUT/DELETE pages; add/update/delete blocks; PUT .../blocks/order reorder.
Block type allowlisted by enum; data validated as JSON object.
2026-06-06 09:21:20 +02:00
cab8c133c8
SEARCH-2b: e2e mock /gerbils/breeders + nameSearch/originBreeder seed; Herkunft + separator-insensitive smokes [QA-1]
2026-06-06 09:15:55 +02:00
13ff97a12b
Merge feature/feat-14b: Charakterbogen UI (checkbox traits + note) on detail + Abgabe composer, feeds AI sale-ad [god-QA pending result-gate]
2026-06-06 09:15:55 +02:00
681e8c28fb
SEARCH-2b: Herkunft dropdown -> originBreeder + GET /gerbils/breeders; name search -> nameSearch (client-normalized)
2026-06-06 09:15:55 +02:00
ba81f48e0f
Merge feature/feat-14a: Charakterbogen backend (Gerbil.CharacterTraits + CharacterNote) + sale-ad request extension [god-QA: 58]
2026-06-06 09:15:36 +02:00
3afb04f646
FEAT-14a: Charakterbogen on Gerbil (traits + note) + sale-ad request extension
...
- Gerbil.CharacterTraits (List<string>, JSON text column, opaque labels) + CharacterNote
(string?). On GerbilDto + Input; round-trips on GET/POST/PUT. Additive migration.
- SaleAdAnimal gains Traits (German labels) + CharacterNote; prompt builder emits
"Charakter: …" + "Charakter-Notiz: …" lines for the AI Verkaufstext.
- Tests: traits/note round-trip (POST->GET via SQLite host), empty-default, prompt inclusion.
2026-06-06 09:10:30 +02:00
5d8bbfa93b
FEAT-14b: Charakterbogen on animal detail (persist) + Abgabe composer; feed traits+note into sale-ad; e2e smoke
2026-06-06 09:08:54 +02:00
5b11780074
FEAT-14b: trait vocabulary (de.character), Gerbil/sale-ad types, Charakterbogen component
2026-06-06 09:08:54 +02:00
f858a02f50
Merge feature/search-1: separator-insensitive NameSearch field + OriginBreeder (Herkunft) filterable string from import + /gerbils/breeders distinct endpoint
2026-06-06 09:03:32 +02:00
09f11cb4e3
SEARCH-1: separator-insensitive NameSearch + OriginBreeder (Herkunft) filter
...
- Gerbil.NameSearch (lowercase, strip whitespace/.-_) auto-synced in ApplicationContext
.SaveChanges; Gridify-filterable so 'clan kleine chaoten' matches 'Clan-Kleine-Chaoten'
(client strips separators the same way). GerbilSearch.Normalize shared helper.
- Gerbil.OriginBreeder (free-text Herkunft) on DTO+Input, set by the FEAT-8 import from the
source Zucht (imported animals have no OriginContact). Gridify-filterable.
- GET /gerbils/breeders: distinct non-empty OriginBreeder values for the Herkunft dropdown.
- Migration AddSearchFields (+ NameSearch backfill SQL for existing rows).
2026-06-06 09:01:12 +02:00
45b213e11d
Merge feature/search-2: Herkunft filter dropdown on Tiere list + live-search UX confirmed [god-QA: 55/47/e2e 60]
2026-06-06 09:00:21 +02:00
38b9717ad2
SEARCH-2: Herkunft (originContactId) filter dropdown on Tiere list + e2e smoke; name-search field behind NAME_SEARCH_FIELD for SEARCH-1 normalized swap
2026-06-06 08:58:34 +02:00
0ee2b53b24
Hotfix: gerbil search contains operator — name=*a not name=*a* + mock mirrors real Gridify [god-QA: 47 unit + 58 e2e; live: name=*a -> 203 hits]
2026-06-06 08:52:08 +02:00
459c66bc3e
Hotfix: gerbil search contains operator — drop trailing '*' (Gridify =* is contains; name=*a not name=*a*) + e2e mock mirrors real Gridify
2026-06-06 08:52:02 +02:00
0cee3e2710
Merge feature/polish-1: canonical Gridify '=', InvalidParentGender German message, Abgabe-abschliessen->wizard wiring, de.ts sweep, e2e mock accepts both operators [god-QA: 55/47/58]
2026-06-06 08:18:08 +02:00
385cccb352
POLISH-1: e2e mock accepts canonical '=' (and legacy '==') equals operator [QA-1 coordination]
2026-06-06 08:16:57 +02:00