From 0b6e7e42192022b692f63e1f8338e22702f90950 Mon Sep 17 00:00:00 2001 From: Erol Haagenrud Date: Sat, 18 Jul 2026 15:54:40 +0200 Subject: [PATCH] =?UTF-8?q?Live=20n=C3=A5=20=E2=80=94=20kun=20teecup=5Ffro?= =?UTF-8?q?ntend=20redeployet,=20begge=20containere=20friske,=20teeoff.no?= =?UTF-8?q?=20up=C3=A5virket.=20Statusdokumentene=20er=20oppdatert=20med?= =?UTF-8?q?=20rot=C3=A5rsaken=20(nestet=20
=20=E2=86=92=20nettleseren?= =?UTF-8?q?=20slo=20sammen=20skjemaene=20=E2=86=92=20=C2=ABS=C3=B8k=C2=BB?= =?UTF-8?q?=20submittet=20det=20ytre=20=C3=B8kt-skjemaet=20som=20ekte=20si?= =?UTF-8?q?denavigasjon=20=E2=86=92=20vasket=20bort=20org-parameteren).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .claude/settings.local.json | 3 +- CLAUDE.md | 49 ++++++++++++++++++++-- FEATURE_BACKLOG.md | 48 ++++++++++++++++++++- frontend/components/tournament-program.tsx | 28 ++++++++++--- 4 files changed, 118 insertions(+), 10 deletions(-) diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 456686b..77730a0 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -247,7 +247,8 @@ "Bash(awk -F: '$1>=782 && $1<=980')", "Bash(python3 -)", "Bash(python3 -c \"import json,sys; d=json.load\\(sys.stdin\\); print\\(len\\(d\\), 'facilities'\\); print\\(d[:2]\\)\")", - "Bash(rm -f /tmp/claude-1000/-opt-teecup/a8bd2fc3-4b9c-4682-a2be-cf36e143de78/scratchpad/scratch.env /tmp/claude-1000/-opt-teecup/a8bd2fc3-4b9c-4682-a2be-cf36e143de78/scratchpad/scratch_app_pw.txt /tmp/claude-1000/-opt-teecup/a8bd2fc3-4b9c-4682-a2be-cf36e143de78/scratchpad/minio_user.txt /tmp/claude-1000/-opt-teecup/a8bd2fc3-4b9c-4682-a2be-cf36e143de78/scratchpad/minio_pass.txt /tmp/scratch_cookies2.txt)" + "Bash(rm -f /tmp/claude-1000/-opt-teecup/a8bd2fc3-4b9c-4682-a2be-cf36e143de78/scratchpad/scratch.env /tmp/claude-1000/-opt-teecup/a8bd2fc3-4b9c-4682-a2be-cf36e143de78/scratchpad/scratch_app_pw.txt /tmp/claude-1000/-opt-teecup/a8bd2fc3-4b9c-4682-a2be-cf36e143de78/scratchpad/minio_user.txt /tmp/claude-1000/-opt-teecup/a8bd2fc3-4b9c-4682-a2be-cf36e143de78/scratchpad/minio_pass.txt /tmp/scratch_cookies2.txt)", + "Bash(curl -s \"https://teecup.teeoff.no/tournaments/73b6bf38-90cd-4ef7-9535-8b8e108eaa9a?org=test-org-id&name=Test\")" ], "additionalDirectories": [ "/opt/teeoff/deploy", diff --git a/CLAUDE.md b/CLAUDE.md index cddac6b..c786176 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -732,11 +732,54 @@ Ferdig og verifisert: prinsipp som handicap-snapshotten (ADR-007). Server-til-server-kall (`teecup_api` → `http://teeoff_api:8000`, internt Docker-nettverk, ingen auth trengs). Ny migrasjon `010` (unik `external_course_ref` per org, - hindrer dupliserte importer). Bygges nå — se ADR-019 for alle fem - delbeslutningene. + hindrer dupliserte importer). Se ADR-019 for alle fem delbeslutningene. + **Bygget, scratch-verifisert MOT EKTE `teeoff_api`** (ikke en simulert + respons — ekte HTTP-kall til den kjørende produksjonscontaineren, kun + lesing): søkte opp "Borregaard" i teeoff sine 174 publiserte anlegg, + hentet Borregaard Golfklubb sin hovedbane (18 hull, 4 tee-farger × + kjønn), importerte den til en scratch-org — alle 18 hull med riktig + par/stroke-index (1-18, unik), alle 8 tee/tee_rating-rader med riktig + full_18 course/slope-rating verifisert direkte i databasen, opprettet + deretter en ekte økt med den importerte banen som `course_id` (beviser + hele veien til handicap-motoren fungerer, ikke bare selve importen). + Reimport av samme bane korrekt avvist (409 DUPLICATE, migrasjon 010 sin + indeks). Kryss-org-isolasjon bekreftet, ukjent teeoff-slug ga korrekt 404, + `test_isolation.sql` 12/12. Ekte typesjekket produksjonsbuild av + frontend-utvidelsen (bane-søk i program-skjemaet: søk anlegg → velg bane → + importer, samme UI-mønster som spiller-/bane-type-ahead ellers i appen). + **Rullet ut live 2026-07-18**, bruker bekreftet eksplisitt: migrasjon 010 + kjørt mot ekte `teecup_db` (kun én ny partiell unik-indeks, ingen + eksisterende rader rørt), begge containere bygget+redeployet, live + sjekker OK, `teeoff.no` upåvirket. **"Bygg i rekkefølgen ting brukes"- + planen gjenopptas nå** — blind draw-skjermen er neste steg. + **Reell produksjonsbug funnet OG fikset samme dag, rapportert av bruker + som faktisk brukte funksjonen:** brukeren klikket seg korrekt via + dashbord → turnering → Program-fane (bekreftet med skjermbilde + full + klikk-sti, ikke gjettet), åpnet "Hent bane fra teeoff", søkte "Tjøme", og + fikk feilmeldingen "Mangler organisasjon i lenken" — URL-en hadde da + MISTET `?org=...&name=...`. Root-cause: `OfficialCourseSearch` sitt eget + søke-`` var rendret INNI `CreateSessionCard` + sitt eksisterende `` -- nestede + ``-elementer er ugyldig HTML. Nettleseren slår sammen de to + skjemaene i den faktiske DOM-en, så "Søk"-knappen submittet i praksis det + YTRE økt-skjemaet som en ekte native side-navigasjon (GET til gjeldende + sti, ingen navngitte felt => tom spørrestreng) -- dette vasket bort + org-parameteren og landet brukeren på siden sin egen org-guard. **Fikset** + ved å fjerne det indre ``-elementet helt (vanlig `
` + + Enter-tast-håndtering på inputet + `type="button"` i stedet for + `type="submit"` på søkeknappen) -- gjør nestede skjemaer strukturelt + umulig fremover for denne komponenten. Ekte typesjekket + produksjonsbuild kjørt på nytt, kun `teecup_frontend` redeployet (ingen + backend-endring). **Lærdom for fremtidige skjermer:** en ny + søk-/underskjema-widget som skal plasseres INNI et eksisterende skjema + (slik som denne bane-søk-widgeten ligger inni økt-opprett-skjemaet) må + ALDRI være et eget `` -- bruk `
` + eksplisitt + klikk-/Enter-håndtering. Neste steg: -1. Flere V0-skjermer (blind draw, scorekort, leaderboard) — samme mønster: +1. Blind draw-skjermen (neste i "bygg i rekkefølgen ting brukes", gjenopptatt + etter ADR-019-sidespranget) — deretter scorekort, leaderboard. Samme + mønster: design i V0 (fortsett i samme prosjekt), FORVENT en full re-eksport hver gang — diff mot live-treet i et scratch-område før noe pakkes ut over eksisterende filer, og sjekk om V0-skjermen bygger inn handlinger backend diff --git a/FEATURE_BACKLOG.md b/FEATURE_BACKLOG.md index 54ec09d..3113a7b 100644 --- a/FEATURE_BACKLOG.md +++ b/FEATURE_BACKLOG.md @@ -25,7 +25,7 @@ | Dedikert app-rolle (ingen superuser/BYPASSRLS) | ✅ | migrasjon 002. | | API: oppsett (spillere/lag/roster/økter/matcher/blind draw) | ✅ | Verifisert for ekte mot scratch-db + engangscontainer. | | API: scoring (hole_score/match_hole_result, matchstatus, handicap-beregning) | ✅ | ADR-012/014. Verifisert for ekte, inkl. fourball better-ball og race-sikker recompute. | -| Banedata fra teeoff via API | 🔨 | ADR-004 → **ADR-019** (design besluttet 2026-07-18, bygges nå — sidesprang fra "bygg i rekkefølgen ting brukes", blind draw-skjermen er fortsatt neste steg etterpå). Import (kopi) ved eksplisitt organisator-valg, ikke live oppslag — se ADR-019 i ARCHITECTURE_DECISIONS.md for alle fem delbeslutningene og CLAUDE.md-status for kartleggingen av teeoff sitt `/api/facilities`-API. | +| Banedata fra teeoff via API | ✅ | ADR-004 → **ADR-019**, LIVE 2026-07-18. Import (kopi) ved eksplisitt organisator-valg, ikke live oppslag ved hver bruk. Se egen seksjon under. | | Konfigurerbar handicap-pipeline (4 brytere) | ✅ | ADR-014. Bygget i `app/handicap.py`, brukt av scoring-runden. | | Ekte autentisering (magic-link + JWT-sesjon) | ✅ | ADR-009. `app/routers/auth.py` + migrasjon `004_auth.sql`. `X-Debug-User-Id`-stubben er helt fjernet. | | RLS-tomstreng-fiks (`app_current_org()`) | ✅ | Migrasjon `005_rls_null_guard.sql`. Se detaljer under. | @@ -502,6 +502,52 @@ andre skjermen når den ble generert i en egen prompt. --- +### Offisiell banedata fra teeoff — ✅ BYGGET OG LIVE 2026-07-18 (ADR-019) + +Bevisst sidesprang fra "bygg i rekkefølgen ting brukes" rett etter +program-skjermen: brukeren påpekte at ADR-004s teeoff-integrasjon fortsatt +bare var vedtatt, ikke bygget. Full design i ARCHITECTURE_DECISIONS.md +ADR-019 (fem delbeslutninger). Kort: organisator søker blant teeoff sine +baner i program-skjemaet, velger én, og teecup KOPIERER bane+hull+tee+ +tee_rating inn i `teecup_db` (`source='official'`) — ikke et live oppslag +ved hver bruk. Ny `app/teeoff_client.py` (ren HTTP-klient mot +`http://teeoff_api:8000`, internt Docker-nettverk, ingen auth trengs — begge +containere deler allerede `teeoff_default`). To nye endepunkter i +`app/routers/courses.py`: `GET .../courses/official-search[/​{slug}]` og +`POST .../courses/official-import`. Migrasjon `010` (unik +`external_course_ref` per org, hindrer dupliserte importer). + +**Bevisste avgrensninger for denne runden:** kun 18-hulls baner kan +importeres (teeoffs skjema har ingen egen 9-hulls-inndeling); kun +`full_18`-rating importeres (teeoff har ingen separat front9/back9-rating, +samme valg som ADR-008 allerede tok for egendefinerte baner); ufullstendige +teeoff-data (manglende par/hcp_index på et hull, eller en tee uten NOEN +rating) avviser hele importen tydelig (`EXTERNAL_DATA_INCOMPLETE`) FØR noe +skrives, ikke en delvis importert bane. + +**Verifisert grundig, inkludert mot EKTE `teeoff_api`** (ikke en simulert +respons): søk, anlegg-/banevalg, og import kjørt reelt mot den kjørende +produksjonscontaineren (kun lesing) — importerte Borregaard Golfklubb sin +hovedbane, bekreftet alle 18 hull + 8 tee/tee_rating-rader riktig i +databasen, og opprettet en ekte økt med den importerte banen (beviser hele +veien til handicap-motoren, ikke bare selve importen). Reimport avvist +(409), kryss-org-isolasjon bekreftet, ukjent teeoff-slug ga 404, +`test_isolation.sql` 12/12, ekte typesjekket produksjonsbuild av +frontend-utvidelsen. + +**Rullet ut live**, bruker bekreftet eksplisitt: migrasjon 010 mot ekte +`teecup_db`, begge containere redeployet, `teeoff.no` upåvirket. + +**Reell bug funnet og fikset samme dag, av en bruker som faktisk testet +funksjonen:** bane-søkeboksen ("Hent bane fra teeoff") var et `` +rendret INNI det ytre økt-opprett-skjemaet — ugyldig, nestet HTML. Å klikke +"Søk" submittet i praksis det ytre skjemaet som en ekte side-navigasjon og +vasket bort `?org=...`-parameteren fra URL-en. Fikset ved å fjerne det +indre ``-elementet (vanlig `
` + Enter-tast/knapp-klikk i +stedet). Se CLAUDE.md-status for full root cause. + +--- + ## UX / frontend (senere fase) - 📋 Høy kontrast, dark/light, store +/- knapper, stor «Neste hull»-knapp diff --git a/frontend/components/tournament-program.tsx b/frontend/components/tournament-program.tsx index 016a05e..8e5da2d 100644 --- a/frontend/components/tournament-program.tsx +++ b/frontend/components/tournament-program.tsx @@ -811,8 +811,7 @@ function OfficialCourseSearch({ const [importing, setImporting] = useState(false) const [error, setError] = useState(null) - async function runSearch(e?: React.FormEvent) { - e?.preventDefault() + async function runSearch() { setSearching(true) setError(null) try { @@ -901,18 +900,37 @@ function OfficialCourseSearch({ {!selectedFacility ? ( <> - + {/* Bevisst IKKE et eget her -- denne komponenten rendres + inne i CreateSessionCard sitt , + og nestede -elementer er ugyldig HTML. Nettleseren + slår da sammen de to skjemaene i den faktiske DOM-en, som + gjorde at "Søk"-knappen i praksis submittet det YTRE + økt-skjemaet i stedet -- en ekte native side-navigasjon som + vasket bort ?org=...-parameteren fra URL-en (funnet ved en + reell feilrapport fra bruker mot produksjon). */} +
setQuery(e.target.value)} + onKeyDown={(e) => { + if (e.key === "Enter") { + e.preventDefault() + runSearch() + } + }} className="h-11 flex-1 rounded-xl text-base" /> - - +
{facilities && (
    {facilities.map((f) => (