pdate Todos

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.
This commit is contained in:
Erol Haagenrud 2026-07-19 11:46:33 +02:00
parent e60a2aafe7
commit c3cca377ed
4 changed files with 69 additions and 9 deletions

View file

@ -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",

View file

@ -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.
---

View file

@ -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`
`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

View file

@ -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.