Dokumenter dashbord/BottomNav/veiviser/login/deling/slagmåling i CHANGELOG.md
Punkt 39-45: dashbord+BottomNav-reskin, ny-runde-veiviser + offisiell- banesøk-produksjonsbug, /logg-inn som ekte innloggingsside, rundedeling- kategoriregel-fiks (ADR-036 E), og slag-for-slag-avstandsmåling inngangspunkt 1. Se de fem foregående commitene for koden.
This commit is contained in:
parent
9538dfec7f
commit
2d1d0ba1d0
1 changed files with 425 additions and 7 deletions
432
CHANGELOG.md
432
CHANGELOG.md
|
|
@ -8683,9 +8683,10 @@ Neste steg:
|
||||||
eksplisitt bekreftet at ekte `teecup_db` sin `datacl` var uendret
|
eksplisitt bekreftet at ekte `teecup_db` sin `datacl` var uendret
|
||||||
etterpå).
|
etterpå).
|
||||||
|
|
||||||
**Ikke rullet ut ennå** -- venter på samlet bekreftelse sammen med
|
**Rullet ut 2026-08-08** sammen med punkt 40 og 41 (`docker compose
|
||||||
resten av det som gjenstår i denne økten (slagmåling-frontend,
|
build teecup_frontend` + `up -d` -- ingen migrasjon, kun ny
|
||||||
dashbord-V0-beslutning).
|
frontend-image). Bekreftet ingen konsollfeil på
|
||||||
|
`https://teecup.golf/` etter omstart.
|
||||||
|
|
||||||
39. **Dashbordet reskinnet til "clubhouse"-paletten — 2026-08-07, bruker
|
39. **Dashbordet reskinnet til "clubhouse"-paletten — 2026-08-07, bruker
|
||||||
bekreftet eksplisitt "full overtagelse, også bakgrunnen".** Egen,
|
bekreftet eksplisitt "full overtagelse, også bakgrunnen".** Egen,
|
||||||
|
|
@ -8745,7 +8746,424 @@ Neste steg:
|
||||||
utvidet korrekt og det eksisterende skjemaet (uendret) fungerte som før.
|
utvidet korrekt og det eksisterende skjemaet (uendret) fungerte som før.
|
||||||
Ingen konsollfeil. Scratch-miljøet ryddet opp fullstendig.
|
Ingen konsollfeil. Scratch-miljøet ryddet opp fullstendig.
|
||||||
|
|
||||||
**Ikke rullet ut ennå** -- venter på BottomTabBar-V0-eksporten (så
|
**Rullet ut 2026-08-08** sammen med BottomNav (punkt 40) og
|
||||||
hele dashbordet, inkludert navigasjonen, kan rulles ut samlet i én
|
ny-runde-veiviseren (punkt 41), som planlagt -- se punkt 41 for
|
||||||
omgang i stedet for i to synlig usammenhengende steg) og på samlet
|
utrullingsdetaljer.
|
||||||
bekreftelse sammen med resten av det som gjenstår denne økten.
|
|
||||||
|
40. **BottomTabBar erstattet med `BottomNav` fra egen V0-prompt —
|
||||||
|
2026-08-08.** Bruker ba eksplisitt om at bunn-navigasjonens utseende
|
||||||
|
skulle avgjøres av V0 selv, ikke av meg (se punkt 39) -- prompt skrevet
|
||||||
|
med eksplisitt kontekst om at komponenten deles mellom clubhouse- og
|
||||||
|
Forest Green-sider og må fungere rimelig godt mot begge, uten å få
|
||||||
|
oppgitt en fasit-retning. V0 valgte en bevisst palett-nøytral løsning:
|
||||||
|
en "flytende hvit flate" (halvtransparent hvit, backdrop-blur, egen
|
||||||
|
skygge) som ikke arver noen sideb palett -- kun den grønne
|
||||||
|
`tee`/`tee-strong`-aksenten (felles for begge paletter) brukes for
|
||||||
|
aktiv-tilstand.
|
||||||
|
|
||||||
|
Ny fil `components/teecup/bottom-nav.tsx`, eksporterer `BottomNav`
|
||||||
|
(ikke lenger `BottomTabBar`). Strukturell endring fra forgjengeren:
|
||||||
|
aktiv fane leses nå fra `usePathname()` internt (ikke en `active`-prop
|
||||||
|
utenfra) -- hrefs rettet fra V0s plassholdere (`/hjem`, `/runder` osv.)
|
||||||
|
til de faktiske rutene under integrering. Fjernet den gamle
|
||||||
|
`BottomTabBar`-definisjonen (og dens nå-ubrukte `C`-fargekonstant og
|
||||||
|
fire lucide-ikon-importer) fra `dashboard.tsx`; alle seks sider
|
||||||
|
(`dashboard.tsx`, `own-rounds.tsx`, `friends.tsx`, `account-
|
||||||
|
settings.tsx`, `feed.tsx`, `notifications.tsx`, `more-menu.tsx`)
|
||||||
|
importerer nå `BottomNav` fra den nye filen i stedet, uten `active`-
|
||||||
|
prop.
|
||||||
|
|
||||||
|
**To reelle bugs funnet og rettet UNDER scratch-verifisering (ikke i
|
||||||
|
selve V0-eksporten -- begge i MIN EGEN integreringskode):**
|
||||||
|
1. Forsøkte først å "forbedre" aktiv-fane-sammenligningen ved å
|
||||||
|
strippe bort et evt. `#hash` før sammenligning (siden "Turneringer"
|
||||||
|
sin href er `/dashboard#kommende-turneringer`). Dette var FEIL --
|
||||||
|
browser-verifisert til å få BÅDE "Hjem" og "Turneringer" til å vise
|
||||||
|
som aktive samtidig på `/dashboard`, siden begge da strippet til
|
||||||
|
samme sti. Reversert til V0s opprinnelige, rå strengsammenligning
|
||||||
|
(som aldri hadde dette problemet -- "Turneringer" matcher rett og
|
||||||
|
slett aldri via ren pathname, akkurat som forgjengeren uansett aldri
|
||||||
|
fremhevet den).
|
||||||
|
2. `/my-friends`, `/my-feed` og `/my-notifications` viste INGEN fane
|
||||||
|
som aktiv i det hele tatt (ren pathname-matching kjenner dem ikke
|
||||||
|
igjen som noen fanes mål) -- forgjengeren løste dette implisitt ved
|
||||||
|
at hver side selv sendte inn riktig `active`-prop. Lagt til en ny,
|
||||||
|
liten `matchPaths`-mekanisme på `Tab`-typen; "Mer" sin oppføring
|
||||||
|
fikk `matchPaths: ["/my-friends", "/my-feed", "/my-notifications"]`
|
||||||
|
-- speiler nøyaktig hvilke tre sider `more-menu.tsx` selv allerede
|
||||||
|
lister som sine undersider, ingen ny gruppering oppfunnet.
|
||||||
|
|
||||||
|
`tsc --noEmit` rent. **Scratch-verifisert i ekte nettleser** (tiende
|
||||||
|
scratch-miljø denne økten, samme migrasjon-002-forsiktighet som
|
||||||
|
punkt 37-39, `teecup_db` bekreftet uendret): logget inn, besøkt alle
|
||||||
|
syv sider som bruker `BottomNav` (dashbord, my-rounds, my-friends,
|
||||||
|
account, my-feed, my-notifications, more) -- riktig (og ETT AV GANGEN,
|
||||||
|
etter fiks 1) fane fremhevet på hver, ingen konsollfeil. Scratch-miljøet
|
||||||
|
ryddet opp fullstendig.
|
||||||
|
|
||||||
|
**Rullet ut 2026-08-08** sammen med punkt 39 og 41 -- se punkt 41 for
|
||||||
|
utrullingsdetaljer.
|
||||||
|
|
||||||
|
41. **`/my-rounds/new` erstattet med ny-runde-veiviser fra egen V0-prompt
|
||||||
|
— 2026-08-08.** Samme mønster som punkt 40: prompt skrevet med full
|
||||||
|
teknisk spesifikasjon (alle 18 spilleformer, alle steg/felt/
|
||||||
|
valideringsregler, alle 12 backend-endepunkt, `submitWizard()`-
|
||||||
|
kontrakten) og eksplisitt UTEN visuell føring -- V0 fikk velge
|
||||||
|
utseendet fritt. Resultat: en ny, selvstendig palett (`--nr-*` i
|
||||||
|
`globals.css`, kald blå/grå, `--nr-accent: #1f5fd6`), additiv og
|
||||||
|
scoped til veiviseren alene, samme "co-eksisterende paletter via
|
||||||
|
Tailwind arbitrary-value-syntaks"-mønster som clubhouse-paletten
|
||||||
|
(punkt 39) -- ingen `@theme inline`-kobling, ingen påvirkning på
|
||||||
|
resten av appen.
|
||||||
|
|
||||||
|
Gammel `components/new-round.tsx` (3364 linjer) SLETTET -- bekreftet
|
||||||
|
via grep at kun `app/my-rounds/new/page.tsx` importerte den (de tre
|
||||||
|
andre grep-treffene, i `course-template-editor.tsx`/
|
||||||
|
`round-leaderboard.tsx`/`round-detail.tsx`, var bare beskrivende
|
||||||
|
norske kommentarer, urørt). Ny modul under
|
||||||
|
`components/ny-runde/` (`wizard-shell.tsx`, `wizard-context.tsx`,
|
||||||
|
fem steg-filer, `primitives.tsx`, `progress.tsx`, `footer-bar.tsx`,
|
||||||
|
`create-course-form.tsx`) + `lib/ny-runde/` (`types.ts`,
|
||||||
|
`formats.ts`, `api.ts`).
|
||||||
|
|
||||||
|
V0s eksport brukte mock-data gjennomgående -- hele portingsjobben
|
||||||
|
var å koble hvert steg til de faktiske backend-kontraktene fra
|
||||||
|
`app/routers/rounds.py` og den gamle `new-round.tsx`, IKKE bare et
|
||||||
|
overflatisk bytte av komponentnavn: `Gender`-oversettelse
|
||||||
|
(`"m"|"f"` API ↔ `"mann"|"kvinne"|"annet"` UI), `Tee`-formen
|
||||||
|
forenklet til kun `{id, name, genders}` (aldri CR/Slope til klienten),
|
||||||
|
`CourseMeta`-discriminated-union for teeoff- vs. egen-bane, ekte
|
||||||
|
`POST /rounds` → `POST .../sides` → `POST .../participants` →
|
||||||
|
`PATCH .../participants/{id}`-sekvens i `submit()`, ekte
|
||||||
|
kontosøk/gjeste-oppslag i steg 3, ekte banesøk (teeoff-fasilitet +
|
||||||
|
egne baner, inkl. geolokasjon for "i nærheten") i steg 1.
|
||||||
|
|
||||||
|
**Fire reelle bugs funnet og rettet under scratch-verifisering:**
|
||||||
|
1. `TextInput` i `primitives.tsx` manglet `forwardRef` (feil i selve
|
||||||
|
V0-eksporten, ikke i portingen) -- ga 3 TS-feil der nedstrøms kode
|
||||||
|
sendte `ref` til komponenten. Rettet ved å pakke inn med
|
||||||
|
`forwardRef`, `tsc --noEmit` gikk fra 3 feil til rent.
|
||||||
|
2. Steg 3 viste "Utslag: Ikke valgt" for eieren selv etter at tee var
|
||||||
|
valgt i steg 1 -- min egen portingsfeil, jeg hadde ikke tatt med
|
||||||
|
den ekte `chooseCourse()`s side-effekt som synker valgt tee inn i
|
||||||
|
spillerlisten. Rettet ved å legge `players:
|
||||||
|
state.players.map(...)` til i `pickCourse()`
|
||||||
|
(`step1-course-time.tsx`). Verifisert rettet ved reload.
|
||||||
|
3. Manglende "Ingen"/"Alle"-hurtigknapp og "ingen kategori
|
||||||
|
valgt"-advarsel i steg 5s kategorivelger (samme mangel som ble
|
||||||
|
oppdaget og rettet i selve appen 2026-08-06, se punkt 36 -- V0s
|
||||||
|
eksport hadde ikke fått denne konteksten). Lagt til i
|
||||||
|
`step5-sharing.tsx`, samme mønster som punkt 36 (`role="group"`,
|
||||||
|
`aria-pressed`, `role="alert"` ved null valgt). Browser-verifisert
|
||||||
|
i scratch: "Ingen" tømmer alle 10 avkrysninger og viser advarselen,
|
||||||
|
"Alle" gjenoppretter alle.
|
||||||
|
4. Fulgte først en blindvei: trodde "Legg til gjest"-knappen i steg 3
|
||||||
|
var usynlig/klikk-slukende bak den klissede (`sticky bottom-0`)
|
||||||
|
`FooterBar`-en (samme feilklasse som `pb-32`-saken 2026-08-02,
|
||||||
|
nevnt i den gamle `new-round.tsx`s egne kommentarer) -- la til
|
||||||
|
`pb-28` på `<main>`. Padding-fiksen var faktisk RIKTIG og
|
||||||
|
nødvendig (uten den er det for lite scroll-klaring til å noensinne
|
||||||
|
få knappen helt fri av footeren), men den første reproduksjonen av
|
||||||
|
"feilen" var selv et testverktøy-artefakt: et koordinat-basert
|
||||||
|
klikk uten forutgående scroll traff footeren fordi den, ved
|
||||||
|
`scrollY: 0`, visuelt ligger over knappen (klissete element som
|
||||||
|
ikke har "festet seg" ennå fordi normal dokumentflyt allerede
|
||||||
|
plasserer det nederst i viewport). Bekreftet ved å måle
|
||||||
|
`getBoundingClientRect()` for begge før/etter scroll: uten scroll
|
||||||
|
overlapper de nesten fullstendig (y:776 vs. top:775); etter
|
||||||
|
`scrollIntoView` (174px, alt tilgjengelig scroll) står knappen på
|
||||||
|
y:602, godt klar. Et ekte, koordinat-basert klikk etter scroll
|
||||||
|
fungerte perfekt. Konklusjon: `pb-28`-fiksen var korrekt og er
|
||||||
|
beholdt (den gir nødvendig klaring når brukeren scroller helt ned),
|
||||||
|
ingen ytterligere kodefeil forelå.
|
||||||
|
|
||||||
|
`tsc --noEmit` rent. **Scratch-verifisert i ekte nettleser** (ellevte
|
||||||
|
scratch-miljø denne økten, samme migrasjon-002-forsiktighet som
|
||||||
|
punkt 37-40, `teecup_db`s ACL bekreftet uendret før og etter): full
|
||||||
|
veiviser-gjennomkjøring for Fourball -- egen bane opprettet og valgt,
|
||||||
|
tee/HCP riktig synket til eier, gjest uten konto lagt til, begge
|
||||||
|
spillere tildelt hver sin side i steg 4, "Ingen"/"Alle"-toggle testet
|
||||||
|
i steg 5, fullført innsending. **DB-verifisert direkte**: `round`-rad
|
||||||
|
med riktig `play_format`/`visibility_mode`/bane-/tee-snapshot,
|
||||||
|
to `round_side`-rader, begge `round_participant`-rader korrekt
|
||||||
|
knyttet til hver sin `round_side_id` med riktig
|
||||||
|
HCP-/tee-/stat_level-snapshot. Ingen konsollfeil. Scratch-miljøet
|
||||||
|
(containere, images, DB, rolle) ryddet opp fullstendig etterpå.
|
||||||
|
|
||||||
|
**Rullet ut 2026-08-08** sammen med punkt 39 og 40, etter eksplisitt
|
||||||
|
brukerbekreftelse ("Rull ut alle tre samlet"): `docker compose build
|
||||||
|
teecup_frontend && docker compose up -d teecup_frontend` (kun
|
||||||
|
frontend-image, ingen migrasjon). Bekreftet `teecup_api`s image
|
||||||
|
UENDRET (bygget 2026-08-07, ikke i dag) -- containeren ble kun
|
||||||
|
re-opprettet fra samme eksisterende image pga. avhengighetskjeden i
|
||||||
|
`docker-compose.yml`, ikke bygget på nytt, så de uncommittede
|
||||||
|
backend-endringene som lå i arbeidstreet (`rounds.py`,
|
||||||
|
`handicap_engine.py` m.fl., urelatert til denne økten) ble IKKE
|
||||||
|
utilsiktet rullet ut. `https://teecup.golf/` bekreftet oppe, ingen
|
||||||
|
konsollfeil på innloggingssiden. Autentisert gjennomgang av
|
||||||
|
dashbord/BottomNav/ny-runde-veiviseren i produksjon overlatt til
|
||||||
|
brukeren selv (krever ekte pålogging).
|
||||||
|
|
||||||
|
42. **`/logg-inn` gjort til den EKTE innloggingssiden (erstatter `/` sin
|
||||||
|
gamle `LoginForm`) — 2026-08-08.** Brukeren la merke til at
|
||||||
|
innloggingssiden fortsatt viste "det gamle grensesnittet" etter
|
||||||
|
punkt 39-41s utrulling -- undersøkelse avdekket at `/logg-inn`
|
||||||
|
(clubhouse-palett, `TeeCupAuth`) var en fullstendig FORELDRELØS V0-
|
||||||
|
utforskning: INGENTING i appen lenket eller redirectet dit (bekreftet
|
||||||
|
ved grep), alle ~11 uautentisert-steder pekte fortsatt til `/` (gammel
|
||||||
|
`LoginForm`, Forest Green). Se dashboard.tsx sin egen kommentar
|
||||||
|
(linje 26-34) som allerede erkjente dette -- "fra en tidligere, ennå
|
||||||
|
ikke integrert /logg-inn-utforskning".
|
||||||
|
|
||||||
|
**Kritisk oppdagelse FØR arbeidet startet:** `TeeCupAuth` var 100 %
|
||||||
|
mock -- `apiSendMagicLink`/`apiPasswordLogin`/`apiJoinByCode` var alle
|
||||||
|
`sleep()`-baserte stubber (hardkodet demo-passord `"teecup123"`,
|
||||||
|
hardkodede demo-koder `TEECUP`/`RYDER-25`/`HOST2026`, en falsk
|
||||||
|
"2FA-kode sendes"-tekst som ALDRI faktisk sendte noe). Dette ble
|
||||||
|
eksplisitt flagget til brukeren (AskUserQuestion) FØR noe ble bygget,
|
||||||
|
siden dette er sikkerhetskritisk kode og omfanget var langt større enn
|
||||||
|
en ren redirect-ombytting -- brukeren bekreftet "gjør full port nå".
|
||||||
|
|
||||||
|
**Full port utført:**
|
||||||
|
- `components/teecup/teecup-auth.tsx` skrevet om fra bunnen: ekte
|
||||||
|
`POST /auth/request-link` (magic link), ekte
|
||||||
|
`POST /auth/login-password` (med `LoginResult`-status-håndtering
|
||||||
|
identisk med den gamle `LoginForm`), ekte
|
||||||
|
`GET /public/tournaments/by-code/{code}`. Alle demo-hint/mock-tekster
|
||||||
|
fjernet. `TwoFactorVerifyForm`/`TwoFactorSetupForm`
|
||||||
|
(`components/two-factor-flow.tsx`) gjenbrukt UENDRET -- samme
|
||||||
|
"delt komponent ikke re-stylet"-mønster som `RoundCard`/
|
||||||
|
`TournamentCard` i dashbord-reskinnet (punkt 39) -- lavest mulig
|
||||||
|
risiko for sikkerhetskritisk 2FA-kode.
|
||||||
|
- `app/logg-inn/page.tsx`: fikk samme server-side allerede-innlogget-
|
||||||
|
sjekk (`cookies()` + `/auth/me`) som `/`-siden hadde.
|
||||||
|
- `app/page.tsx` (root): redusert til en tynn videresending
|
||||||
|
(autentisert → `/dashboard`/`/account`, uautentisert → `/logg-inn`)
|
||||||
|
-- beholdt for gamle bokmerker/lenker til `teecup.golf/`. Gamle
|
||||||
|
`LoginForm`/`components/login-form.tsx` SLETTET (bekreftet ingen
|
||||||
|
andre importer via grep).
|
||||||
|
- Alle 11 `router.replace("/")`-steder (401-håndtering + logout) i
|
||||||
|
`dashboard.tsx`, `friends.tsx`, `more-menu.tsx`,
|
||||||
|
`account-settings.tsx`, `notifications.tsx`, `course-rounds.tsx`,
|
||||||
|
`own-rounds.tsx`, `rounds-stats-summary.tsx` byttet til
|
||||||
|
`router.replace("/logg-inn")`. `verify-form.tsx` sin
|
||||||
|
"Be om en ny lenke"-fallback-lenke (`href="/"`) byttet til
|
||||||
|
`/logg-inn`.
|
||||||
|
|
||||||
|
**Én reell bug funnet og rettet under scratch-verifisering:**
|
||||||
|
`app/logg-inn/page.tsx` kalte `redirect()` INNI `try`-blokken som
|
||||||
|
henter `/auth/me` -- Next.js sin `redirect()` fungerer ved å kaste en
|
||||||
|
egen `NEXT_REDIRECT`-kontrollflyt-exception som MÅ boble videre
|
||||||
|
urørt til Next.js sin render-maskineri. Den tomme `catch {}`-en rundt
|
||||||
|
slukte denne stille, så en allerede innlogget bruker som besøkte
|
||||||
|
`/logg-inn` fikk se innloggingsskjemaet på nytt i stedet for å bli
|
||||||
|
sendt videre -- oppdaget fordi en ekte innlogget test-bruker IKKE ble
|
||||||
|
omdirigert i scratch, mens en direkte nettleser-`fetch("/auth/me")`
|
||||||
|
(som går via `next.config.mjs` sin rewrite, ikke gjennom denne
|
||||||
|
server-komponentens egen kode) bekreftet sesjonen var helt gyldig --
|
||||||
|
avslørte at feilen satt i AKKURAT denne serverkomponentens egen
|
||||||
|
try/catch-struktur. Den opprinnelige `/`-sidens ekvivalente kode
|
||||||
|
unngikk dette ved å KUN sette `authenticated`/`profileComplete`-
|
||||||
|
variabler inni try/catch og kalle `redirect()` etterpå, UTENFOR
|
||||||
|
blokken -- samme mønster gjeninnført her. `tsc --noEmit` rent etter
|
||||||
|
fiks.
|
||||||
|
|
||||||
|
**Scratch-verifisert i ekte nettleser** (tolvte scratch-miljø denne
|
||||||
|
økten, samme migrasjon-002-forsiktighet som punkt 37-41 --
|
||||||
|
`teecup_db`s ACL bekreftet uendret før og etter; `TEECUP_DEV_LOG_MAGIC_LINKS=true`
|
||||||
|
brukt for å hente ekte magic-link-tokens fra API-loggen i stedet for å
|
||||||
|
sende ekte e-post til testadresser): full runde -- magic-link-
|
||||||
|
forespørsel + `/verify?token=`-innlogging (ny bruker auto-opprettet,
|
||||||
|
korrekt sendt til `/account` pga. ufullstendig profil), passord-
|
||||||
|
innlogging med feil passord (ekte feilmelding "E-post eller passord
|
||||||
|
er feil." fra `/auth/login-password`), invitasjonskode med ugyldig
|
||||||
|
kode (ekte feilmelding fra `/public/tournaments/by-code/`), logout
|
||||||
|
(→ `/logg-inn`), uautentisert besøk til `/dashboard` (→ `/logg-inn`,
|
||||||
|
ikke lenger `/`), `/` og `/logg-inn` besøkt allerede innlogget med
|
||||||
|
ufullstendig profil (→ `/account`) og med fullført profil
|
||||||
|
(→ `/dashboard`, satt via direkte `PATCH /auth/profile`-kall for å
|
||||||
|
unngå å klikke gjennom fødselsdato-datepickeren manuelt). Ingen
|
||||||
|
konsollfeil. **Ikke click-through-testet:** `2fa_required`-grenen
|
||||||
|
(krever en konto med 2FA allerede aktivert) -- vurdert lav risiko
|
||||||
|
siden `TwoFactorVerifyForm`/`TwoFactorSetupForm` er gjenbrukt helt
|
||||||
|
uendret fra den allerede beviste `LoginForm`-implementasjonen, kun
|
||||||
|
kablingen frem til dem (`handleLoginResult`) er ny kode, og den er
|
||||||
|
identisk portert fra `LoginForm`. Scratch-miljøet (containere, images,
|
||||||
|
DB, rolle) ryddet opp fullstendig etterpå, inkl. en disk-full-hendelse
|
||||||
|
underveis (`docker builder prune` frigjorde 11,75 GB build-cache fra
|
||||||
|
denne øktens mange scratch-bygg -- ingen kjørende containere eller
|
||||||
|
volumer berørt).
|
||||||
|
|
||||||
|
**Rullet ut 2026-08-08**, etter egen, eksplisitt brukerbekreftelse
|
||||||
|
separat fra punkt 39-41s batch-bekreftelse (sikkerhetskritisk --
|
||||||
|
autentisering). `docker compose build teecup_frontend && up -d` --
|
||||||
|
denne gangen ble kun `teecup_frontend` gjenskapt (`teecup_api` forble
|
||||||
|
"Running" med bekreftet uendret image-tidsstempel før/etter, ulikt
|
||||||
|
forrige utrulling i punkt 39-41 der en avhengighets-kjede-bivirkning
|
||||||
|
gjenskapte -- men ikke bygde om -- `teecup_api`). `https://teecup.golf/`
|
||||||
|
bekreftet å redirecte til `/logg-inn` med clubhouse-designet, ingen
|
||||||
|
konsollfeil.
|
||||||
|
|
||||||
|
43. **PRODUKSJONSBUG: "Laster baner…" hang for alltid ved offisiell
|
||||||
|
banevalg i ny-runde-veiviseren — funnet og fikset 2026-08-08.**
|
||||||
|
Brukeren rapporterte (skjermbilde) at steget etter å ha valgt et
|
||||||
|
teeoff-anlegg ("Baner") aldri kom videre fra "Laster baner…". Dette
|
||||||
|
hadde vært live siden punkt 41s utrulling -- treffer ALLE nye runder
|
||||||
|
som starter fra en offisiell (teeoff-) bane, ikke egne baner.
|
||||||
|
|
||||||
|
**Rotårsak:** `fetchFacilityCourses()` i `lib/ny-runde/api.ts` antok
|
||||||
|
at `GET /rounds/official-search/{slug}` returnerer banene direkte som
|
||||||
|
en array (`data.map(...)`), men det ekte endepunktet returnerer et
|
||||||
|
OBJEKT -- `OfficialFacilityDetail = {slug, name, courses: [...]}`
|
||||||
|
(`app/routers/rounds.py` linje 530). `data.map` er ikke en funksjon
|
||||||
|
på et objekt, så kallet kastet en `TypeError` -- og siden
|
||||||
|
`OfficialCourses` sin `useEffect` i `step1-course-time.tsx` kun hadde
|
||||||
|
`.then(...)` uten `.catch(...)`, ble denne exceptionen en stille,
|
||||||
|
ufanget promise-rejection: `setCourses` ble aldri kalt, og
|
||||||
|
`courses === null`-grenen ("Laster baner…") viste seg for alltid.
|
||||||
|
Bug i min egen porting (punkt 41) -- **denne konkrete stien
|
||||||
|
(offisiell teeoff-bane) ble aldri scratch-testet den runden**, kun
|
||||||
|
"egen bane"-veien ble klikket gjennom (se punkt 41s test-notat).
|
||||||
|
|
||||||
|
**To rettelser:**
|
||||||
|
1. `fetchFacilityCourses()`: leser nå `data.courses.map(...)` i
|
||||||
|
stedet for `data.map(...)`.
|
||||||
|
2. `OfficialCourses` (`step1-course-time.tsx`): la til en reell
|
||||||
|
`.catch()` + en `loadError`-tilstand (`role="alert"`, samme
|
||||||
|
`--nr-danger`-stil som resten av veiviseren) -- uten denne ville
|
||||||
|
ENHVER fremtidig feil her (f.eks. teeoff nede, 502) gitt nøyaktig
|
||||||
|
samme uendelige "Laster baner…"-hang på nytt, uansett om
|
||||||
|
datakontrakt-bugen over er rettet. Dette er defensivt, ikke bare
|
||||||
|
en fiks for det spesifikke tilfellet.
|
||||||
|
|
||||||
|
`tsc --noEmit` rent. **Scratch-verifisert i ekte nettleser** (trettende
|
||||||
|
scratch-miljø denne økten, samme migrasjon-002-forsiktighet, `teecup_db`
|
||||||
|
bekreftet uendret) MOT EKTE teeoff-data (samme `teeoff_db`/`teeoff_api`
|
||||||
|
som produksjon deler, nådd direkte på `teeoff_default`-nettverket):
|
||||||
|
søkte opp "Hvaler Golfklubb" (reell fasilitet), banen ("Hovedbanen, 2
|
||||||
|
utslag") lastet korrekt i stedet for å henge, gikk videre til
|
||||||
|
felt-steget og bekreftet ekte utslag (Gul/Rød) hentet riktig fra
|
||||||
|
teeoff. Ingen konsollfeil (kun én forhåndseksisterende, ikke-relatert
|
||||||
|
"Deprecated feature"-info-melding fra nettleseren selv). Scratch-miljøet
|
||||||
|
ryddet opp fullstendig.
|
||||||
|
|
||||||
|
**Rullet ut umiddelbart** (produksjonsbug som traff alle live
|
||||||
|
brukere som prøvde å starte en runde på en offisiell bane) --
|
||||||
|
`docker compose build teecup_frontend && up -d`, kun frontend-image,
|
||||||
|
`teecup_api`s image-tidsstempel bekreftet uendret før/etter. Kunne
|
||||||
|
ikke click-through-verifisere selve produksjonssiden med ekte
|
||||||
|
brukerkonto (krever brukerens egen pålogging) -- basert på grundig
|
||||||
|
scratch-verifisering mot ekte teeoff-data rett før utrulling.
|
||||||
|
|
||||||
|
44. **PRODUKSJONSBUG: rundedeling med venner i flere kategorier virket
|
||||||
|
ikke som forventet — funnet og fikset 2026-08-08, se ADR-036
|
||||||
|
Beslutning E.** Brukeren rapporterte at en runde delt med kategorien
|
||||||
|
"Make" ikke ble synlig for vedkommendes ektefelle, til tross for at
|
||||||
|
"Make" var huket av. Diagnostisert direkte mot ekte `teecup_db`
|
||||||
|
(skrivebeskyttede spørringer): eieren (Erol) hadde kategorisert
|
||||||
|
ektefellen (Gina) under TRE kategorier (`close_family`,
|
||||||
|
`extended_family`, `spouse`), mens runden kun delte
|
||||||
|
(`close_family`, `golf_friends`, `spouse`) -- `extended_family`
|
||||||
|
manglet. `_can_view_round` krevde den gang at ALLE en venns
|
||||||
|
kategorier måtte være i rundens synlige sett (presisert av bruker
|
||||||
|
2026-07-29, kun dokumentert i kode-kommentarer, ALDRI i
|
||||||
|
ARCHITECTURE_DECISIONS.md -- selve dokumentasjonshullet som gjorde
|
||||||
|
dette vanskelig å spore tilbake), ikke bare én relevant kategori.
|
||||||
|
|
||||||
|
Brukeren fikk vist mekanismen konkret (hvilke kategorier Gina var
|
||||||
|
tagget i, hvilke runden delte, den strenge AND-regelen) og valgte via
|
||||||
|
et eksplisitt spørsmål å reversere til "minst én kategori er nok"
|
||||||
|
(som var den OPPRINNELIGE ADR-036 Beslutning B-regelen fra
|
||||||
|
2026-07-25 -- 2026-07-29-presiseringen hadde altså strammet inn en
|
||||||
|
regel utover det som noensinne ble ordentlig dokumentert som en
|
||||||
|
bevisst arkitekturbeslutning).
|
||||||
|
|
||||||
|
**Rettet i alle fire duplikate SQL-steder** (samme
|
||||||
|
kopier-inn-i-SQL-mønster som allerede omtalt i ADR-036 Beslutning B):
|
||||||
|
`app/routers/rounds.py` sin `_can_view_round` (selve
|
||||||
|
tilgangssjekken), `_friends_who_can_see_round` (varsel-fan-out ved
|
||||||
|
rundeopprettelse/fullføring), `list_friends_on_course`
|
||||||
|
(dashbordets "Venner på banen"); `app/routers/round_messages.py` sin
|
||||||
|
`/feed`-listing. Alle gikk fra "`NOT EXISTS` en kategori UTENFOR
|
||||||
|
synlig sett" til et enklere "`EXISTS` en kategori INNENFOR synlig
|
||||||
|
sett" -- enklere spørringer, ikke bare annen semantikk.
|
||||||
|
|
||||||
|
**Scratch-verifisert i ekte API-kall** (fjortende scratch-miljø denne
|
||||||
|
økten, samme migrasjon-002-forsiktighet, `teecup_db` bekreftet
|
||||||
|
uendret): gjenskapte den ekte Erol/Gina-situasjonen (venn kategorisert
|
||||||
|
i to kategorier, runde deler kun én av dem) -- vennen fikk nå 200 på
|
||||||
|
`GET /public/rounds/{id}` (tidligere 403). Bekreftet at motsatt
|
||||||
|
tilfelle (venn med INGEN overlappende kategori) fortsatt korrekt gir
|
||||||
|
403 -- ingen utilsiktet åpning av tilgangskontrollen. `/friends/
|
||||||
|
on-course` og `/feed` (de to andre endrede spørringene) begge 200
|
||||||
|
uten SQL-feil. Scratch-miljøet ryddet opp fullstendig.
|
||||||
|
|
||||||
|
**Rullet ut umiddelbart** (produksjonsbug, brukerens egen delte runde
|
||||||
|
var konkret berørt) -- `docker compose build teecup_api && up -d`,
|
||||||
|
KUN backend-image (ingen migrasjon, `visibility_mode`/
|
||||||
|
`round_visible_category` er uendret skjema), `teecup_frontend`s
|
||||||
|
image-tidsstempel bekreftet uendret før/etter. **Bekreftet direkte
|
||||||
|
mot ekte data etter utrulling**: samme spørring som
|
||||||
|
`_can_view_round` nå bruker, kjørt skrivebeskyttet mot den ekte
|
||||||
|
Erol/Gina/runde-situasjonen, returnerer nå `true`.
|
||||||
|
|
||||||
|
45. **Slag-for-slag GPS-avstandsmåling — inngangspunkt 1 av 2, i
|
||||||
|
scoring-veiviseren — 2026-08-08 (ADR-048).** Backend (migrasjon
|
||||||
|
`060_round_shot.sql`, `ShotIn`/`ShotOut`/`ShotShareIn`-endepunktene i
|
||||||
|
`rounds.py`, `lib/geo.ts` Haversine, Mapbox-token-plumbing) var
|
||||||
|
allerede bygget og scratch-verifisert fra tidligere i økten (se
|
||||||
|
ADR-048 i ARCHITECTURE_DECISIONS.md). Denne runden: selve
|
||||||
|
frontend-flaten.
|
||||||
|
|
||||||
|
V0-prompt skrevet med `DESIGN_SYSTEM.md`s tokens som en HARD
|
||||||
|
begrensning (i motsetning til dashbord-/veiviser-/login-promptene
|
||||||
|
tidligere i økten, som bevisst fikk null designføring) -- dette
|
||||||
|
arket lever INNI den eksisterende Forest Green-skjermen
|
||||||
|
(`round-detail.tsx`), ikke som en ny frittstående side. Eksporten
|
||||||
|
(zip 4) var meget tro mot spesifikasjonen: `next/dynamic({ssr:false})`
|
||||||
|
for kartsteget, ingen `mapbox-gl`-import i det hele tatt på
|
||||||
|
GPS-only-stien, kartet mountes kun én gang per arkåpning
|
||||||
|
(tom-deps `useEffect`, klikk/drag re-initialiserer aldri).
|
||||||
|
|
||||||
|
`components/shot/shot-measurement-sheet.tsx` +
|
||||||
|
`components/shot/map-point-picker.tsx` kopiert inn uendret (kun
|
||||||
|
én import-sti rettet: V0s egen plassholder-`ClubPicker` byttet til
|
||||||
|
den nå faktisk utrukne, delte `components/teecup/club-picker.tsx`
|
||||||
|
-- ren utrekking fra `round-detail.tsx`s tidligere lokale kopi,
|
||||||
|
ingen atferdsendring for veiviserens eksisterende bruk). Ny
|
||||||
|
`components/ui/textarea.tsx`-shadcn-primitiv lagt til (fantes ikke
|
||||||
|
fra før).
|
||||||
|
|
||||||
|
Koblet inn som `ScoringWizard`s nye `roundId`-prop + lokal
|
||||||
|
`shotSheetOpen`/`shotCount`-state: "Mål et slag"-knapp rett etter
|
||||||
|
kølle-plukkeren i detalj-steget, henter eksisterende slag-antall on
|
||||||
|
mount (`GET .../holes/{n}/shots`), sender til ekte
|
||||||
|
`POST .../holes/{n}/shots` ved innsending og (hvis deling valgt)
|
||||||
|
en påfølgende `POST /rounds/{id}/shots/{shot_id}/share`.
|
||||||
|
|
||||||
|
**Scratch-verifisert** (femtende scratch-miljø denne økten, samme
|
||||||
|
migrasjon-002-forsiktighet, `teecup_db` bekreftet uendret): full
|
||||||
|
klikk-gjennomgang fra "Mål et slag" til arket åpner riktig, korrekt
|
||||||
|
feilmelding+"Prøv igjen" når GPS-tillatelse mangler (bekreftet ekte
|
||||||
|
-- CDP-automatiserte nettlesersesjoner har `geolocation`-tillatelse
|
||||||
|
permanent `denied` uten noen dialog å akseptere, en verktøy-
|
||||||
|
begrensning i selve test-miljøet, ikke i appen). Siden selve
|
||||||
|
GPS-suksess-stien derfor ikke lot seg klikke gjennom i denne
|
||||||
|
økten, ble de eksakte kallene `submitShot()` sender (opprett slag,
|
||||||
|
list slag, del) i stedet verifisert direkte mot API-et med samme
|
||||||
|
data-kontrakt -- alle tre 200/201, ingen feil i API-loggen. Bekreftet
|
||||||
|
i ekte nettleser at slag-tellingen faktisk oppdateres og vises i
|
||||||
|
knappeteksten ("Mål et slag (1 målt)") etter et slag er opprettet.
|
||||||
|
Scratch-miljøet ryddet opp fullstendig.
|
||||||
|
|
||||||
|
**Ikke rullet ut** -- `round_shot`-tabellen finnes ennå ikke i ekte
|
||||||
|
`teecup_db` (migrasjonen er aldri kjørt der), og `.env` har fortsatt
|
||||||
|
tomme Mapbox-token-plassholdere (kart-veien vil ikke fungere i
|
||||||
|
produksjon før brukeren skaffer et ekte token). Gjenstår før dette
|
||||||
|
kan vurderes for utrulling: inngangspunkt 2 (alltid-synlig
|
||||||
|
"N slag målt"-merkelapp på selve hull-kortet, for retroaktiv måling
|
||||||
|
OG for lagformater/side-eide hull -- denne `ScoringWizard`-veien
|
||||||
|
dekker kun deltaker-eide hull, siden delt-ball-formater bruker en
|
||||||
|
egen, enklere side-veiviser uten dette detalj-steget), ekte
|
||||||
|
Mapbox-tokens, og migrering av `060_round_shot.sql` mot ekte
|
||||||
|
`teecup_db` (krever egen, eksplisitt brukerbekreftelse).
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue