Dokumenter konkurranseklasser (ADR-041) i CHANGELOG/FEATURE_BACKLOG
Fullfører dokumentasjonen for klasse-funksjonen (migrasjon 053, rullet ut 2026-08-04): ny ADR-041 med de fire load-bærende beslutningene (fritt navngitte klasser, delt tabell mellom turneringstyper, standardutslag som frontend-bekvemmelighet, egen resultatliste kun i individuelle turneringer), pluss fulle bygge-/verifiseringsoppføringer i CHANGELOG.md og FEATURE_BACKLOG.md. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
7bda1bf789
commit
38168b2871
3 changed files with 215 additions and 0 deletions
|
|
@ -3819,6 +3819,86 @@ ikke noe brukeren har bedt om.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## ADR-041: Konkurranseklasser ("Damer fra 44, Herrer fra 50+")
|
||||||
|
|
||||||
|
**Kontekst:** Brukeren spurte om det var mulig å sette opp runder i en
|
||||||
|
turnering slik at f.eks. damer spiller fra utslag 44 mens herrer spiller
|
||||||
|
fra 50+. Undersøkelse viste at DELER allerede virket (hvert
|
||||||
|
`match_participant`/`round_participant` har alltid hatt sitt eget
|
||||||
|
`tee_id`, uavhengig av de andre, med server-side validering av at
|
||||||
|
utslaget har rating for spillerens kjønn, ADR-029) — men det var et
|
||||||
|
manuelt valg per spiller hver gang, ingen gjenbrukbar "klasse"-
|
||||||
|
gruppering. Ingen "klasse"/kategori-konsept for konkurranse fantes fra
|
||||||
|
før noe sted i skjemaet (kun den urelaterte venne-kategoriseringen,
|
||||||
|
ADR-036).
|
||||||
|
|
||||||
|
**Beslutning A — Klasser er fritt navngitte, ikke en fast taksonomi.**
|
||||||
|
Organisator oppretter klasser med eget navn (f.eks. "Damer", "Herrer A",
|
||||||
|
"Junior") og et VALGFRITT standardutslag — ikke en kjønns- eller
|
||||||
|
alders-spesifikk datamodell. Bekreftet eksplisitt med bruker
|
||||||
|
(`AskUserQuestion`) framfor en fast kjønn+alder-kombinasjon: dekker
|
||||||
|
kjønn/alder/HCP eller annet uten at systemet må forstå forskjellen,
|
||||||
|
samme fleksibilitets-prinsipp som `friend_categorization` (ADR-036).
|
||||||
|
|
||||||
|
**Beslutning B — Delt tabell, ikke duplisert per turneringstype.** Ny
|
||||||
|
`tournament_class`-tabell (migrasjon 053) FK'et til `tournament`, ikke
|
||||||
|
en utvidelse av selve `tournament`-raden — samme sidetabell-mønster som
|
||||||
|
`tournament_sponsor`. Siden BÅDE lagturneringer (ADR-011) og
|
||||||
|
individuelle turneringer (ADR-037) peker til samme delte `tournament`-
|
||||||
|
tabell (`format_type`-diskriminator), dekker ÉN tabell begge uten
|
||||||
|
duplisering. Klassetilhørighet lever på `team_roster.class_id`
|
||||||
|
(lagturneringer) og `tournament_participant.class_id` (individuelle
|
||||||
|
turneringer) — begge nullable, `ON DELETE SET NULL` (samme prinsipp som
|
||||||
|
`tournament_round_bbb_hole`s FK-er, migrasjon 044): sletter man en
|
||||||
|
klasse, forsvinner ikke roster-/deltaker-radene, de mister bare
|
||||||
|
merkelappen.
|
||||||
|
|
||||||
|
**Beslutning C — Standardutslag er en frontend-bekvemmelighet, ikke en
|
||||||
|
ny backend-mekanisme.** `tee_id` er ALLEREDE required og satt per
|
||||||
|
deltaker (ikke per økt/runde) ved både `POST .../matches/{id}/
|
||||||
|
participants` og `POST .../rounds/{id}/participants` — klassens
|
||||||
|
standardutslag forhåndsvelger bare dette feltet i UI-et (fortsatt fritt
|
||||||
|
overstyrbart), backend-kontrakten er uendret. Samme mønster som
|
||||||
|
`new-round.tsx`s eksisterende kjønnsfilter/-default for personlige
|
||||||
|
runder. Forhåndsvelgingen sjekker eksplisitt at utslaget faktisk finnes
|
||||||
|
på DEN aktuelle øktens/rundens bane før det brukes — en klasses
|
||||||
|
standardutslag kan tilhøre en annen bane enn den som er i bruk akkurat
|
||||||
|
da.
|
||||||
|
|
||||||
|
**Beslutning D — Egen resultatliste KUN i individuelle turneringer,
|
||||||
|
aldri i lagturneringer.** Den mest substansielle avklaringen
|
||||||
|
(`AskUserQuestion`, med begrunnelse presentert først): i lagturneringer
|
||||||
|
er poeng knyttet til hele KAMPER (lag mot lag, `match.points_side_a/b`),
|
||||||
|
ikke enkeltspillere — å dele opp dette per klasse gir ikke naturlig
|
||||||
|
mening, og brukeren bekreftet eksplisitt at klasse der KUN skal foreslå
|
||||||
|
utslag. Det finnes fra før et smalt, PER-ØKT individuelt leaderboard for
|
||||||
|
singles/fourball-slagspill (`fetch_individual_leaderboard`,
|
||||||
|
`tournaments.py`) — bevisst IKKE utvidet eller gjenbrukt av denne runden,
|
||||||
|
det er en annen, allerede eksisterende funksjon med annet formål
|
||||||
|
(sesjonsscoped, format-begrenset). I individuelle turneringer (flatt
|
||||||
|
felt, ADR-037) er splitting derimot en naturlig match: `individual_
|
||||||
|
leaderboard`-endepunktet fikk `class_id`/`class_name` lagt til i
|
||||||
|
SELECT+respons, men selve summerings-/sorteringslogikken er UENDRET —
|
||||||
|
frontend grupperer den allerede korrekt sorterte listen visuelt (stabil
|
||||||
|
gruppering bevarer riktig rangering per klasse), ingen ny motorlogikk i
|
||||||
|
`handicap_engine.py` trengtes (Copenhagen/BBB var allerede scope-
|
||||||
|
agnostiske på deltaker-mengde).
|
||||||
|
|
||||||
|
**Konsekvens:** `053_tournament_classes.sql`. Ny klasse-CRUD i
|
||||||
|
`tournaments.py` (delt, siden `tournament`-tabellen er delt). `Roster
|
||||||
|
EntryUpdate` (tidligere KUN `is_captain: bool` påkrevd) lagt om til
|
||||||
|
`exclude_unset`-PATCH-semantikk. Ny `PATCH .../participants/{id}` i
|
||||||
|
`individual_tournaments.py` (fantes ikke før). Frontend: "Klasser"-kort
|
||||||
|
i BÅDE `tournament-detail.tsx` og `individual-tournament-detail.tsx`,
|
||||||
|
utslag-forhåndsutfylling i `session-blind-draw.tsx`s `AddSlotForm` og
|
||||||
|
`individual-tournament-detail.tsx`s `AssignRoundParticipantControl`,
|
||||||
|
klasse-gruppert `LeaderboardTab` (individuelle turneringer). Se
|
||||||
|
CHANGELOG.md 2026-08-04 for full bygge-/verifiseringsdetalj (inkl. tall-
|
||||||
|
for-tall-bekreftet leaderboard-rangering per klasse i ekte nettleser).
|
||||||
|
**Rullet ut live 2026-08-04**, bruker bekreftet eksplisitt.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Åpne spørsmål (ikke besluttet ennå)
|
## Åpne spørsmål (ikke besluttet ennå)
|
||||||
|
|
||||||
Disse må avklares før eller under de relevante fasene:
|
Disse må avklares før eller under de relevante fasene:
|
||||||
|
|
|
||||||
88
CHANGELOG.md
88
CHANGELOG.md
|
|
@ -7032,3 +7032,91 @@ Neste steg:
|
||||||
så dette er samme build som scratch-verifisert, ikke i tillegg
|
så dette er samme build som scratch-verifisert, ikke i tillegg
|
||||||
egenhendig bekreftet mot ekte produksjonsdata. Bekreft ved neste
|
egenhendig bekreftet mot ekte produksjonsdata. Bekreft ved neste
|
||||||
faktiske turnering.
|
faktiske turnering.
|
||||||
|
17. **Konkurranseklasser ("Damer fra 44, Herrer fra 50+") — BYGGET,
|
||||||
|
SCRATCH-VERIFISERT OG LIVE 2026-08-04, migrasjon 053.** Brukeren
|
||||||
|
spurte om det var mulig å sette opp runder i en turnering slik at
|
||||||
|
f.eks. damer spiller fra utslag 44 mens herrer spiller fra 50+.
|
||||||
|
Svaret var at DELER allerede virket (hver deltaker i en match/runde
|
||||||
|
fikk allerede sitt eget `tee_id`, backend validerte allerede at
|
||||||
|
utslaget hadde rating for spillerens kjønn) -- men et manuelt valg
|
||||||
|
per spiller hver gang, ingen gjenbrukbar "klasse". Brukeren ba om en
|
||||||
|
ekte klasse-mekanisme, "samt andre parametre som er relevante i en
|
||||||
|
slik problemstilling."
|
||||||
|
Full plan-modus-runde med to `AskUserQuestion`-avklaringer FØR
|
||||||
|
bygging (samme disiplin som ADR-037/ADR-039): (1) klasser er FRITT
|
||||||
|
NAVNGITTE (ikke bare kjønn) med et valgfritt standardutslag, ikke en
|
||||||
|
fast kjønn+alder-modell -- dekker kjønn/alder/HCP eller annet uten at
|
||||||
|
systemet må forstå forskjellen; (2) klasse gir EGEN RESULTATLISTE --
|
||||||
|
men KUN i individuelle turneringer (ADR-037, flatt felt). I
|
||||||
|
lagturneringer (ADR-011, to lag) er poeng knyttet til hele kamper,
|
||||||
|
ikke enkeltspillere -- brukeren bekreftet eksplisitt at klasse der
|
||||||
|
KUN skal foreslå utslag, ingen leaderboard-splitting (det finnes fra
|
||||||
|
før et smalt per-økt individuelt leaderboard for singles/fourball-
|
||||||
|
slagspill, `fetch_individual_leaderboard` -- IKKE noe denne runden
|
||||||
|
bygger videre på); (3) gjelder org-lagturneringer OG org-individuelle
|
||||||
|
turneringer, ikke frittstående personlige runder.
|
||||||
|
**Skjema** (`053_tournament_classes.sql`): ny delt `tournament_class`-
|
||||||
|
tabell (id/organization_id/tournament_id/name/default_tee_id,
|
||||||
|
`UNIQUE(tournament_id, name)`) -- delt mellom begge turneringstyper
|
||||||
|
siden begge peker til samme `tournament`-tabell (ADR-037s
|
||||||
|
`format_type`-mønster), unngår duplisering. To nye NULLABLE FK-
|
||||||
|
kolonner (`ON DELETE SET NULL`, samme mønster som `tournament_round_
|
||||||
|
bbb_hole`): `team_roster.class_id` og `tournament_participant.
|
||||||
|
class_id`. Samme `org_isolation`-RLS-loop som migrasjon 040.
|
||||||
|
**Backend**: ny klasse-CRUD (`GET/POST/PATCH/DELETE .../classes`) i
|
||||||
|
`tournaments.py` (delt fil, siden `tournament`-tabellen er delt).
|
||||||
|
`RosterEntryCreate`/`RosterEntry` fikk `class_id`/`class_name`;
|
||||||
|
`RosterEntryUpdate` (tidligere KUN `is_captain: bool` påkrevd)
|
||||||
|
lagt om til `exclude_unset`-PATCH-semantikk (samme mønster som
|
||||||
|
`TournamentUpdate`/`SponsorUpdate` fra presentasjons-panel-runden)
|
||||||
|
slik at klasse kan settes uten å tvinge et samtidig kaptein-valg.
|
||||||
|
`TournamentParticipantCreate`/`Out` (individual_tournaments.py) fikk
|
||||||
|
samme felt, pluss en NY `PATCH .../participants/{id}` (fantes ikke
|
||||||
|
før -- kun POST/GET/DELETE). `individual_leaderboard` utvidet med
|
||||||
|
`class_id`/`class_name` i SELECT+respons -- selve summerings-/
|
||||||
|
sorteringslogikken UENDRET, frontend grupperer den allerede sorterte
|
||||||
|
listen visuelt (stabil gruppering bevarer riktig rangering per
|
||||||
|
klasse, ingen ny motorlogikk i `handicap_engine.py` -- verifisert:
|
||||||
|
98/98 eksisterende enhetstester fortsatt grønne, ingen regresjon).
|
||||||
|
**Frontend**: "Klasser"-kort (opprett/slett, kaskaderende bane→
|
||||||
|
utslag-velger for standardutslag) i BÅDE `tournament-detail.tsx`
|
||||||
|
("Lag og spillere"-fanen) og `individual-tournament-detail.tsx`
|
||||||
|
(Oppsett-fanen). Utslag-forhåndsutfylling i to steder --
|
||||||
|
`session-blind-draw.tsx`s `AddSlotForm` (lagturneringer) og
|
||||||
|
`individual-tournament-detail.tsx`s `AssignRoundParticipantControl`
|
||||||
|
(individuelle turneringer) -- begge en `useEffect` som slår opp valgt
|
||||||
|
spillers klasse → standardutslag når spilleren velges, KUN hvis det
|
||||||
|
utslaget faktisk finnes på DENNE øktens/rundens bane (klassens
|
||||||
|
standardutslag kan tilhøre en annen bane), fortsatt fritt
|
||||||
|
overstyrbart. Ren frontend-bekvemmelighet, samme "gjenbruk et
|
||||||
|
eksisterende felt, ikke en ny backend-mekanisme"-prinsipp som
|
||||||
|
`new-round.tsx`s eksisterende kjønnsfilter/-default. `LeaderboardTab`
|
||||||
|
(individuelle turneringer) grupperer den mottatte, allerede sorterte
|
||||||
|
listen på `class_id`, hver klasse får egen seksjonsoverskrift +
|
||||||
|
egen 1/2/3-rangering INNAD i klassen -- ingen klasser opprettet =
|
||||||
|
identisk med tidligere flat visning, bakoverkompatibelt uten
|
||||||
|
migrasjonsflagg.
|
||||||
|
**Scratch-verifisert grundig** (isolert `teecup_app_scratch`-rolle +
|
||||||
|
isolert scratch-MinIO + engangs API-/frontend-container, ekte
|
||||||
|
nettleser-innlogging inkl. 2FA): full API-rundtur (klasse-CRUD,
|
||||||
|
roster-/deltaker-PATCH med class_id, `ON DELETE SET NULL` bekreftet
|
||||||
|
ved klasseslettelse), ekte nettleser-klikk gjennom BEGGE
|
||||||
|
turneringstyper -- lagturnering: opprettet klasser via UI-skjemaet
|
||||||
|
(kaskaderende bane→utslag bekreftet), tildelte klasse via
|
||||||
|
dropdown-menyen, bekreftet utslag forhåndsvalgt korrekt idet en
|
||||||
|
spiller med klasse ble valgt i `AddSlotForm` (Kari→44, Ola→56);
|
||||||
|
individuell turnering: samme mønster i `AssignRoundParticipantControl`
|
||||||
|
(Bjørn Ege→56), pluss det klasse-delte leaderboardet bekreftet
|
||||||
|
visuelt korrekt -- "DAMER"-seksjon viste Kari (72 slag, rang 1) foran
|
||||||
|
Siv (108 slag, rang 2), "HERRER" viste Ola alene (90 slag, rang 1),
|
||||||
|
tallene håndregnet og stemte eksakt (par/+18/+36 mot faktisk
|
||||||
|
innsendt score). `test_isolation.sql` 12/12 uendret, ekte
|
||||||
|
typesjekket produksjonsbuild (fanget og rettet ETT reelt
|
||||||
|
TypeScript-funn under selve verifiseringen: `classes`-propen manglet
|
||||||
|
på `TeamColumn` i `session-blind-draw.tsx` -- `AddSlotForm` ligger i
|
||||||
|
en underkomponent som ikke automatisk arver overordnet komponents
|
||||||
|
state, måtte tres eksplisitt gjennom).
|
||||||
|
**Rullet ut live 2026-08-04**, bruker bekreftet eksplisitt: migrasjon
|
||||||
|
053 mot ekte `teecup_db`, `docker compose up -d --build teecup_api
|
||||||
|
teecup_frontend`, begge containere boot-et rent, `/health`/
|
||||||
|
`/dashboard` → 200.
|
||||||
|
|
|
||||||
|
|
@ -3967,6 +3967,53 @@ IKKE stilt til V0 ennå. Egen, senere, liten vurdering om ønskelig.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Konkurranseklasser ("Damer fra 44, Herrer fra 50+") — ✅ HELT FERDIG, BYGGET, SCRATCH-/BROWSERVERIFISERT OG LIVE 2026-08-04 (ADR-041)
|
||||||
|
|
||||||
|
Brukeren spurte om det var mulig å sette opp runder i en turnering slik
|
||||||
|
at f.eks. damer spiller fra utslag 44 mens herrer spiller fra 50+. Full
|
||||||
|
plan-modus-runde med to `AskUserQuestion`-avklaringer FØR bygging (samme
|
||||||
|
disiplin som ADR-037/039) — se ADR-041 for de fire load-bærende
|
||||||
|
beslutningene (fritt navngitte klasser, delt tabell mellom begge
|
||||||
|
turneringstyper, standardutslag som ren frontend-bekvemmelighet, og —
|
||||||
|
den mest substansielle avklaringen — egen resultatliste KUN i
|
||||||
|
individuelle turneringer, aldri i lagturneringer siden poeng der er
|
||||||
|
knyttet til hele kamper).
|
||||||
|
|
||||||
|
Kort: ny `tournament_class`-tabell (migrasjon 053, org-isolert RLS) +
|
||||||
|
nullable `class_id` på `team_roster`/`tournament_participant` (`ON
|
||||||
|
DELETE SET NULL`). Organisator oppretter klasser med navn + valgfritt
|
||||||
|
standardutslag i et nytt "Klasser"-kort (BÅDE `tournament-detail.tsx` og
|
||||||
|
`individual-tournament-detail.tsx`). Standardutslaget forhåndsvelges
|
||||||
|
automatisk når en spiller med klasse legges til en match/runde (fortsatt
|
||||||
|
overstyrbart) — INGEN endring i selve `tee_id`-kontrakten, som allerede
|
||||||
|
var required og satt per deltaker. I individuelle turneringer deler
|
||||||
|
`individual_leaderboard` seg nå i egne, riktig rangerte seksjoner per
|
||||||
|
klasse; i lagturneringer er klasse bevisst KUN et utslag-forslag, ingen
|
||||||
|
leaderboard-endring (bekreftet med bruker — matchpoeng er lag-mot-lag,
|
||||||
|
ikke enkeltspiller-atomisk).
|
||||||
|
|
||||||
|
**Scratch-/browserverifisert grundig** (isolert `teecup_app_scratch`-
|
||||||
|
rolle + engangs API-/frontend-container, ekte nettleser-innlogging inkl.
|
||||||
|
2FA): full API-rundtur, ekte klikk gjennom BEGGE turneringstyper —
|
||||||
|
kaskaderende bane→utslag-velger ved klasse-opprettelse, dropdown-
|
||||||
|
klassetildeling, utslag-forhåndsutfylling bekreftet i `AddSlotForm` OG
|
||||||
|
`AssignRoundParticipantControl`, og det klasse-delte leaderboardet
|
||||||
|
tall-for-tall bekreftet korrekt (Damer: Kari 72 slag rang 1, Siv 108
|
||||||
|
slag rang 2; Herrer: Ola 90 slag rang 1 — alle mot håndregnet
|
||||||
|
slagsum). 98/98 eksisterende `handicap_engine.py`-enhetstester uendret
|
||||||
|
(ingen ny motorlogikk), `test_isolation.sql` 12/12 uendret. Ett reelt
|
||||||
|
TypeScript-funn under selve verifiseringen (ikke antatt riktig fra
|
||||||
|
implementasjonen alene): `classes`-propen manglet på `TeamColumn` i
|
||||||
|
`session-blind-draw.tsx` (egen underkomponent, arver ikke overordnet
|
||||||
|
komponents state automatisk) — fanget av produksjonsbuildens
|
||||||
|
typesjekk, rettet før utrulling.
|
||||||
|
|
||||||
|
**Rullet ut live 2026-08-04**, bruker bekreftet eksplisitt: migrasjon
|
||||||
|
053 mot ekte `teecup_db`, `docker compose up -d --build teecup_api
|
||||||
|
teecup_frontend`. Full detalj i CHANGELOG.md 2026-08-04 og ADR-041.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Bevisst endret fra opprinnelige (Gemini-)råd
|
## Bevisst endret fra opprinnelige (Gemini-)råd
|
||||||
|
|
||||||
- 🔀 **Banedata:** API mot teeoff (ADR-004), IKKE direkte delt database. Direkte
|
- 🔀 **Banedata:** API mot teeoff (ADR-004), IKKE direkte delt database. Direkte
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue