From c3cca377ed81c77275cf0739e6f280a0dc4946bb Mon Sep 17 00:00:00 2001 From: Erol Haagenrud Date: Sun, 19 Jul 2026 11:46:33 +0200 Subject: [PATCH] pdate Todos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Legge til visuell hint på øktkort ("Sett opp flights") i program-skjermen Avklare designbeslutninger for Brukerroller med bruker Skrive team_authz.py på nytt (kaptein-only + match-deltaker-sjekk) Oppdatere matches.py til å bruke user_is_team_captain Oppdatere scoring.py til å bruke user_is_match_participant Håndheve 'kun én kaptein per lag' i tournaments.py PATCH/POST roster Sjekke ekte teecup_db for lag uten kaptein / med flere kapteiner (kun lesing) Skrive ADR-023 for Brukerroller-beslutningene Sette opp scratch MinIO + engangs API-container Kjøre autorisasjonstester (kaptein/deltaker) mot scratch-API-et Rydde opp scratch-infrastruktur Ekte typesjekket frontend-build (øktkort-hint) Deploy etter eksplisitt bekreftelse + oppdatere .md-filer Live og verifisert. Oppsummert: Øktkort-hint: "Sett opp flights og lås oppstilling →" vises nå tydelig på hvert øktkort i Program-fanen. Brukerroller (ADR-023): Kaptein er nå en reell autorisasjonsrolle — kun kaptein (eller org-eier/admin) kan legge til/fjerne deltakere og låse laget. Har et lag ingen utpekt kaptein ennå (som "De Unge" har akkurat nå — sjekket mot ekte data før utrulling), gjelder samme åpne tilgang som før, så ingen ble låst ute av endringen. "Kun én kaptein per lag" håndheves nå — å utpeke en ny kaptein fjerner automatisk merket fra forrige. Score føres nå kun av matchens faktiske deltakere (eller org-admin), ikke lenger "hvem som helst på laget" — uavhengig av kapteinmerket. Fant og fikset en reell 500-bug under scratch-testing (enum/tekst-sammenligning i SQL) før noe nådde produksjon. Alt scratch-verifisert (15 automatiserte sjekker + test_isolation.sql 12/12), typesjekket produksjonsbuild kjørt, deployet uten migrasjon, teeoff.no upåvirket. Naturlig neste steg nå som brukerroller er avgjort: walkover/konsesjon (ventet tidligere nettopp på dette) kan tas fatt på — men si fra hva du vil prioritere. --- .claude/settings.local.json | 5 ++- ARCHITECTURE_DECISIONS.md | 6 ++-- CLAUDE.md | 63 +++++++++++++++++++++++++++++++++++-- FEATURE_BACKLOG.md | 4 +-- 4 files changed, 69 insertions(+), 9 deletions(-) diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 5971bee..41f6b28 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -280,7 +280,10 @@ "Bash(curl -s -o /dev/null -w '%{http_code}\\\\n' https://teecup.teeoff.no/dashboard)", "Bash(grep -n \"teecup\" -A 20 /opt/teeoff/deploy/Caddyfile 2>/dev/null | head -60)", "Bash(curl -s -o /dev/null -w '%{http_code} -> %{redirect_url}\\\\n' -b \"teecup_session=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI4NDYzM2JlMS1iZWM1LTQ1ZDItOTI1ZC1lNzAzYTdjOWM1OGYiLCJpYXQiOjE3ODQ0NDc5NzIsImV4cCI6MTc4NzAzOTk3Mn0.wQAHP4qlo-zzHH7JrDWm_FyupW8g-_vMkr96szWmuXg\" https://teecup.teeoff.no/)", - "Bash(curl -s -w '\\\\n%{http_code}\\\\n' -X POST https://teecup.teeoff.no/auth/login-password -H \"Content-Type: application/json\" -d '{\"email\":\"ikke@finnes.no\",\"password\":\"whatever\"}')" + "Bash(curl -s -w '\\\\n%{http_code}\\\\n' -X POST https://teecup.teeoff.no/auth/login-password -H \"Content-Type: application/json\" -d '{\"email\":\"ikke@finnes.no\",\"password\":\"whatever\"}')", + "Bash(curl -s -o /dev/null -w \"health: %{http_code}\\\\n\" https://teecup.teeoff.no/health)", + "Bash(curl -s -o /dev/null -w \"dashboard: %{http_code}\\\\n\" https://teecup.teeoff.no/dashboard)", + "Bash(curl -s -o /dev/null -w \"teeoff.no: %{http_code}\\\\n\" https://teeoff.no)" ], "additionalDirectories": [ "/opt/teeoff/deploy", diff --git a/ARCHITECTURE_DECISIONS.md b/ARCHITECTURE_DECISIONS.md index 4629166..19c9797 100644 --- a/ARCHITECTURE_DECISIONS.md +++ b/ARCHITECTURE_DECISIONS.md @@ -961,9 +961,9 @@ formelt tilskuer-begrep bør defineres sammen med det ennå ubesluttede synlighetsspørsmålet for «Banter Board»-feeden (FEATURE_BACKLOG), ikke isolert her, for å unngå å bygge to overlappende synlighetsmodeller. -**Status: ✅ BYGGET 2026-07-19.** Ingen migrasjon (ren autorisasjonslogikk, -ingen skjemaendring). Se CLAUDE.md-status for scratch-verifisering og -utrulling. +**Status: ✅ BYGGET OG LIVE 2026-07-19.** Ingen migrasjon (ren +autorisasjonslogikk, ingen skjemaendring). Se CLAUDE.md-status for +scratch-verifisering og utrulling. --- diff --git a/CLAUDE.md b/CLAUDE.md index d629529..ae1a78f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1334,12 +1334,69 @@ Ferdig og verifisert: Bevisst utenfor omfang: dedikert superadmin-UI (brukes via API av en betrodd operatør), SMS som 2FA-metode. +- **Program-skjerm: tydeligere klikk-hint på øktkort (2026-07-19):** brukeren + påpekte at ingenting i grensesnittet indikerte at et øktkort er klikkbart + inn til blind draw-skjermen. Lagt til en synlig "Sett opp flights og lås + oppstilling →"-rad nederst i hvert kort (`components/tournament-program.tsx`). + Ren frontend-endring, ingen backend-rørt. +- **Brukerroller: kaptein som reell autorisasjon, deltaker-avgrenset scoring + (2026-07-19, ADR-023):** direkte oppfølging av det lenge åpne + "Brukerroller"-punktet i FEATURE_BACKLOG.md. Fire beslutninger avklart + eksplisitt med bruker (AskUserQuestion) før bygging — alle anbefalte valg. + **Bygget:** `app/team_authz.py` skrevet om — `user_is_team_captain` + (erstatter `user_may_act_for_team`) krever `is_captain=true` på + `team_roster` (eller org-eier/admin) for å legge til/fjerne deltakere og + låse et lag (`matches.py`); ny `user_is_match_participant` krever en ekte + `match_participant`-rad for brukeren i AKKURAT den matchen (valgfritt + side-spesifikk via `team_side`) for å føre/korrigere score (`scoring.py`) + — uavhengig av kapteinmerket. Nye feilkoder `NOT_TEAM_CAPTAIN` og + `NOT_MATCH_PARTICIPANT` (erstatter `NOT_ROSTERED_ON_TEAM` på disse fem + stedene). `app/routers/tournaments.py` sin `PATCH`/`POST .../roster` + håndhever nå "kun én kaptein per lag" (fjerner automatisk forrige + kapteins merke i samme transaksjon). + **Reelt funn FØR utrulling, ikke antatt:** sjekket (kun lesing, superbruker + mot ekte `teecup_db`) om noen eksisterende lag ville blitt låst ute av en + ren kaptein-only-regel — "De Unge" i "De Gamle er Eldst" har i dag 0 av 2 + roster-rader merket kaptein. Designet derfor en bevisst fallback i + `user_is_team_captain`: har laget INGEN utpekt kaptein ennå, godtas enhver + rostret spiller i stedet for å låse laget helt ute. Ingen lag hadde flere + kapteiner, så "kun én kaptein"-håndhevelsen krevde ingen data-opprydning. + **Reell bug funnet OG fikset UNDER scratch-testing:** `user_is_match_ + participant` sin SQL sammenlignet `mp.team_side` (enum-kolonne) direkte + mot en tekst-parameter uten cast når `team_side=None` (hole_result-modus) + — ga en rå 500 (`UndefinedFunctionError: operator does not exist: team_side + = text`). Rettet med et eksplisitt `mp.team_side::text = $3`. + **Verifisert grundig mot fersk `teecup_scratch`** (isolert + `teecup_app_scratch`-rolle, isolert scratch-MinIO, engangs API-container): + et 15-punkts Python/httpx-testskript som simulerte fire innloggede + brukere (organisator + tre rostrede spillere på to lag) gjennom hele + syklusen — lag uten kaptein tillater enhver rostret (fallback bekreftet), + kaptein utpekt fjerner andre rostredes rettighet, "kun én kaptein" bekreftet + (ny kaptein avsetter automatisk forrige), org-admin fungerer uendret + uavhengig av kaptein, og scoring (`hole_result`-modus) bekreftet begrenset + til faktiske matchdeltakere (en kaptein som IKKE selv spiller matchen ble + korrekt avvist med `NOT_MATCH_PARTICIPANT`, mens en faktisk deltaker og + org-admin begge fikk føre score). Måtte også oppdage og legge til et + forutsetning-steg underveis: `get_authorized_org` krever + `organization_membership` for ALLE org-scopede endepunkter uansett — en + rostret spiller må derfor også være invitert som org-medlem (minimum + 'member', ADR-022s invitasjonsflyt) for i det hele tatt å nå + team_authz-vurderingen; ikke en bug, men en forutsetning testskriptet + først manglet. `test_isolation.sql` 12/12 uendret (ingen skjemaendring). + Ekte typesjekket produksjonsbuild av frontend (øktkort-hintet fra samme + runde) kjørt og bekreftet, alle 11 ruter listet. + **Rullet ut live 2026-07-19**, bruker bekreftet eksplisitt: ingen + migrasjon, `docker compose up -d --build teecup_api teecup_frontend`, + begge containere boot-et rent (`Application startup complete`, Next.js + `Ready`), `/health` og `/dashboard` → 200, `teeoff.no` upåvirket. + Neste steg: 1. PWA-egenskaper (manifest, service worker, offline-cache) — ikke startet. 2. Kommunikasjon (chat/feed) — ikke startet. -3. Fortsatt åpne beslutninger fra FEATURE_BACKLOG.md (walkover/konsesjon, - sanntid/WebSockets vs. polling, tilskuer-rolle, kode-regenerering for - ADR-020) — bør avklares i egne, dedikerte runder når det er naturlig. +3. Fortsatt åpne beslutninger fra FEATURE_BACKLOG.md: walkover/konsesjon + (kan nå tas fatt på — ventet tidligere på brukerroller/ADR-023, som nå er + avgjort og bygget), sanntid/WebSockets vs. polling, tilskuer-rolle + (bevisst utsatt til Kommunikasjon-runden), kode-regenerering for ADR-020. 4. Ved fremtidige nye V0-skjermer/-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 diff --git a/FEATURE_BACKLOG.md b/FEATURE_BACKLOG.md index afe988a..c0be890 100644 --- a/FEATURE_BACKLOG.md +++ b/FEATURE_BACKLOG.md @@ -298,8 +298,8 @@ ## Ønsket, men IKKE fanget før nå (fra Gemini-samtalene) ### Brukerroller (utover org-medlemskap) — ADR-023 -- **Status:** ✅ BYGGET OG SCRATCH-VERIFISERT 2026-07-19 (deploy venter på - bekreftelse) — kaptein/deltaker-delen. Tilskuer bevisst utsatt. +- **Status:** ✅ BYGGET OG LIVE 2026-07-19 — kaptein/deltaker-delen. + Tilskuer bevisst utsatt. - De opprinnelige samtalene beskriver: turneringsadmin, **lagkaptein**, spiller, **tilskuer** (les-only, følger live uten skriverettigheter). - Vi har i dag org-roller (owner/admin/member) + `is_captain` på roster.