diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a12637..666259d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6336,6 +6336,128 @@ Ferdig og verifisert: teecup_frontend` (gjenskapte også `teecup_api` som vanlig bivirkning). Begge containere boot-et rent, `/health`/`/my-rounds/new` → 200, `teeoff.no` upåvirket. +- **Midlertidige spillere (gjester på frittstående runder): full runde + ferdig -- e-post, navnesplitt, retroaktiv kobling, autofyll, "gjenkjenn + gjest"-oppslag, BYGGET, GRUNDIG SCRATCH-/BROWSERVERIFISERT OG LIVE + (2026-08-03):** brukeren ba om seks ting samtidig (e-post som valgfritt + felt manglet, navnesplitt for-/etternavn, retroaktiv lagring/kobling av + gjeste-runder til en fremtidig konto, automatisk e-post med scorekort+ + statistikk+invitasjon ved fullføring, autofyll fra søkefeltet inn i + gjesteskjemaet, og "gjenkjenn en tidligere registrert gjeste-e-post") og + ba eksplisitt om innspill på hva mer som var lurt. Grundig + kodeutforskning FØR noe ble bygget avdekket presist hva som faktisk + manglet: `guest_email` fantes ALLEREDE i backend (2026-07-26), bare + aldri eksponert i selve "legg til gjest"-skjemaet; `guest_name` var ETT + enkelt tekstfelt brukt i 10+ spørringer. + **Tre load-bærende avklaringer bekreftet av bruker** (AskUserQuestion): + (A) en retroaktivt koblet runde (noen registrerte deg som gjest FØR du + hadde konto) teller IKKE automatisk mot faktisk HCP -- `exclude_from_ + handicap` settes til `true` som default ved kobling, personen må selv + slå den på (samme mekanisme ADR-038 allerede bygget, kun default + snudd for denne ene banen inn). Begrunnelse: en org-turnering sin + eksisterende `link_player_by_email`-presedens (ADR-017) er trygg fordi + org-scoring aldri teller mot faktisk HCP -- frittstående runder GJØR + det (ADR-038), så blind auto-inkludering ville latt en fremmed + påvirke noens HCP uten samtykke. (B) treffer en gjeste-e-post en + EKSISTERENDE konto, opprettes gjesten likevel -- kobles ved neste + innlogging, ikke et eget "denne personen har konto"-forgreiningssteg + (enklere, bevisst valgt fremfor det opprinnelig anbefalte). (C) bygget + i én samlet runde (skjema→backend→frontend→e-post lagvis, samme + disiplin som ellers i prosjektet). + **Migrasjon `052_guest_name_split.sql`:** `round_participant. + guest_first_name`/`guest_last_name` lagt til, `guest_name` beholdt + UENDRET som et auto-synkronisert, lagret "fullt navn" (samme mønster + som `app_user.display_name` synkes fra `first_name`/`last_name`, + 2026-07-25-bugfiksen) -- unngikk å måtte røre alle eksisterende + SELECT-steder. Backfill: "første ord = fornavn, resten = etternavn". + **Retroaktiv kobling** (`app/routers/auth.py`, ny + `_link_round_participants_by_email`, kalt fra BEGGE innloggingsveiene + -- magic-link og passord, samme "kjør trygt på hver innlogging"- + idempotens som `link_player_by_email`): INGEN SECURITY DEFINER-bro + trengs siden `round`/`round_participant` ikke har RLS (ADR-033 + Beslutning A) -- en rett UPDATE er nok. `NOT EXISTS`-vaktet mot en + allerede eksisterende ekte deltaker-rad på samme runde (ville ellers + brutt migrasjon 027 sin UNIQUE-indeks). **Reell bug funnet OG fikset + UNDER scratch-testing:** en første versjon nullet `gender` sammen med + de andre gjeste-feltene ved kobling -- krasjet med en NOT NULL- + violation, siden `gender` er en påkrevd snapshot for ALLE deltakere + (brukt til utslags-rating-oppslag), ikke bare gjester. Rettet ved å la + `gender` stå urørt (uansett låst mot videre endring av `update_ + participant` sin egen `guest_only_fields`-sjekk så snart `user_id` er + satt). + **HTML-e-post** (`app/email.py`, FØRSTE i appen): `_send_sync` fikk en + valgfri `html_body`-parameter (`EmailMessage.add_alternative`, + multipart/alternative -- ekte tekst-fallback bevart). Ny + `send_round_summary_email` -- scorekort som HTML-tabell, statistikk + gradert etter `stat_level`/individuell- vs. delt-ball (kalleren bygger + `stat_lines`, e-post-modulen antar ingenting), ekte magic-link- + innlogging (samme token-mønster som `send_scorecard_invitations`, + ADR/CLAUDE.md 2026-07-28). **Navneformat (ufravikelig regel):** + hilsenen er "Hei {fornavn}," -- direkte adressering, kun fornavn, aldri + fullt navn. Trigget fra en ny `_send_guest_round_summaries`, kalt fra + `complete_round` for hver deltaker med `guest_email` satt -- bygger + scorekortet fra ENTEN `_build_participant_holes` (individuell) ELLER + `_build_side_holes` (delt-ball, ADR-039), gjenbruker eksisterende + hjelpefunksjoner uendret, ingen egen regnelogikk. + **Known-guest-oppslag** (`GET /rounds/guests/known`, statisk rute + plassert FØR `/rounds/{round_id}` i filen, samme mønster som + `/rounds/stats/summary`): bevisst scoped til KUN den spørrende + brukerens EGNE tidligere registrerte gjester (`WHERE r.owner_user_id = + $1`) -- et globalt oppslag ville latt hvem som helst skrive inn en + tilfeldig e-post og se navn/kjønn/HCP en HELT ANNEN organisator har + registrert, en reell personvernlekkasje unngått FØR bygging (flagget + proaktivt til bruker, bekreftet enig). + **Frontend** (`round-detail.tsx`): `AddGuestForm` skrevet om -- separate + Fornavn/Etternavn-felt (etternavn valgfritt), nytt E-post-felt med + debounced known-guest-oppslag + en "Bruk disse opplysningene"-forslags- + boks, `initialName`-prop fra søkefeltet (`AddParticipantForm`s `query`) + autofyller navnefeltene ved "Legg til uten konto (gjest)" via en ny + `splitName()`-heuristikk (samme "første ord/resten" som backfillen). + `EditParticipantPanel` oppdatert til samme to-felts navnestruktur (var + i ferd med å bli en regresjon siden backend ikke lenger godtar + `guest_name` direkte). **Reelt, uforespurt funn fanget under + implementering:** rundeoppsett-veiviseren (`new-round.tsx`) sender + OGSÅ `guest_name` ved opprettelse av spillere i Steg 3 -- ville brutt + hvis ikke oppdatert samtidig; løst med samme splitt-heuristikk direkte + ved innsending (ingen UI-endring i wizarden denne runden, kun + kontraktsrettelse). + **Scratch-verifisert grundig, 41/41 sjekker** (isolert + `teecup_app_scratch`-rolle + isolert scratch-MinIO + engangs API- + container, alle 52 migrasjoner kjørt friskt, samme mønster som hele + prosjektet): navnesplitt+auto-synk, delvis PATCH bevarer det andre + feltet, validering (verken/begge user_id+guest_first_name avvist), + known-guest-oppslag (funnet for egen bruker, IKKE synlig for en annen + organisator -- personvern-scopingen bekreftet presist), full + fullførings-e-post-syklus (dev-log bekreftet både magic-link OG + rundeoppsummering), retroaktiv kobling (user_id satt, gjeste-felt + nullstilt, `gender` BEVART, `exclude_from_handicap=true`, `display_ + name` viser nå kontoens ekte navn), idempotent gjeninnlogging, OG et + eget delt-ball-scenario (foursome) som bekreftet ingen krasj ved + fullføring og korrekt sideoppsummering i e-post-loggen. + **Deretter en FULL, ekte nettleser-gjennomgang** (Chrome DevTools MCP): + hele "+ Medspiller"→"Legg til uten konto"-flyten klikket gjennom med et + navn som ikke fantes -- bekreftet AUTOFYLL fungerte (Fornavn/Etternavn + korrekt splittet), skrev inn en kjent gjeste-e-post og bekreftet + "Vi fant Anna fra en tidligere runde..."-forslaget dukket opp, trykket + "Bruk disse opplysningene" og bekreftet navn/kjønn ble overskrevet + korrekt (HCP forble tomt, siden Anna ikke hadde noen registrert), + sendte inn skjemaet og bekreftet gjesten dukket opp i spillerlisten + UTEN konsollfeil, åpnet rediger-panelet og bekreftet det viser samme + to-felts navnestruktur korrekt forhåndsutfylt. E-postens faktiske + HTML/tekst-innhold generert og inspisert direkte (ikke bare at + utsendingen ble trigget) -- bekreftet riktig "Hei Kari,"-hilsen, + korrekt hull-tabell inkl. et uspilt hull vist som "–", og korrekt + byggede statistikklinjer. + **Rullet ut mot ekte systemer 2026-08-03**, bruker bekreftet + eksplisitt (plan vist FØR migrasjonen, per CLAUDE.md sin ufravikelige + regel): migrasjon 052 kjørt mot ekte `teecup_db` (nye kolonner + bekreftet, backfill verifisert nøyaktig mot de 3 eksisterende gjeste- + radene i produksjon -- "Christer Heitun"→"Christer"/"Heitun", "Sigurd" + →"Sigurd"/null, "Vidar Hoksrød"→"Vidar"/"Hoksrød" -- `test_isolation.sql` + fortsatt 12/12), deretter `docker compose up -d --build teecup_api + teecup_frontend`. Begge containere boot-et rent, `/health`/`/dashboard` + → 200, `GET /rounds/guests/known` anonymt ga korrekt `401` gjennom hele + produksjonsstacken (ikke en rå 404), `teeoff.no` upåvirket. Neste steg: 0a. **Spillerliste-redesign — nå FAKTISK nettleser-bekreftet