Update Todos

Add non-org-scoped teeoff search + personal-course detail endpoints to rounds.py

Build /rounds list page + component

Build /rounds/new creation flow (course search/create, tee, date, holes)

Build /rounds/[id] detail page (participants, hole-by-hole stats, complete)

Link new feature from dashboard

Scratch-verify backend additions + typecheck production build

Deploy live after user confirmation

Update ADR-033/FEATURE_BACKLOG/CLAUDE.md status
Frontend for frittstående rundeføring er nå live på teecup.teeoff.no. Oppsummert:

/rounds — liste over egne runder, med «Ny runde»-knapp
/rounds/new — velg bane (søk i teeoff live, eller søk/opprett egen bane), utslag (filtrert til ditt registrerte kjønn), dato, starthull, 9/18 hull
/rounds/[id] — deltaker-faner (deg + gjester), hull-for-hull-registrering med slag/putt-tallvelgere, utvidbare detaljer (kølle, utslagsretning, innspill, chip, bunker, straffeslag, putt-avstand), automatisk GIR-visning, og «Fullfør runde» som beregner HCP-differensial
Lenket fra dashbordet som «Egne runder» — bevisst adskilt fra det eksisterende «Mine runder» (turnering-deltakelse) for å unngå forveksling.

Underveis fant jeg og fikset et reelt kontraktshull: hull-PATCH-endepunktet skriver alle felt ved hvert kall, ikke bare det som sendes — jeg bekreftet dette eksplisitt i scratch (et PATCH med kun score nullstiller stille putts) og bygget derfor inn en merge-før-send i frontend-koden.

Alt er scratch-verifisert (22 sjekker + en egen test av hele teeoff-baserte oppretteflyten mot ekte teeoff_api), typesjekket med ekte produksjonsbuild, og rullet ut uten migrasjon. teeoff.no upåvirket gjennom hele runden. Status oppdatert i CLAUDE.md, FEATURE_BACKLOG.md og ADR-033.
This commit is contained in:
Erol Haagenrud 2026-07-23 06:06:41 +02:00
parent c15c68efca
commit 2cbb9fd308
4 changed files with 126 additions and 10 deletions

View file

@ -355,7 +355,10 @@
"Bash(docker run -d --name teecup_api_scratch --network teeoff_default \\\\ *)",
"Bash(docker rm -f teecup_api_scratch >/dev/null 2>&1 *)",
"Bash(python3 test_rounds_frontend_endpoints.py)",
"Bash(TEECUP_API_ORIGIN=http://localhost:8000 npx next build)"
"Bash(TEECUP_API_ORIGIN=http://localhost:8000 npx next build)",
"Bash(curl -s -o /dev/null -w \"teecup.teeoff.no/health: %{http_code}\\\\n\" https://teecup.teeoff.no/health)",
"Bash(curl -s -o /dev/null -w \"teecup.teeoff.no/dashboard: %{http_code}\\\\n\" https://teecup.teeoff.no/dashboard)",
"Bash(curl -s -o /dev/null -w \"teecup.teeoff.no/rounds: %{http_code}\\\\n\" https://teecup.teeoff.no/rounds)"
],
"additionalDirectories": [
"/opt/teeoff/deploy",

View file

@ -1901,8 +1901,66 @@ skjerm bygget for dette ennå), boot-et rent, `/health`/`/dashboard` → 200,
ADR-016/medlemsside-hendelsen — enhver ny API-prefiks MÅ inn her FØR en
frontend-side bygges) — denne ENDRINGEN ligger IKKE deployet ennå (ingen
frontend-kode bruker den), tas med i neste frontend-runde.
**Gjenstår:** hele frontend-en for frittstående rundeføring — ingenting
bygget ennå.
**Frontend BYGGET OG RULLET UT 2026-07-23** — fjerde og siste lag
(engine → skjema → API → frontend). Tre nødvendige tillegg til
`app/routers/rounds.py` funnet og bygget UNDER frontend-designet, ikke
antatt på forhånd: `GET /rounds/official-search`/`{slug}` (samme
teeoff-søkemønster som `courses.py`, men uten org-kontekst — frittstående
runder har ingen), `GET /personal-courses/{id}` (detalj med
utslag+kjønn — søk-endepunktet returnerte kun navn), og
`GET .../participants/{id}/holes` (et reelt hull: `RoundOut` bar aldri
hull-nivå-data, så ingen skjerm kunne vise gjeldende tilstand ved
gjenlasting). Hull-PATCH endret til å returnere hele den oppdaterte raden
i stedet for `{"ok": true}`.
**Reelt kontraktsfunn, bekreftet i scratch FØR frontend stolte på det:**
hull-PATCH-endepunktet er IKKE et ekte delvis-PATCH — det skriver ALLE
felt ved hvert kall (arvet fra hvordan `HoleUpdate`-modellen alltid har
defaultverdier for utelatte felt). Et PATCH som kun sender `score` ville
derfor stille NULLSTILT `putts` og alle andre allerede lagrede felt.
Løst ved at `round-detail.tsx` alltid slår sammen med gjeldende
hull-data før hver PATCH, aldri sender et isolert feltnavn alene —
verifisert eksplisitt i en egen scratch-test som FØRST beviste
nullstillings-oppførselen uten merge, DERETTER beviste at
merge-mønsteret unngår den.
**Nye sider:** `/rounds` (liste over egne runder), `/rounds/new`
(bane-kilde teeoff vs. egen — for egen bane: søk-før-opprett, samme idé
som org-banenes gjenbrukbare katalog; utslag filtrert til kun de som har
rating for brukerens registrerte kjønn, ADR-029s automatikk-prinsipp
gjenbrukt her selv om HCP-motoren er en helt annen), `/rounds/[id]`
(deltaker-faner — eier + gjester, ingen ekte kontokobling i v1 per
Beslutning D; hull-navigasjon fra runde-ens starthull; slag/putt-
tallvelgere i samme visuelle stil som `session-scorecard.tsx` sin
`StrokePicker`; kølle/retning/innspill/chip/bunker/straffeslag/
putt-avstand bak en «flere detaljer»-utvidelse; GIR utledet og vist
KLIENTSIDE ved lesing, aldri lagret — nøyaktig Beslutning B sitt prinsipp;
fullfør-runde med HCP-differensial-sammendrag, låser videre redigering).
Lenket fra dashbordet som «Egne runder» (header-lenke + en egen kort på
forsiden) — bevisst adskilt navn fra det eksisterende «Mine runder»
(ADR-031, turnering-deltakelse) for å unngå at de to konseptene blandes
sammen i UI-et, selv om begge bokstavelig talt handler om "runder".
**Scratch-verifisert grundig** (isolert `teecup_app_scratch`-rolle +
isolert scratch-MinIO + engangs API-container, samme mønster som resten
av ADR-033): 22 automatiserte sjekker (egendefinert-bane-opprettelse med
to utslag/to kjønn, søk, detalj, PATCH-kontraktsbeviset over,
GIR-derivering for et konstruert par4/score3/putt1-tilfelle, gjest-
fjerning, kryss-bruker-autorisasjon 403, full fullføring med differensial)
PLUSS en separat, egen test av HELE teeoff-baserte opprettelsesløpet mot
den ekte kjørende `teeoff_api`-containeren (Borregaard Golfklubb, samme
anlegg som tidligere ADR-019/033-verifiseringer) som bekreftet
`course_handicap_snapshot` ble beregnet riktig fra live-hentet
rating. Ekte typesjekket PRODUKSJONSBUILD kjørt via
`docker build --target builder` (nøyaktig samme steg `Dockerfile` bruker
i prod, ikke `next dev`) — kompilerte rent, alle nye ruter listet.
**Rullet ut live 2026-07-23**, bruker bekreftet eksplisitt: ingen
migrasjon i denne del-runden, `docker compose up -d --build teecup_api
teecup_frontend`, begge containere boot-et rent, `/health`/`/dashboard`/
`/rounds` → 200 over ekte https, `teeoff.no` upåvirket.
**Bevisst utenfor omfang, ikke bygget denne runden:** ekte kontokobling
for gjeste-deltakere (Beslutning D), automatisk oppdatering av
`app_user.handicap_index`/`handicap_history` ved fullført tellende runde
(åpent spørsmål i Beslutning G, fortsatt ubesvart), shotgun-start
(egen, separat ADR-034), GPS/avstandsmåling (se eget notat i
FEATURE_BACKLOG.md, krever data ingen kilde har i dag).
**Motor-komponenten (punkt 1-11) er ✅ BYGGET OG TESTET 2026-07-22,**
som første, isolerte byggesteg (ren Python, ingen DB/API/frontend ennå —

View file

@ -2346,14 +2346,59 @@ Neste steg:
`teecup_db`/`teecup_api` 2026-07-22, `/health`/`/dashboard` → 200,
`teeoff.no` upåvirket. `frontend/next.config.mjs` fikk `/rounds`/
`/personal-courses` lagt til i `rewrites()` proaktivt (ikke deployet
ennå, ingen frontend bruker den før neste runde). **Frontend for
frittstående rundeføring er fortsatt HELT ubygget** — neste steg.
Se ADR-033 i ARCHITECTURE_DECISIONS.md for full detalj.
ennå, ingen frontend bruker den før neste runde).
**Notat fra bruker, IKKE designet:** planer om å måle lengde på slag +
opplyse avstand til ulike punkter på banen (golf-GPS/rangefinder-type
funksjonalitet) — krever geografiske/GPS-data ingen kilde har i dag
(verken teeoff eller `personal_course`). Se FEATURE_BACKLOG.md for
full detalj.
**Frontend bygget og rullet ut 2026-07-23, samme rekkefølge-prinsipp
(engine → skjema → API → frontend) fullført:** tre nye,
organisasjonsuavhengige endepunkter lagt til i `rounds.py`
(`GET /rounds/official-search`/`{slug}` — samme mønster som
`courses.py` sitt org-scopede søk, men uten org-kontekst, siden
frittstående runder ikke har noen; `GET /personal-courses/{id}`
detalj med utslag+kjønn, manglet fra søk-runden) og en fjerde,
nødvendig tilføyelse oppdaget UNDER frontend-designet: `RoundOut` bar
aldri hull-nivå-data i det hele tatt — ny
`GET .../participants/{id}/holes`. Hull-PATCH-endepunktet endret til å
returnere hele den oppdaterte raden i stedet for `{"ok": true}`.
**Reelt kontraktsfunn, bekreftet i scratch FØR frontend stolte på det:**
hull-PATCH er IKKE et ekte delvis-PATCH — den skriver ALLE felt ved
hvert kall, så et utelatt felt (f.eks. putts) nullstilles stille hvis
frontend ikke sender det. Løst ved at `round-detail.tsx` alltid slår
sammen med gjeldende hull-data før hver PATCH, aldri sender et isolert
feltnavn alene — verifisert eksplisitt med en egen scratch-test som
FØRST beviste nullstillings-oppførselen, DERETTER beviste at
merge-mønsteret unngår den.
Nye sider: `/rounds` (liste), `/rounds/new` (bane-kilde teeoff/egen,
søk-før-opprett for egen bane samme idé som org-banene, utslag filtrert
på brukerens registrerte kjønn, dato/starthull/hull-antall), `/rounds/
[id]` (deltaker-faner, hull-navigasjon fra starthull, slag/putt-
tallvelgere i samme stil som `session-scorecard.tsx` sin `StrokePicker`,
kølle/retning/innspill/chip/bunker/straffeslag bak en «flere detaljer»-
utvidelse, GIR utledet og vist klientside — aldri lagret, kun beregnet
fra `approach_result`+slag+putt ved lesing, fullfør-runde med HCP-
differensial-sammendrag). Lenket fra dashbordet som «Egne runder»
(bevisst adskilt navn fra det eksisterende «Mine runder», som gjelder
turnering-deltakelse — samme ord, to ulike konsepter).
**Scratch-verifisert grundig** (isolert `teecup_app_scratch`-rolle +
isolert scratch-MinIO + engangs API-container, samme mønster som hele
økten ellers): 22 sjekker som dekker egendefinert-bane-opprettelse med
to utslag/kjønn, søk, detalj, PATCH-kontrakten (inkl. det bevisste
nullstillings-beviset over), GIR-derivering, gjest-fjerning,
kryss-bruker-autorisasjon (403), og full fullføring med differensial
— PLUSS en egen, separat test av hele teeoff-baserte opprettelsesløpet
mot den ekte kjørende `teeoff_api`-containeren (Borregaard Golfklubb),
som bekreftet course_handicap ble beregnet riktig. Ekte typesjekket
PRODUKSJONSBUILD (`docker build --target builder`, samme steg som
`Dockerfile` faktisk bruker) kjørt og bekreftet — alle nye ruter listet.
**Rullet ut live 2026-07-23**, bruker bekreftet eksplisitt: ingen
migrasjon, `docker compose up -d --build teecup_api teecup_frontend`,
begge containere boot-et rent, `/health`/`/dashboard`/`/rounds` → 200,
`teeoff.no` upåvirket. **Frittstående rundeføring har dermed backend
OG frontend live** — se ADR-033 i ARCHITECTURE_DECISIONS.md for full
detalj om alle fire lagene (engine/skjema/API/frontend).
4. **Del 1 (fri, ukrevd sekundær-e-post) er nå BYGGET OG LIVE** (2026-07-21,
se status over). **Del 2 (ekte konto-sammenslåing) fortsatt IKKE
designet:** hva skjer hvis den ønskede adressen ALLEREDE tilhører en

View file

@ -1366,14 +1366,24 @@ tom-skjermens endelige form kan bestemmes.
---
## Frittstående rundeføring + detaljert statistikk (uten turnering/organisasjon) — 🔨 ADR-033 SKREVET OG KILDEBELAGT, BYGGING PÅBEGYNT 2026-07-22
## Frittstående rundeføring + detaljert statistikk (uten turnering/organisasjon) — ✅ BACKEND + FRONTEND LIVE (2026-07-23)
**Fremdrift 2026-07-22:** HCP-indeks-motor (43/43 tester), databaseskjema
(`020`+`021`, sistnevnte en fiks for manglende rating-snapshot-kolonner),
OG et fullt API-lag (`app/routers/rounds.py`) er alle bygget,
scratch-verifisert og rullet ut mot ekte `teecup_db`/`teecup_api`. Se
ADR-033 i ARCHITECTURE_DECISIONS.md for full detalj. **Gjenstår: hele
frontend-en** — ingenting bygget ennå.
scratch-verifisert og rullet ut mot ekte `teecup_db`/`teecup_api`.
**Frontend bygget og rullet ut 2026-07-23** — se ADR-033 i
ARCHITECTURE_DECISIONS.md for full detalj om alle tre lagene (engine,
skjema, API) og hele frontend-runden (nye endepunkter, komponenter,
verifisering, utrulling). Kort: `/rounds` (liste), `/rounds/new`
(bane-søk teeoff/egen + opprett egen bane, utslag/dato/hull), `/rounds/[id]`
(deltakere, hull-for-hull-registrering med automatisk GIR-visning,
fullfør-runde med HCP-differensial). Lenket fra dashbordet som «Egne
runder». Ingen migrasjon i denne del-runden — kun tre nye,
organisasjonsuavhengige endepunkter i `rounds.py`
(`official-search`/`official-search/{slug}`/`personal-courses/{id}`/
`.../holes`) og en endring av hull-PATCH-responsen.
**Notat fra bruker, IKKE designet/bygget ennå (fanget 2026-07-22):**
brukeren har tenkt å ha med (a) måling av lengde på slag, og (b) å kunne