Dashbordet er bygget (zip 18 integrert): kun dashboard.tsx var reelt nytt fra V0, og jeg fant en genuin merge-situasjon i tournament-card.tsx — V0s nye "Arrangør"-merkelapp lagt til ved siden av den eksisterende offentlig/innlogget-lenkelogikken, ikke en revert. "Ny turnering" implementerer nå selve ADR-035-mekanismen (usynlig org-opprettelse ved innsending), "Statistikk"/"Spilte baner" er ren klientside-utledning fra data vi allerede har, og "Venner" viser en ærlig tom-tilstand siden ADR-036 ikke er bygget ennå. Typesjekket produksjonsbuild kompilerte rent.
Notert og bekreftet: Medspillere skal kunne registrere score for hele flighten, ikke bare egen rad — oppdatert i ADR-036 (sletting av runden/bane-bytte forblir eier-eksklusivt). To nye backlog-notater: flytte spillere mellom lag i turneringsoppsett, og flere flighter i én frittstående runde (sistnevnte har en reell modelleringsspenning mellom to retninger — ikke besluttet, bør trolig vente til ADR-036 fase 1 er bygget).
This commit is contained in:
parent
f88d0a1469
commit
c8c4ad29b6
7 changed files with 1220 additions and 580 deletions
13
.claude/settings.json
Normal file
13
.claude/settings.json
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(find / -maxdepth 3 -iname \"*zip*18*\")",
|
||||
"Bash(find / -maxdepth 4 -iname \"*.zip\" -mmin -120)",
|
||||
"Bash(rm -rf /tmp/claude-1000/-opt-teecup/a8bd2fc3-4b9c-4682-a2be-cf36e143de78/scratchpad/zip18)",
|
||||
"Bash(mkdir -p /tmp/claude-1000/-opt-teecup/a8bd2fc3-4b9c-4682-a2be-cf36e143de78/scratchpad/zip18)",
|
||||
"Bash(unzip -q \"/opt/teecup/tee-cup-login-screen \\(18\\).zip\")",
|
||||
"Bash(python3 -m zipfile -e \"/opt/teecup/tee-cup-login-screen \\(18\\).zip\" .)",
|
||||
"Bash(grep -v \"ui/dropdown-menu\\\\|^.*DropdownMenuItem,$\\\\|import\")"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -2808,6 +2808,242 @@ ekte https, `teeoff.no` upåvirket.
|
|||
|
||||
---
|
||||
|
||||
## ADR-035: Dashbord-redesign — organisasjon blir implisitt
|
||||
|
||||
Direkte oppfølging av en refleksjonsrunde 2026-07-25: brukeren spurte
|
||||
eksplisitt hvorfor organisasjon i det hele tatt trengs, gitt at en enkelt
|
||||
bruker som vil sette opp ÉN turnering for en vennegjeng ikke får noe igjen
|
||||
for opprettelses-seremonien. To alternativer ble veid opp mot hverandre:
|
||||
|
||||
- **A — bruker-eide turneringer** (samme mønster som ADR-033 sine
|
||||
frittstående runder, `user_id`-eierskap, ingen RLS): AVVIST. Praktisk
|
||||
talt HELE turnering-apparatet (lag/roster/blind draw/scoring/chat/
|
||||
leaderboard/offentlig side, se CLAUDE.md sin arkitektur-invariant om
|
||||
`organization_id` på alle domenetabeller) er bygget rundt RLS og
|
||||
org-medlemskap. Å gjøre turneringer bruker-eide ville krevd enten en
|
||||
full duplisering av dette apparatet i en parallell, RLS-fri variant,
|
||||
eller å gjøre `organization_id` valgfri overalt — et brudd på
|
||||
invarianten CLAUDE.md eksplisitt krever en ny ADR for, med en
|
||||
reverseringskostnad som går GALT begge veier (migrere eksisterende
|
||||
bruker-eide turneringer inn i organisasjoner senere, eller gjenoppfinne
|
||||
medadministrasjon fra bunnen om den viser seg nødvendig uansett).
|
||||
- **B — organisasjon beholdes, men opprettelsen gjøres usynlig/automatisk**:
|
||||
VALGT. Rører verken skjema, RLS eller noen av de ni routerne som
|
||||
allerede er bygget rundt organisasjon — alt fortsetter å virke uendret.
|
||||
Kun UX-seremonien fjernes.
|
||||
|
||||
### Beslutning A — Hva "usynlig organisasjon" betyr konkret
|
||||
|
||||
`POST /orgs` (`app/routers/organizations.py`) krever i dag KUN `name` —
|
||||
verifisert direkte i koden: `slug`/`public_profile` settes separat via
|
||||
`PATCH /orgs/{id}` (ADR-018), ikke ved opprettelse. Dette betyr at
|
||||
"usynlig opprettelse" krever **null backend-endring** — kun en endret
|
||||
frontend-orkestrering:
|
||||
|
||||
- Trykker en bruker "Ny turnering" og har PRESIS ÉN organisasjon fra før:
|
||||
den gjenbrukes direkte, ingen synlig org-steg.
|
||||
- Har brukeren INGEN organisasjon ennå: `POST /orgs` kalles automatisk med
|
||||
et generert navn (`"{fornavn} {etternavn}s turneringer"`, eller
|
||||
`"Mine turneringer"` som fallback hvis navn mangler) FØR turnering-
|
||||
opprettelsen vises — brukeren ser aldri et eget "opprett organisasjon"-
|
||||
skjema.
|
||||
- Har brukeren FLERE organisasjoner (f.eks. fordi de også er invitert inn
|
||||
i en ekte klubb, ADR-022): et lett org-valg vises FØRST da — samme
|
||||
`OrganizationView`-mønster som i dag, men kun synlig i dette ene
|
||||
tilfellet, ikke som standard.
|
||||
- Alt annet er UENDRET: en bruker som ønsker en ekte klubb-identitet
|
||||
(navn, slug, offentlig side, medadministratorer) kan fortsatt navngi
|
||||
orgen sin og bygge den ut senere — B fjerner kun ceremonien ved
|
||||
FØRSTE opprettelse, ikke noen av de eksisterende org-funksjonene.
|
||||
|
||||
### Reversibilitet
|
||||
|
||||
B kan reverseres på en ettermiddag: legg navnesteget tilbake i UI-flyten
|
||||
FØR "Ny turnering" fullføres. Ingen datamigrering — eksisterende org-rader
|
||||
er identiske uansett om de ble navngitt av brukeren eller auto-generert.
|
||||
|
||||
**Status: 📋 DESIGNET 2026-07-25, IKKE BYGGET.** Se
|
||||
"Dashbord: tom-tilstand"-seksjonen i FEATURE_BACKLOG.md for det fulle
|
||||
blokk-forslaget og V0-prompten som ble skrevet i samme runde.
|
||||
|
||||
---
|
||||
|
||||
## ADR-036: Venner, kategorisert deling av runder, og tiered personsøk for medspillere
|
||||
|
||||
Reist av brukeren 2026-07-25, samme runde som ADR-035. To sammenhengende
|
||||
behov: (1) når man legger til en medspiller på en frittstående runde, skal
|
||||
det søkes opp EKTE personer — venner FØRST, deretter samme hjemmeklubb,
|
||||
deretter samme land, til slutt globalt, uavhengig av om for- eller
|
||||
etternavn skrives først, i samme UI-mønster som bane-/klubbsøket; (2)
|
||||
appen skal ha et fullverdig vennekonsept, der venner (med mindre runden er
|
||||
satt til "Privat") kan se livescoren din, og der DU kan kategorisere hver
|
||||
venn i én eller flere av et fast sett grupper — uten at vennen selv vet
|
||||
hvilke grupper du har puttet dem i.
|
||||
|
||||
**Direkte oppfølging av et allerede notert, men avvist punkt:** ADR-033
|
||||
Beslutning D satte `round_participant.user_id` i skjemaet, men avgrenset
|
||||
bevisst til KUN gjeste-deltakere i v1 ("en deltaker med `user_id` satt får
|
||||
IKKE egen tilgang til runden"), med e-post-kobling notert som en mulig,
|
||||
ikke-designet senere utvidelse. Denne ADR-en erstatter e-post-kobling-
|
||||
ideen med noe som passer bedre til det brukeren faktisk ba om: ekte
|
||||
personsøk (samme mønster som bane/klubb), ikke en e-postadresse man må
|
||||
kjenne på forhånd.
|
||||
|
||||
### Beslutning A — Vennskap er gjensidig; kategorisering er privat og ensidig
|
||||
|
||||
Et vennskap krever en forespørsel + aksept (samme grunnmønster som
|
||||
organisasjon-invitasjoner, ADR-022) — "venner ser livescoren din" gir kun
|
||||
mening som et GJENSIDIG, bekreftet forhold, ikke en ensidig følging.
|
||||
Kategoriseringen ("Make", "Golfvenner" osv.) er derimot et HELT SEPARAT,
|
||||
privat attributt EIET av den som kategoriserer — A kan sette B i
|
||||
"Golfvenner" uten at B noensinne får vite det, og B kategoriserer A helt
|
||||
uavhengig (kan sette A i en annen gruppe, eller ingen). Dette er bevisst
|
||||
samme idé som Facebooks "nære venner"-lister: vennskapet er symmetrisk,
|
||||
men grupperingen er det ikke.
|
||||
|
||||
**Datamodell (arbeidsnavn, avgjøres ved migrasjonsskriving):**
|
||||
- `friendship`: `requester_user_id`, `addressee_user_id`, `status`
|
||||
(`pending`/`accepted`/`declined`), tidsstempler. Et UNIK
|
||||
uttrykks-indeks på `(LEAST(requester_user_id, addressee_user_id),
|
||||
GREATEST(...))` hindrer duplikate forespørsler i begge retninger
|
||||
samtidig.
|
||||
- Kategori er IKKE en egen tabell — et fast, CHECK-constrained sett
|
||||
(samme mønster som `BAG_CLUBS`/`gender`/`stat_level` ellers i appen),
|
||||
ikke brukerdefinerbart: `spouse` (Make), `close_family` (Nær familie),
|
||||
`extended_family` (Storfamilie), `close_friends` (Nære venner),
|
||||
`golf_friends` (Golfvenner), `colleagues` (Kollegaer), `business`
|
||||
(Forretningsforbindelser), `classmates` (Studiekamerater),
|
||||
`acquaintances` (Perifere bekjente), `other` (Ymse).
|
||||
- `friend_categorization`: `owner_user_id`, `friend_user_id`, `category`
|
||||
— én rad PER kategori en venn er satt i (en venn kan ha flere rader,
|
||||
"de skal kunne være tilknyttet forskjellige kategorier"). Håndheves i
|
||||
app-laget (skriving krever en `accepted`-vennskapsrad mellom de to),
|
||||
ikke en direkte FK til `friendship` (unngår å måtte holde styr på
|
||||
requester/addressee-retning to steder).
|
||||
|
||||
### Beslutning B — Rundevisibilitet: tre nivåer, samme struktur som turnering, men egen mekanisme
|
||||
|
||||
`round` får `visibility_mode` (`public`/`private`/`friends`, default
|
||||
`private` — trygg standard, samme filosofi som RLS-policyenes "se
|
||||
ingenting" ved manglende kontekst). Når `friends` er valgt: hvilke
|
||||
KATEGORIER som får se runden velges eksplisitt (`round_visible_category`,
|
||||
`round_id`+`category`) — ikke "alle venner", siden brukeren eksplisitt ba
|
||||
om å velge blant gruppene sine ved rundestart.
|
||||
|
||||
**Viktig presisering, unngår en reell forvekslingsfelle:** dette er
|
||||
ADSKILT fra om noen er lagt til som faktisk MEDSPILLER (Beslutning C
|
||||
under). En medspiller du har lagt til ser ALLTID runden dere spiller
|
||||
sammen, uavhengig av `visibility_mode` — visibility-nivået styrer kun
|
||||
TREDJEPARTS innsyn (venner/offentligheten), ikke de som faktisk er med i
|
||||
flighten.
|
||||
|
||||
**Autorisasjonssjekk** (app-lag, `plain_connection()`-mønsteret fra
|
||||
ADR-033 Beslutning A — INGEN RLS, samme begrunnelse som der):
|
||||
1. `viewer == round.owner_user_id` → alltid tilgang.
|
||||
2. `viewer` er en lenket medspiller (`round_participant.user_id ==
|
||||
viewer`) → alltid tilgang til DEN runden.
|
||||
3. `visibility_mode == 'public'` → alle, også anonyme (samme mønster som
|
||||
turneringers offentlige side).
|
||||
4. `visibility_mode == 'private'` → kun 1+2.
|
||||
5. `visibility_mode == 'friends'` → krever innlogget bruker MED en
|
||||
`accepted`-vennskapsrad til eieren OG minst én
|
||||
`friend_categorization`-rad (`owner_user_id=eier, friend_user_id=
|
||||
viewer`) hvor kategorien finnes i `round_visible_category` for akkurat
|
||||
denne runden. Legg merke til retningen: det er EIERENS kategorisering
|
||||
av VIEWER som brukes, ikke omvendt — riktig, siden det er eieren som
|
||||
begrenser hvem som får se, basert på eierens egen gruppering.
|
||||
|
||||
**"Livescore"** — forstått som sanntidsoppdatering mens runden pågår,
|
||||
samme idé som turnering sin `/t/[id]/live` (ADR-027). Gjenbruker samme
|
||||
kringkastingsmønster (`app/realtime.py`, `broadcast_live_update`) — en
|
||||
tilsvarende funksjon for runder, kringkastet ved hver hull-PATCH når
|
||||
`visibility_mode != 'private'`, med et WS-endepunkt gated av samme
|
||||
autorisasjonssjekk som over.
|
||||
|
||||
### Beslutning C — Tiered personsøk: delt mellom "finn venn" og "legg til medspiller"
|
||||
|
||||
Samme underliggende endepunkt brukes til BEGGE formål (finn en venn å
|
||||
sende forespørsel til, OG søk opp en medspiller å legge til på en runde)
|
||||
— begge er i essens "finn en person", kun hva som skjer ETTER valg
|
||||
skiller dem. Foreslått: `GET /people/search?q=...`.
|
||||
|
||||
**Navnerekkefølge-uavhengig matching:** spørringen splittes i tokens
|
||||
(mellomrom-separert). For HVER token må minst ett av `first_name`/
|
||||
`last_name` matche (`ILIKE token||'%'`) — ALLE tokens må matche (AND på
|
||||
tvers av tokens, OR på tvers av feltene per token). Dette gjør at "Erol
|
||||
Haagenrud" og "Haagenrud Erol" gir identisk treff, uten noen spesiell
|
||||
"gjett rekkefølgen"-logikk — det faller naturlig ut av at hvert ord kan
|
||||
matche HVILKET SOM HELST av de to feltene.
|
||||
|
||||
**Tiered rangering, én spørring:** en beregnet prioritet per kandidat —
|
||||
0 hvis venn (uavhengig av kategorisering — ALLE venner, ikke bare de i
|
||||
en bestemt gruppe, siden dette er søk-for-å-legge-til, ikke visibility-
|
||||
sjekken over), 1 hvis samme `home_club` som søkeren (nå en pålitelig
|
||||
eksakt streng siden ADR-025-runden 2026-07-25 gjorde Hjemmeklubb til en
|
||||
ekte dropdown-verdi i stedet for fritekst — retroaktivt en god
|
||||
begrunnelse for den endringen), 2 hvis samme `country`, 3 ellers.
|
||||
`ORDER BY prioritet, fornavn, etternavn LIMIT 20` gir venner-først uten
|
||||
behov for separate spørringer per nivå.
|
||||
|
||||
**Personvernhensyn, bevisst innebygd i designet, ikke tilføyd i
|
||||
etterkant:**
|
||||
- Svaret inneholder KUN navn, avatar, hjemmeklubb — ALDRI e-post/mobil/
|
||||
fødselsdato.
|
||||
- Foreslått minimum 2 tegn i søket før noe returneres i det hele tatt
|
||||
(hindrer triviell enumerering av alle brukere via ett enkelt
|
||||
bokstavsøk) — MIN anbefaling, ikke bekreftet med bruker.
|
||||
- Kun innloggede brukere kan søke (`get_current_user`, ikke anonymt).
|
||||
|
||||
### Beslutning D — Byggerekkefølge (foreslått, IKKE bekreftet)
|
||||
|
||||
Gitt omfanget (nytt vennekonsept + ny rundevisibilitet + nytt delt
|
||||
søkeendepunkt + sanntidsutvidelse) foreslås tre uavhengig leverbare faser,
|
||||
samme "bygg i rekkefølgen ting brukes"-prinsipp som resten av prosjektet:
|
||||
|
||||
1. **Venner-kjernen**: `friendship`+`friend_categorization`, forespørsel/
|
||||
aksept/fjern-endepunkter, `/people/search`, en ny `/friends`-side
|
||||
(søk, forespørsler, kategoriser). Leverbar og nyttig helt alene.
|
||||
2. **Rundevisibilitet**: `round.visibility_mode`+`round_visible_category`,
|
||||
valg ved rundestart, `can_view_round`-gatede lese-endepunkter for
|
||||
ikke-eiere, sanntidsutvidelse for live-visning. Avhenger av fase 1.
|
||||
3. **Ekte medspillere** (ikke bare gjester): utvid `POST .../participants`
|
||||
til å godta et søkt `user_id` i tillegg til `guest_name`. Avhenger av
|
||||
fase 1 (samme søk). **Avklart med bruker 2026-07-25: JA** — en
|
||||
lagt-til ekte medspiller skal se runden i SIN EGEN "Egne runder"-liste,
|
||||
ikke bare eieren.
|
||||
**Konkret teknisk konsekvens, presisert her siden det ikke er
|
||||
opplagt:** `list_rounds` filtrerer i dag KUN på `owner_user_id`, og
|
||||
`RoundOut` sine `owner_holes_played`/`owner_total_score`/
|
||||
`owner_score_to_par`-felt (lagt til 2026-07-25, se status) er alltid
|
||||
utledet fra EIERENS `round_participant`-rad. For en medspiller som
|
||||
ser runden i SIN liste må disse tallene i stedet vise DERES EGEN
|
||||
score i runden, ikke eierens — feltene må derfor bli
|
||||
"viewer-relative" (utledet fra HVILKEN SOM HELST deltaker-rad som
|
||||
matcher innlogget bruker, enten `is_owner` eller lenket `user_id`),
|
||||
ikke hardkodet til `is_owner=true`-raden. `list_rounds`-spørringen må
|
||||
utvides til `WHERE owner_user_id = $1 OR id IN (SELECT round_id FROM
|
||||
round_participant WHERE user_id = $1)`. Ingen endring i selve
|
||||
eierskapet (`round.owner_user_id` er fortsatt entydig én person).
|
||||
**Skrivetilgang avklart med bruker 2026-07-25: en medspiller skal
|
||||
kunne registrere score for ALLE i flighten**, ikke bare sin egen rad
|
||||
— samme skrivetilgang som eieren allerede har i dag (via
|
||||
`_get_owned_round_or_404`), nå utvidet til å gjelde ENHVER lenket
|
||||
ekte deltaker (`round_participant.user_id`), ikke kun eieren. Praktisk
|
||||
presisering: dette gjelder KUN hull-registrering
|
||||
(`PATCH .../participants/{id}/holes/{hole}`) og legg-til-deltaker —
|
||||
sletting av selve runden og bane-/utslagsbytte (`DELETE /rounds/{id}`,
|
||||
`PATCH /rounds/{id}` sine bane-felt) forblir eier-eksklusivt, siden
|
||||
disse er destruktive/strukturelle handlinger uavhengig av hvem som
|
||||
fører score. Autorisasjonssjekken for hull-PATCH blir dermed:
|
||||
`viewer == owner_user_id OR viewer IN (SELECT user_id FROM
|
||||
round_participant WHERE round_id = $1 AND user_id IS NOT NULL)`.
|
||||
|
||||
**Status: 📋 DESIGNET 2026-07-25, IKKE BYGGET.** Se "Venner og
|
||||
kategorisert deling"-seksjonen i FEATURE_BACKLOG.md for åpne spørsmål og
|
||||
videre kontekst.
|
||||
|
||||
---
|
||||
|
||||
## Åpne spørsmål (ikke besluttet ennå)
|
||||
|
||||
Disse må avklares før eller under de relevante fasene:
|
||||
|
|
|
|||
89
CLAUDE.md
89
CLAUDE.md
|
|
@ -2574,17 +2574,86 @@ Ferdig og verifisert:
|
|||
12/12, begge containere redeployet, `/health`/`/dashboard`/`/my-rounds`/
|
||||
`/account` → 200, `teeoff.no` upåvirket.
|
||||
|
||||
- **Refleksjonsrunde 2026-07-25: hvorfor organisasjon? + venner/deling —
|
||||
DESIGNET, IKKE bygget.** Brukeren spurte hvorfor organisasjon i det
|
||||
hele tatt trengs, gitt at ADR-033 nå gjør en enkelt bruker fullt
|
||||
selvstendig. Veide A (bruker-eide turneringer, som runder) mot B
|
||||
(organisasjon beholdt, men opprettelsen gjøres usynlig/automatisk) —
|
||||
A avvist (ville krevd duplisering av HELE turnering-apparatet som er
|
||||
bygget rundt RLS/`organization_id`, og er ikke reversibelt i noen
|
||||
retning), B valgt (rører verken skjema eller de ni eksisterende
|
||||
routerne, kun frontend-orkestrering — `POST /orgs` krever allerede kun
|
||||
`name`). Skrevet som **ADR-035** (organisasjon-B-beslutningen + et
|
||||
konkret 7-blokks dashbord-forslag: Hurtighandlinger/Kommende runder/
|
||||
Kommende turneringer/Statistikk/Spilte baner/Venner/Organisasjoner —
|
||||
sistnevnte nedtonet, kun synlig ved reelt flere org-er) og **ADR-036**
|
||||
(nytt vennekonsept — gjensidig forespørsel/aksept, privat
|
||||
kategorisering i faste grupper som Make/Nær familie/Golfvenner/osv.,
|
||||
ny rundevisibilitet `public`/`private`/`friends` med eksplisitt
|
||||
gruppevalg, og et tiered personsøk — venner→samme klubb→samme
|
||||
land→globalt, navnerekkefølge-uavhengig — delt mellom "finn venn" og
|
||||
en fremtidig "legg til ekte medspiller"-utvidelse av
|
||||
`round_participant.user_id`, som allerede lå ubrukt i skjemaet som en
|
||||
eksplisitt notert "v1-avgrensning" i ADR-033). V0-prompt for det nye
|
||||
dashbordet skrevet (i FEATURE_BACKLOG.md), IKKE sendt til V0 ennå.
|
||||
**Ingen kode skrevet** — bevisst en design-/dokumentasjonsrunde, ikke
|
||||
en byggerunde, på brukerens eksplisitte instruks. Full detalj i
|
||||
ARCHITECTURE_DECISIONS.md (ADR-035/036) og FEATURE_BACKLOG.md (åpne
|
||||
spørsmål, foreslått 3-fase byggerekkefølge for venner-delen).
|
||||
- **Oppfølging samme dag:** bruker bekreftet at en lagt-til ekte
|
||||
medspiller SKAL se runden i sin egen "Egne runder"-liste (ADR-036 fase
|
||||
3, tidligere bevisst uavklart). Presiserte samtidig en ny teknisk
|
||||
konsekvens i ARCHITECTURE_DECISIONS.md: `RoundOut` sine
|
||||
`owner_*`-statistikkfelt må bli viewer-relative, ikke alltid eierens,
|
||||
og et NYTT åpent spørsmål dukket opp — skal medspilleren også kunne
|
||||
SKRIVE egne hull-tall, ikke bare lese? Ikke avgjort. Fortsatt ingen
|
||||
kode skrevet.
|
||||
|
||||
- **Dashbord-redesign (ADR-035) BYGGET, IKKE ENNÅ RULLET UT (2026-07-25):**
|
||||
zip 18 mottatt og integrert — kun `dashboard.tsx` var reelt nytt (samme
|
||||
full-reeksport-mønster som alltid), pluss en genuin MERGE (ikke revert)
|
||||
i `tournament-card.tsx`: V0s nye `organizer`-merkelapp lagt til SIDE OM
|
||||
SIDE med den eksisterende `orgId`-baserte lenkelogikken (offentlig vs.
|
||||
innlogget kontekst) som V0 ikke kjente til. Datalag skrevet fra bunnen:
|
||||
"Kommende turneringer" slår sammen deltaker- (`me.my_tournaments`) og
|
||||
arrangør-turneringer (hentet per org, alle organisasjoner brukeren er
|
||||
medlem i) til ÉN tidssortert liste, filtrert til `draft`/`active`-status.
|
||||
"Statistikk"/"Spilte baner" er REN klientside-utledning fra eksisterende
|
||||
`GET /rounds` + `GET /auth/profile/handicap-history` — ingen nye
|
||||
endepunkter trengt. "Ny turnering"-hurtighandlingen implementerer selve
|
||||
ADR-035-mekanismen: oppretter/gjenbruker organisasjon USYNLIG først
|
||||
(kun ved faktisk innsending, ikke når skjemaet åpnes — unngår en
|
||||
foreldreløs org ved avbrutt skjema), deretter turneringen, deretter
|
||||
navigerer rett inn i den. "Bli med med kode" gjenbruker samme
|
||||
`by-code`-oppslag som `login-form.tsx` sin `JoinByCode`, nå som en
|
||||
dashbord-lokal variant. "Venner"-seksjonen vises med en ærlig
|
||||
tom-tilstand (ADR-036 er ikke bygget ennå) — CTA-en er bevisst uten
|
||||
href/onClick, ikke en lenke til noe som ikke finnes. "Spilte baner"
|
||||
fikk sine listeelementer gjort om til ren visning (ikke lenker) siden
|
||||
API-et ikke eksponerer noen stabil bane-id å lenke til per runde.
|
||||
Ekte typesjekket produksjonsbuild kompilerte rent, alle 21 ruter
|
||||
listet. **IKKE rullet ut ennå** — venter på brukerens bekreftelse
|
||||
(ren frontend-endring, ingen migrasjon).
|
||||
- **Oppfølging samme runde, avklart med bruker:** medspillere skal kunne
|
||||
registrere score for HELE flighten (ikke bare egen rad) når ADR-036
|
||||
fase 3 bygges — oppdatert i ARCHITECTURE_DECISIONS.md/FEATURE_BACKLOG.md.
|
||||
To nye notater lagt i FEATURE_BACKLOG.md (ingen design/bygging ennå,
|
||||
kun fanget opp): (1) turneringsoppsett mangler en vei til å FLYTTE en
|
||||
rostret spiller til et annet lag (kun fjerning finnes i dag), (2) et
|
||||
reelt modelleringsspørsmål om flere flighter i én frittstående runde
|
||||
(f.eks. "min flight + vennenes flight bak oss samme dag") — to
|
||||
prinsipielt ulike retninger skissert, ingen valgt.
|
||||
|
||||
Neste steg:
|
||||
1. **Pauset, venter på retning:** dashbordets tom-tilstand ved første
|
||||
innlogging. Brukeren ba om å justere det opprinnelige 2026-07-20-
|
||||
forslaget i lys av et dypere spørsmål — bør organisasjon fortsatt være
|
||||
"det som meldes først"? Min vurdering (se FEATURE_BACKLOG.md): nei,
|
||||
bør bli ett likestilt valg blant flere. **Delvis besvart 2026-07-22:**
|
||||
den ALLER første tingen en ny/ufullstendig bruker nå ser er den
|
||||
obligatoriske profil-fullføringen (se status over), ikke selve
|
||||
dashbordet — men spørsmålet om HVA dashbordets tom-tilstand skal vise
|
||||
for en bruker som HAR fullført profilen, men ennå ikke har noen
|
||||
organisasjon/turnering, står fortsatt åpent.
|
||||
1. **Klart for bygging, venter på brukerens go-ahead:** dashbord-redesign
|
||||
(ADR-035) + venner/kategorisert deling (ADR-036), begge designet
|
||||
2026-07-25 (se status over og FEATURE_BACKLOG.md). Retningen er
|
||||
avklart (organisasjon blir usynlig/automatisk, dashbordet får syv
|
||||
konkrete blokker, venner bygges i tre uavhengige faser) — men INGEN
|
||||
av delene er bekreftet klar til bygging ennå. Naturlig neste steg:
|
||||
send V0-prompten for dashbordet (se FEATURE_BACKLOG.md) til v0.app,
|
||||
ELLER start på venner-kjernen (fase 1 av ADR-036), etter brukerens
|
||||
valg.
|
||||
3. **Frittstående rundeføring + detaljert statistikk — ADR-033 skrevet
|
||||
2026-07-22, IKKE bygget.** Brukeren avklarte 2026-07-22 at dette skal
|
||||
bli appens HOVEDFOKUS (turneringsoppsett skal bli ekstremt enkelt
|
||||
|
|
|
|||
|
|
@ -1329,7 +1329,7 @@ og vil derfor begge se profil-fullførings-skjemaet ved neste innlogging.
|
|||
|
||||
---
|
||||
|
||||
## Dashboard: tom-tilstand ved første innlogging — 📋 UNDER REVURDERING (2026-07-21), IKKE bygget
|
||||
## Dashboard: tom-tilstand ved første innlogging — 📋 KONKRET FORSLAG LAGT FREM (2026-07-25), IKKE bygget
|
||||
|
||||
Brukeren påpekte 2026-07-20 at dagens tomme-tilstand ("Du har ingen
|
||||
organisasjon ennå — opprett en") er organisator-vridd og ikke stemmer med
|
||||
|
|
@ -1381,6 +1381,222 @@ tom-skjermens endelige form kan bestemmes.
|
|||
|
||||
---
|
||||
|
||||
### 2026-07-25 — avhengigheten er løst, konkret forslag lagt frem (📋 DESIGNET, IKKE BYGGET)
|
||||
|
||||
Frittstående runder (ADR-033) er nå ferdig bygget (backend+frontend, alle
|
||||
oppfølgingsrunder), så blokkeringen over er borte. Brukeren reiste samtidig
|
||||
det dypere spørsmålet "hvorfor har vi organisasjon i det hele tatt" —
|
||||
besvart og designet som **ADR-035** (organisasjon beholdes, men
|
||||
opprettelsen gjøres usynlig/automatisk — Beslutning B, se
|
||||
ARCHITECTURE_DECISIONS.md for full A-vs-B-avveining og
|
||||
reversibilitetsvurdering).
|
||||
|
||||
**Konkret blokk-forslag for det nye dashbordet** (rekkefølge, topp til
|
||||
bunn):
|
||||
|
||||
1. **Hurtighandlinger** — tre likestilte kort/knapper: "Ny runde", "Ny
|
||||
turnering" (oppretter/gjenbruker organisasjon usynlig, ADR-035), "Bli
|
||||
med med kode" (ADR-020). Ingen av de tre skal kreve noe org-steg
|
||||
synlig for brukeren.
|
||||
2. **Kommende runder** — egne runder som ikke er fullført
|
||||
(`completed_at IS NULL`), sortert på dato, inntil 3 vist + "se alle"
|
||||
til `/my-rounds`. Tomtilstand: kort tekst + snarvei til "Ny runde".
|
||||
3. **Kommende turneringer** — SLÅR SAMMEN turneringer man er deltaker i
|
||||
(dagens "Mine runder"-data) OG turneringer man arrangerer (dagens
|
||||
organisasjons-turneringsliste, på tvers av ALLE organisasjoner
|
||||
brukeren er medlem i, flatt) til ÉN tidssortert liste. Kort man
|
||||
arrangerer får en liten "Arrangør"-merkelapp. Tomtilstand: snarvei til
|
||||
"Ny turnering"/"Bli med med kode".
|
||||
4. **Statistikk** — smått aggregert: antall runder spilt, HCP-trend
|
||||
(sparkline fra den eksisterende `handicap_history`-tabellen, kun vist
|
||||
ved ≥2 datapunkter), snitt til par siste 5 runder. Tomtilstand til
|
||||
minst én runde er fullført.
|
||||
5. **Spilte baner** — utledet fra `round.course_name_snapshot`, gruppert
|
||||
med besøksantall + sist spilt. Ingen ny datamodell trengs.
|
||||
6. **Venner** — kort med antall ventende forespørsler + snarvei til en ny
|
||||
`/friends`-side (se ADR-036 under). Tomtilstand: "Du har ingen venner
|
||||
ennå — søk etter noen".
|
||||
7. **Organisasjoner** — KUN vist hvis brukeren er medlem i mer enn den
|
||||
auto-opprettede sin egen (dvs. har en ekte, navngitt klubb-tilknytning)
|
||||
— én liten, nedtonet lenke, ikke en egen fremtredende seksjon. Dette er
|
||||
selve poenget med ADR-035: organisasjon skal ikke lenger dominere
|
||||
dashbordet.
|
||||
|
||||
**V0-prompt skrevet, IKKE sendt til V0 ennå** (venter på brukerens
|
||||
gjennomgang av blokk-forslaget over først):
|
||||
|
||||
> Design et nytt dashbord for TeeCup (golf-app, Next.js + Tailwind +
|
||||
> shadcn/ui, mobil-først, eksisterende merkevarefarger: grønn primær,
|
||||
> oransje sekundær — bruk appens eksisterende design-tokens, ikke nye
|
||||
> farger). Dette ERSTATTER dagens dashbord, som feilaktig satte
|
||||
> "organisasjon" som det første og viktigste en bruker møtte — ny
|
||||
> retning: brukeren er først og fremst en GOLFSPILLER, organisasjon er en
|
||||
> liten, valgfri detalj lengre ned.
|
||||
>
|
||||
> Innhold, i denne rekkefølgen, som distinkte kort/seksjoner (ikke faner):
|
||||
> 1. Hurtighandlinger: tre like store, likestilte knapper/kort side ved
|
||||
> side (stables på smal skjerm) — "Ny runde", "Ny turnering", "Bli med
|
||||
> med kode". Tydelige, tekstede (ikke kun ikon), store trykkflater.
|
||||
> 2. "Kommende runder" — liste over inntil 3 pågående/ikke-fullførte
|
||||
> runder (banenavn eller eget rundenavn, dato, en liten
|
||||
> fremdriftsindikator "X/18 hull"), med en "se alle"-lenke. Vis en
|
||||
> tydelig, vennlig tomtilstand med snarvei til "Ny runde" hvis ingen.
|
||||
> 3. "Kommende turneringer" — liste over turneringer brukeren enten
|
||||
> deltar i eller arrangerer, sortert på dato, en liten
|
||||
> "Arrangør"-merkelapp på kort man selv arrangerer. Tomtilstand med
|
||||
> snarveier til "Ny turnering"/"Bli med med kode".
|
||||
> 4. "Statistikk" — en kompakt rad med 2-3 nøkkeltall (antall runder,
|
||||
> HCP nå + en liten trendpil/sparkline, snitt til par) i staselige
|
||||
> tall-fliser (stort, fet skrift, høy kontrast).
|
||||
> 5. "Spilte baner" — en kompakt liste/rutenett av baner med
|
||||
> besøksantall og sist spilt-dato.
|
||||
> 6. "Venner" — et lite kort: avatar-stabel av noen få venner (om noen),
|
||||
> et tall-merke for ventende forespørsler, snarvei "Se venner".
|
||||
> Tomtilstand: oppfordring til å søke opp noen.
|
||||
> 7. "Organisasjoner" — KUN når relevant: én liten, nedtonet tekstlenke
|
||||
> nederst, IKKE et fremtredende kort — dette skal se ut som en
|
||||
> bakgrunnsdetalj, ikke en hovedseksjon.
|
||||
>
|
||||
> Tilgjengelighet er et ufravikelig krav, ikke en estetisk sluttpuss: god
|
||||
> kontrast, stor nok skrift, store trykkflater (min. 44px), ALDRI
|
||||
> ikon-only uten tekstlabel på viktige handlinger, appen skal være
|
||||
> brukbar uten finmotorikk eller skarpt syn. Design ALLE tomtilstander
|
||||
> eksplisitt, ikke bare den fylte varianten — de fleste nye brukere vil
|
||||
> se flere tomme blokker samtidig, og det skal fortsatt se innbydende ut,
|
||||
> ikke ufullstendig.
|
||||
|
||||
**Åpne spørsmål før bygging:**
|
||||
- Skal blokk 3 og 4 lenke til nye, dedikerte sider (f.eks. en egen
|
||||
aggregert statistikk-side), eller er de rene dashbord-widgets uten
|
||||
"se mer"? Statistikk-tallene over er enkle å beregne, men en FULL
|
||||
aggregert statistikk-side (grafer over tid på tvers av alle runder) er
|
||||
et større, eget stykke arbeid — ikke inkludert i dette forslaget.
|
||||
- Nøyaktig terskel for når "Organisasjoner"-lenken vises (mer enn 1 org
|
||||
totalt? Eller kun når minst én org har et eksplisitt satt `slug`/
|
||||
`public_profile`, dvs. faktisk er gjort til en "ekte" klubb?).
|
||||
|
||||
---
|
||||
|
||||
## Venner, kategorisert deling av runder, og tiered personsøk — 📋 DESIGNET 2026-07-25, IKKE bygget
|
||||
|
||||
Reist av brukeren samme runde som dashbord-forslaget over. Fullt design
|
||||
skrevet som **ADR-036** i ARCHITECTURE_DECISIONS.md — se der for
|
||||
datamodell, autorisasjonslogikk og søke-algoritme i detalj. Kort
|
||||
oppsummert her, pluss åpne spørsmål og foreslått byggerekkefølge.
|
||||
|
||||
**Tre sammenhengende deler:**
|
||||
1. Et ekte vennekonsept — gjensidig forespørsel/aksept (som org-
|
||||
invitasjoner), pluss et fast sett kategorier en venn kan settes i
|
||||
(flere samtidig): Make, Nær familie, Storfamilie, Nære venner,
|
||||
Golfvenner, Kollegaer, Forretningsforbindelser, Studiekamerater,
|
||||
Perifere bekjente, Ymse. **Kategoriseringen er privat** — vennen vet
|
||||
ikke hvilken/hvilke grupper du har satt dem i.
|
||||
2. Rundevisibilitet — ny `round.visibility_mode`
|
||||
(`public`/`private`/`friends`, default `private`). Ved `friends`
|
||||
velger man EKSPLISITT hvilke av gruppene sine som får se runden (ikke
|
||||
"alle venner"). Styrer kun tredjeparts innsyn — en faktisk lagt-til
|
||||
medspiller ser alltid runden uansett innstilling.
|
||||
3. Tiered personsøk — samme søkbare-liste-mønster som bane-/klubbsøket
|
||||
(`HomeClubField`/`OfficialSearchStep`), navnerekkefølge-uavhengig
|
||||
(skriv for- ELLER etternavn først, begge treffer), rangert: venner →
|
||||
samme hjemmeklubb → samme land → globalt. Ett delt endepunkt brukt
|
||||
BÅDE til "finn en venn" og (i en senere fase) "legg til medspiller på
|
||||
en runde".
|
||||
|
||||
**Reell synergi funnet under design, ikke tilfeldig:** forrige rundes
|
||||
redesign av "Hjemmeklubb" til en ekte dropdown-verdi (i stedet for
|
||||
fritekst) gjør nå "samme klubb"-rangeringen i søket pålitelig — et
|
||||
eksakt strengmatch fungerer nå, noe det ikke ville gjort med den gamle
|
||||
fritekst-versjonen.
|
||||
|
||||
**Foreslått byggerekkefølge (IKKE bekreftet), tre uavhengig leverbare
|
||||
faser:**
|
||||
1. Venner-kjernen (vennskap, kategorisering, `/people/search`, ny
|
||||
`/friends`-side) — leverbar og nyttig helt alene.
|
||||
2. Rundevisibilitet (visibility-valg ved rundestart, gatede
|
||||
lese-endepunkter, sanntids-livevisning for venner/offentlighet).
|
||||
3. Ekte medspillere (ikke bare gjester) — utvider
|
||||
`POST /rounds/{id}/participants` til å godta et søkt `user_id`.
|
||||
**Avklart med bruker 2026-07-25: JA, runden skal vises i spillerens
|
||||
egen rundeliste.** Teknisk konsekvens (se ADR-036 for full detalj):
|
||||
`list_rounds` må utvides fra kun `owner_user_id` til også lenkede
|
||||
`round_participant.user_id`-rader, og `RoundOut` sine
|
||||
`owner_*`-statistikkfelt må bli "viewer-relative" (vise DEN som ser
|
||||
på sin egen score, ikke alltid eierens). **Skrivetilgang også
|
||||
avklart 2026-07-25: en medspiller skal kunne registrere score for
|
||||
ALLE i flighten**, ikke bare egen rad — samme rettighet som eieren
|
||||
har i dag, utvidet til enhver lenket ekte deltaker. Sletting av
|
||||
runden og bane-/utslagsbytte forblir eier-eksklusivt (se ADR-036 for
|
||||
presis autorisasjonssjekk).
|
||||
|
||||
**Andre åpne spørsmål (se ADR-036 for full drøfting):**
|
||||
- Skal en bruker kunne gjøre seg "usøkbar"? Foreslått default: alle med
|
||||
fullført profil er søkbare, ingen opt-out i første omgang.
|
||||
- Minimum antall tegn før søket returnerer globale (ikke-venn/klubb/land)
|
||||
treff — foreslått 2, for å hindre triviell enumerering av alle
|
||||
brukere.
|
||||
- Skal en "offentlig" runde være synlig for ANONYME besøkende (som
|
||||
turneringers offentlige side), eller kreve innlogging? Foreslått:
|
||||
samme mønster som turnering — anonymt tilgjengelig.
|
||||
|
||||
**Ingen kode skrevet ennå** — dette var en design-/dokumentasjonsrunde,
|
||||
ikke en byggerunde, på brukerens eksplisitte instruks.
|
||||
|
||||
---
|
||||
|
||||
## Turneringsoppsett: flytte/slette spillere mellom lag — 📋 NOTERT 2026-07-25, IKKE bygget
|
||||
|
||||
Reist av brukeren samme runde som dashbord-integreringen. I dag finnes
|
||||
`DELETE .../roster/{roster_id}` (fjerner en spiller fra ETT lag) og
|
||||
`PATCH .../roster/{roster_id}` (kun `is_captain`, ADR-023) — men INGEN vei
|
||||
til å FLYTTE en allerede rostret spiller til et ANNET lag i samme
|
||||
turnering i én operasjon. I dag må organisatoren gjøre det som to separate
|
||||
kall (fjern fra lag A, legg til på lag B), og det finnes ingen slik
|
||||
UI-handling i `tournament-detail.tsx` sin `TeamPanel` i det hele tatt —
|
||||
kun fjerning.
|
||||
|
||||
**Ikke designet i detalj ennå** — rent notert som et reelt hull. Naturlig
|
||||
retning ved bygging: enten et eget `POST .../roster/{roster_id}/move`
|
||||
(target-team-id) som gjør begge operasjonene atomisk (unngår en
|
||||
mellomtilstand der spilleren midlertidig ikke er rostret noe sted), eller
|
||||
en UI-snarvei som bare kjører de to eksisterende kallene i sekvens — det
|
||||
første er tryggere (ingen delvis fullført tilstand ved feil midtveis).
|
||||
|
||||
---
|
||||
|
||||
## Frittstående runder: flere flighter i én "vanlig" runde — 📋 NOTERT 2026-07-25, IKKE bygget
|
||||
|
||||
Reist av brukeren samme runde: eksempel gitt — "jeg går i den første
|
||||
flighten sammen med tre andre, mens fire venner går i flighten bak."
|
||||
Dagens datamodell (`round`, ADR-033 Beslutning A) er implisitt ÉN flight
|
||||
= ÉN runde: `round.owner_user_id` er entydig, og alle
|
||||
`round_participant`-rader (eier + gjester/medspillere) spiller sammen i
|
||||
SAMME flight på SAMME hull-for-hull-registrering.
|
||||
|
||||
**Reell modelleringsspenning, ikke bare en UI-mangel:** å støtte flere
|
||||
flighter "i samme runde" krever et valg mellom to prinsipielt ulike
|
||||
retninger:
|
||||
1. **Løs gruppering av flere separate `round`-rader** — hver flight er
|
||||
fortsatt sin egen `round` (egen eier, egne deltakere, egen
|
||||
hull-registrering, uendret datamodell), men et nytt, tynt
|
||||
"delt arrangement"-konsept binder flere runder sammen visuelt (samme
|
||||
dag, samme bane, "spilt sammen med disse flightene") — minst
|
||||
invasivt, gjenbruker alt som allerede er bygget og scratch-verifisert.
|
||||
2. **`round` blir en beholder for flere flighter** — ligner
|
||||
turneringers `session`→`match`-struktur (én økt, flere matcher).
|
||||
Større omskriving: `round_participant` må da vite hvilken flight den
|
||||
hører til, og eierskap/autorisasjon (i dag: "eieren av runden ser/
|
||||
redigerer alt") må revurderes for en modell med flere selvstendige
|
||||
flighter under samme paraply.
|
||||
|
||||
**Ikke besluttet hvilken retning** — kun notert som et reelt, ikke-trivielt
|
||||
spørsmål. Henger dessuten sammen med det pågående ADR-036-arbeidet
|
||||
(medspillere/venner) — en avklaring bør trolig vente til minst fase 1 av
|
||||
ADR-036 er bygget, siden "hvem er i min flight" og "hvem er min venn/
|
||||
medspiller" er beslektede, men ikke identiske spørsmål.
|
||||
|
||||
---
|
||||
|
||||
## Frittstående rundeføring + detaljert statistikk (uten turnering/organisasjon) — ✅ BACKEND + FRONTEND LIVE, løpende oppfølging t.o.m. 2026-07-25 (se ADR-033 for full detalj per dag)
|
||||
|
||||
**Fremdrift 2026-07-22:** HCP-indeks-motor (43/43 tester), databaseskjema
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -33,12 +33,17 @@ function formatDateRange(start?: string, end?: string) {
|
|||
export function TournamentCard({
|
||||
tournament,
|
||||
orgId,
|
||||
organizer = false,
|
||||
}: {
|
||||
tournament: Tournament
|
||||
// Satt (dashbordet, innlogget) -> lenker til den innloggede detaljsiden.
|
||||
// Utelatt (klubb-landingsside, offentlig) -> lenker til den offentlige
|
||||
// /t/{id}-ruten i stedet. Samme kort, to kontekster.
|
||||
orgId?: string
|
||||
// Vis en "Arrangør"-merkelapp (dashbordets slåtte-sammen "Kommende
|
||||
// turneringer"-liste, 2026-07-25 -- deltaker- og arrangør-turneringer i
|
||||
// ÉN liste, merkelappen skiller dem visuelt).
|
||||
organizer?: boolean
|
||||
}) {
|
||||
const dateRange = formatDateRange(tournament.startDate, tournament.endDate)
|
||||
const href = orgId
|
||||
|
|
@ -56,6 +61,12 @@ export function TournamentCard({
|
|||
{tournament.name}
|
||||
</h3>
|
||||
<TournamentStatusBadge status={tournament.status} />
|
||||
{organizer && (
|
||||
<span className="inline-flex items-center gap-1.5 rounded-full bg-brand-orange/15 px-2.5 py-1 text-xs font-semibold text-foreground">
|
||||
<span aria-hidden="true" className="size-1.5 rounded-full bg-brand-orange" />
|
||||
Arrangør
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
{dateRange ? (
|
||||
<div className="flex items-center gap-1.5 text-sm text-muted-foreground">
|
||||
|
|
|
|||
BIN
tee-cup-login-screen (18).zip
Normal file
BIN
tee-cup-login-screen (18).zip
Normal file
Binary file not shown.
Loading…
Reference in a new issue