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:
parent
e60a2aafe7
commit
c3cca377ed
4 changed files with 69 additions and 9 deletions
|
|
@ -280,7 +280,10 @@
|
||||||
"Bash(curl -s -o /dev/null -w '%{http_code}\\\\n' https://teecup.teeoff.no/dashboard)",
|
"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(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 -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": [
|
"additionalDirectories": [
|
||||||
"/opt/teeoff/deploy",
|
"/opt/teeoff/deploy",
|
||||||
|
|
|
||||||
|
|
@ -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
|
synlighetsspørsmålet for «Banter Board»-feeden (FEATURE_BACKLOG), ikke
|
||||||
isolert her, for å unngå å bygge to overlappende synlighetsmodeller.
|
isolert her, for å unngå å bygge to overlappende synlighetsmodeller.
|
||||||
|
|
||||||
**Status: ✅ BYGGET 2026-07-19.** Ingen migrasjon (ren autorisasjonslogikk,
|
**Status: ✅ BYGGET OG LIVE 2026-07-19.** Ingen migrasjon (ren
|
||||||
ingen skjemaendring). Se CLAUDE.md-status for scratch-verifisering og
|
autorisasjonslogikk, ingen skjemaendring). Se CLAUDE.md-status for
|
||||||
utrulling.
|
scratch-verifisering og utrulling.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
63
CLAUDE.md
63
CLAUDE.md
|
|
@ -1334,12 +1334,69 @@ Ferdig og verifisert:
|
||||||
Bevisst utenfor omfang: dedikert superadmin-UI (brukes via API av en
|
Bevisst utenfor omfang: dedikert superadmin-UI (brukes via API av en
|
||||||
betrodd operatør), SMS som 2FA-metode.
|
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:
|
Neste steg:
|
||||||
1. PWA-egenskaper (manifest, service worker, offline-cache) — ikke startet.
|
1. PWA-egenskaper (manifest, service worker, offline-cache) — ikke startet.
|
||||||
2. Kommunikasjon (chat/feed) — ikke startet.
|
2. Kommunikasjon (chat/feed) — ikke startet.
|
||||||
3. Fortsatt åpne beslutninger fra FEATURE_BACKLOG.md (walkover/konsesjon,
|
3. Fortsatt åpne beslutninger fra FEATURE_BACKLOG.md: walkover/konsesjon
|
||||||
sanntid/WebSockets vs. polling, tilskuer-rolle, kode-regenerering for
|
(kan nå tas fatt på — ventet tidligere på brukerroller/ADR-023, som nå er
|
||||||
ADR-020) — bør avklares i egne, dedikerte runder når det er naturlig.
|
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),
|
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
|
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
|
scratch-område før noe pakkes ut over eksisterende filer, og sjekk om
|
||||||
|
|
|
||||||
|
|
@ -298,8 +298,8 @@
|
||||||
## Ønsket, men IKKE fanget før nå (fra Gemini-samtalene)
|
## Ønsket, men IKKE fanget før nå (fra Gemini-samtalene)
|
||||||
|
|
||||||
### Brukerroller (utover org-medlemskap) — ADR-023
|
### Brukerroller (utover org-medlemskap) — ADR-023
|
||||||
- **Status:** ✅ BYGGET OG SCRATCH-VERIFISERT 2026-07-19 (deploy venter på
|
- **Status:** ✅ BYGGET OG LIVE 2026-07-19 — kaptein/deltaker-delen.
|
||||||
bekreftelse) — kaptein/deltaker-delen. Tilskuer bevisst utsatt.
|
Tilskuer bevisst utsatt.
|
||||||
- De opprinnelige samtalene beskriver: turneringsadmin, **lagkaptein**, spiller,
|
- De opprinnelige samtalene beskriver: turneringsadmin, **lagkaptein**, spiller,
|
||||||
**tilskuer** (les-only, følger live uten skriverettigheter).
|
**tilskuer** (les-only, følger live uten skriverettigheter).
|
||||||
- Vi har i dag org-roller (owner/admin/member) + `is_captain` på roster.
|
- Vi har i dag org-roller (owner/admin/member) + `is_captain` på roster.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue