display_name synkroniseres nå automatisk med for-/etternavn ved profilendring. Rettet også de to eksisterende kontoene som allerede hadde fylt ut profilen sin (erolhaagenrud@gmail.com → "Tore Morell", hei@erol.no → "Erol Haagenrud") — bekreftet med en tørrkjøring først, verifisert med RETURNING etterpå.

Varsel-spørsmålet
Ekte push til telefonens varslingssystem: teknisk mulig, men ikke gratis. Fundamentet finnes (ADR-028s PWA), men iOS Safari krever at PWA-en faktisk er lagt til på hjemskjermen for at Web Push skal fungere i det hele tatt — en vanlig fane kan aldri motta push på iPhone, uansett tillatelse. Krever i tillegg ny infrastruktur (VAPID-nøkler, abonnement-tabell, utsendingslogikk, eksplisitt tillatelsesspørsmål). Reelt eget byggeløft, ikke noe jeg vil anbefale som første steg.

Anbefaling: bygg et in-app varslingssenter først — fungerer på alle enheter uten noen tillatelse, og løser akkurat det du beskrev (venneforespørsel synlig på dashbordet). Design: en notification-tabell, varsler skapt når en forespørsel sendes/aksepteres, bjelle-ikon med tall-merke i header, ny side på /my-notifications.

V0-prompten er skrevet og ligger i FEATURE_BACKLOG.md, klar til å sendes. Ekte push kan bygges som egen, senere runde hvis dere fortsatt vil ha det etterpå.
This commit is contained in:
Erol Haagenrud 2026-07-26 05:58:35 +02:00
parent a635ea289f
commit 0e17a257dc
7 changed files with 194 additions and 2 deletions

View file

@ -14,7 +14,8 @@
"Bash(rm -rf /tmp/claude-1000/-opt-teecup/a8bd2fc3-4b9c-4682-a2be-cf36e143de78/scratchpad/zip19)",
"Bash(mkdir -p /tmp/claude-1000/-opt-teecup/a8bd2fc3-4b9c-4682-a2be-cf36e143de78/scratchpad/zip19)",
"Bash(python3 -m zipfile -e \"/opt/teecup/tee-cup-login-screen \\(19\\).zip\" .)",
"Bash(curl -s -o /dev/null -w \"my-friends: %{http_code}\\\\n\" https://teecup.teeoff.no/my-friends)"
"Bash(curl -s -o /dev/null -w \"my-friends: %{http_code}\\\\n\" https://teecup.teeoff.no/my-friends)",
"Bash(python3 test_display_name.py)"
]
}
}

View file

@ -3071,7 +3071,12 @@ Disse må avklares før eller under de relevante fasene:
3. **Prising:** Per organisasjon (abonnement) eller per turnering? Påvirker ikke
isolasjonsmodellen, men påvirker fakturerings-/kvotemodell.
4. **Scramble-grensesnitt:** Arkitekturen skal ta høyde for formatet; eksakt
UI-løsning spesifiseres senere.
UI-løsning spesifiseres senere. **Utvidet 2026-07-25:** brukeren ba om
statistikk over hvor mange utslag hver spiller har hatt (dvs. hvor
mange ganger spillerens drive ble valgt) — se egen seksjon i
FEATURE_BACKLOG.md ("Scramble: statistikk over utslag brukt per
spiller") for full detalj og åpne spørsmål. Sannsynligvis samme
problemstilling for greensome.
5. **Individuell-vs-delt-ball i `hole_score`:** Håndheves i app-laget, ikke av
databasen (CHECK når ikke opp til `session.format`). Motoren/API-et må passe
på at f.eks. et foursome ikke får per-spiller-scorer.

View file

@ -2711,6 +2711,62 @@ Ferdig og verifisert:
200, `teeoff.no` upåvirket. **ADR-036 fase 1 (venner-kjernen) er
dermed helt ferdig, backend + frontend, live.**
- **Notat 2026-07-25: scramble-statistikk (utslag brukt per spiller) —
IKKE bygget, kun fanget opp.** Brukeren ba om at scramble-turneringer
skal føre statistikk over hvor mange ganger hver spillers utslag ble
valgt av laget. Dette er reelt NY datamodell — dagens `hole_score`/
`match_hole_result` for scramble er en delt rad per side, ingen
kobling til HVILKEN spiller sitt utslag ble brukt. Trolig samme
problemstilling for greensome. Krysset mot det allerede eksisterende
"Scramble-grensesnitt"-punktet i ARCHITECTURE_DECISIONS.md sin "Åpne
spørsmål"-seksjon, full detalj i FEATURE_BACKLOG.md.
- **Bug fikset: `display_name` synkroniserte aldri med for-/etternavn
(2026-07-25), rapportert av bruker med skjermbilde av dashbordet.**
`app_user.display_name` settes i dag KUN fra e-postens lokaldel ved
kontoopprettelse (`verify_magic_link`) — ADR-031s profil-fullføring la
til atskilte `first_name`/`last_name`-felt, men rørte aldri
`display_name`. Konsekvens: en bruker med fullstendig utfylt profil
viste fortsatt e-post-avledet plassholdernavn overalt `display_name`
brukes (org-medlemslister, invitasjons-e-post, dashbord-hilsen — ikke
bare dashbordet). **Fikset** i `app/routers/auth.py` sin
`update_profile`: synkroniserer nå `display_name` automatisk til
`"{first_name} {last_name}"` hver gang et av de to feltene endres via
`PATCH /auth/profile` — KUN når begge er satt etterpå (unngår et
halvferdig navn ved delvis utfylling). Scratch-verifisert (7/7 sjekker:
fersk konto får fortsatt e-post-plassholder, delvis utfylling (kun
fornavn) rører IKKE `display_name` ennå, komplett for-/etternavn
synkroniserer korrekt, urelaterte PATCH-er (f.eks. HCP) lar
`display_name` stå urørt, en SENERE navneendring re-synkroniserer på
nytt).
**Rullet ut mot ekte systemer 2026-07-25**, bruker bekreftet
eksplisitt (valgte "kjør begge deler"): `teecup_api` redeployet, samt
en engangs data-rettelse kjørt direkte mot ekte `teecup_db`
(`UPDATE app_user SET display_name = ... WHERE first_name/last_name
utfylt OG display_name avvek`) for å rette allerede-utfylte kontoer
som ikke ville blitt rettet av seg selv (krever en NY navneendring for
å trigge synk-koden). Bekreftet FØR kjøring med en dry-run `SELECT`
(2 kontoer berørt: `erolhaagenrud@gmail.com` → "Tore Morell",
`hei@erol.no` → "Erol Haagenrud"), kjørt med `RETURNING` for å
bekrefte nøyaktig hvilke rader som ble endret, `test_isolation.sql`
fortsatt 12/12 etterpå. Ingen migrasjon (ren datarettelse + kodefiks).
- **Varsler (push til telefon + in-app varslingssenter) — DESIGNET
2026-07-25, IKKE bygget.** Brukeren spurte om dagens PWA kan varsle
telefonens eget system (f.eks. ny venneforespørsel), og ba om en
in-app-fallback (bjelle-indikator + uleste-side) med et V0-prompt klart
"i tilfelle". Svar: ekte push er teknisk mulig (ADR-028s PWA-fundament),
men iOS Safari krever PWA-en installert til hjemskjermen for at Web
Push skal fungere i det hele tatt, pluss ny infrastruktur (VAPID,
`push_subscription`-tabell, `pywebpush`-utsending, eksplisitt
tillatelse) — anbefalt som EGEN, senere runde, ikke første steg.
Anbefalte i stedet et in-app varslingssenter først (ny
`notification`-tabell, triggerpunkter ved venneforespørsel sendt/
akseptert, ny `/my-notifications`-rute — ikke `/notifications`, samme
kollisjonsklasse unngått som `/rounds`/`/friends`). V0-prompt skrevet
i FEATURE_BACKLOG.md, ikke sendt ennå. Ingen kode skrevet — ren
design-/dokumentasjonsrunde.
Neste steg:
1. **Klart for bygging, venter på brukerens go-ahead:** dashbord-redesign
(ADR-035) + venner/kategorisert deling (ADR-036), begge designet

View file

@ -576,6 +576,118 @@
---
## Varsler: push til telefon + in-app varslingssenter — 📋 DESIGNET 2026-07-25, IKKE bygget
Brukeren spurte om dagens PWA-oppsett kan varsle telefonens eget
varslingssystem (f.eks. ved en ny venneforespørsel), og ba om at det uansett
finnes en in-app-fallback på dashbordet (varslingsindikator + en side med
uleste varsler) — med et V0-prompt klart "i tilfelle".
**Push-varsler til telefonens OS — teknisk mulig, men reell ny
infrastruktur, ikke en liten utvidelse:**
- Fundamentet finnes allerede (ADR-028: service worker, installerbar PWA).
Web Push (Push API + Notification API) fungerer UTEN en native app.
- **Viktig plattformbegrensning:** på iOS Safari fungerer Web Push KUN når
PWA-en er lagt til på hjemskjermen (iOS 16.4+) — en vanlig Safari-fane
kan ALDRI motta push, uansett tillatelse gitt. Android/desktop er langt
mer tilgivende.
- Krever: et VAPID-nøkkelpar, en ny `push_subscription`-tabell (én bruker
kan ha flere enheter/abonnementer), en backend-sende-funksjon (f.eks.
`pywebpush`), og et eksplisitt tillatelsesspørsmål fra nettleseren (kan
ikke sendes stille, brukeren kan avslå).
- **Vurdering:** reell verdi, men et eget, moderat-til-stort byggeløft med
en hard plattformbegrensning å designe rundt — IKKE anbefalt som første
steg.
**In-app varslingssenter — anbefalt første steg, fungerer overalt, ingen
tillatelse kreves:**
- Ny tabell `notification` (arbeidsnavn): `id`, `user_id` (mottaker),
`type`, `message` (ferdig norsk tekst, samme snapshot-prinsipp som
`author_display_name` i meldinger — unngår å måtte slå opp relaterte
data på nytt ved hver lesing), `link_path` (f.eks. `/my-friends`),
`created_at`, `read_at` (nullable).
- Triggerpunkter nå (matcher det som faktisk er bygget, ADR-036 fase 1):
`POST /friends` → varsel til mottaker ("X har sendt deg en
venneforespørsel"), `POST /friends/{id}/accept` → varsel til den
opprinnelige forespørreren ("X godtok venneforespørselen din").
Åpent for flere triggerpunkter etter hvert som appen får flere
hendelser verdt å varsle om.
- Nye endepunkter (arbeidsnavn): `GET /notifications` (liste, nyeste
først), `GET /notifications/unread-count` (lett, til selve
indikator-tallet), `POST /notifications/{id}/read`,
`POST /notifications/read-all`.
- Frontend: bjelle-ikon + tall-merke i dashbordets header, ny rute
`/my-notifications` (IKKE `/notifications` — det ville krasjet med det
nye API-prefikset, samme kollisjonsklasse som `/rounds`/`/friends`
tidligere, unngått fra start denne gangen).
**V0-prompt skrevet, IKKE sendt til V0 ennå:**
> Legg til en varslingsindikator i TeeCups dashbord-header (Next.js +
> Tailwind + shadcn/ui, mobil-først, eksisterende merkevarefarger): et
> bjelle-ikon ved siden av "Konto"/"Logg ut", med et lite, tydelig
> tall-merke når det finnes uleste varsler (ingen merke når null).
>
> Design i tillegg en egen "Varsler"-side den lenker til:
> - En liste over varsler, nyeste øverst, hver rad med kort tekst, et
> tidspunkt (f.eks. "for 2 timer siden"), og en tydelig visuell
> forskjell mellom lest/ulest (IKKE kun farge — bruk f.eks. en liten
> prikk pluss fet skrift for uleste, ikke fargen alene).
> - En "Merk alle som lest"-knapp øverst.
> - Hver rad er klikkbar og fører videre til det varselet gjelder.
> - En tydelig, vennlig tomtilstand ("Ingen varsler ennå").
>
> Tilgjengelighet er et ufravikelig krav: god kontrast, stor nok skrift,
> store trykkflater (min. 44px), aldri ikon-only uten tekstlabel på
> viktige handlinger (bjelleikonet i header er et unntak siden det er et
> universelt gjenkjent symbol, MEN skal ha en beskrivende
> `aria-label` som inkluderer antall uleste).
**Status: ren design-/dokumentasjonsrunde, ingen kode skrevet** — venter på
brukerens beslutning om (a) bygge in-app-senteret først, (b) sende
V0-prompten, eller (c) også gå videre med ekte push-varsler som en egen,
senere runde.
---
## Scramble: statistikk over utslag brukt per spiller — 📋 NOTERT 2026-07-25, IKKE bygget
Brukeren ba om at det i scramble-turneringer skal føres statistikk over
hvor mange utslag hver spiller har hatt (dvs. hvor mange ganger den
enkelte spillerens drive ble VALGT av laget som ballen man fortsetter
med).
**Reelt ny type data, ikke en liten utvidelse:** dagens
`hole_score`/`match_hole_result` er en DELT rad per side for scramble
(se det allerede eksisterende åpne punktet "Individuell-vs-delt-ball i
`hole_score`" i ARCHITECTURE_DECISIONS.md sin "Åpne spørsmål"-seksjon,
og "Scramble-grensesnitt" rett over det samme stedet) — det finnes i dag
INGEN kobling mellom en registrert hull-score og HVILKEN spiller sitt
utslag som faktisk ble valgt. Å telle "utslag brukt" krever et nytt,
eksplisitt datapunkt per hull (f.eks. hvem sitt utslag ble valgt), ikke
noe som kan utledes fra det som allerede lagres.
**Sannsynligvis samme problemstilling for greensome** (ikke eksplisitt
nevnt av bruker, men samme spilleregel-mekanikk: begge partnere slår
egen ball fra tee, ett velges) — verdt å vurdere sammen når dette
designes, ikke som to separate ting.
**Åpne spørsmål, ikke besluttet:**
- Hvem registrerer dette — kapteinen/den som fører score for laget
(samme autorisasjonsmodell som resten av match-scoring, ADR-023), og
på hvilket tidspunkt (samtidig med selve hull-scoren, eller separat)?
- Hvor vises statistikken — per match, aggregert for hele turneringen,
eller begge deler?
- Teller uspilte/ikke-registrerte hull annerledes enn et hull der ingen
eksplisitt valgte utslag ble registrert (skal det være mulig å hoppe
over)?
**Ingen datamodell eller UI designet ennå** — rent notat, fanget opp slik
at det ikke går i glemmeboken til scramble/greensome-scoring tas fatt på
som egen runde.
---
## Kommunikasjon — ✅ HELT FERDIG 2026-07-19 (ADR-025)
| Del | Status | Notat |

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

View file

@ -834,6 +834,24 @@ async def update_profile(
*values,
)
# `display_name` er brukt BREDT (org-medlemslister, invitasjons-
# e-post, dashbord-hilsen) og settes i dag KUN fra e-postens
# lokaldel ved kontoopprettelse (verify_magic_link) -- ADR-031s
# profil-fullføring la til atskilte first_name/last_name-felt, men
# rørte aldri display_name. Konsekvens (rapportert av bruker
# 2026-07-25, egen konto): en bruker med fullstendig utfylt profil
# viste fortsatt e-post-avledet plassholdernavn overalt. Fikset her
# ved å synkronisere display_name automatisk hver gang for-/
# etternavn endres -- KUN når begge faktisk er satt etterpå (unngår
# et halvferdig "Fornavn None"-navn ved delvis utfylling).
if "first_name" in updates or "last_name" in updates:
name_row = await conn.fetchrow(
"SELECT first_name, last_name FROM app_user WHERE id = $1", user.user_id
)
if name_row and name_row["first_name"] and name_row["last_name"]:
full_name = f"{name_row['first_name']} {name_row['last_name']}".strip()
await conn.execute("UPDATE app_user SET display_name = $1 WHERE id = $2", full_name, user.user_id)
if "handicap_index" in updates:
new_hcp = updates["handicap_index"]
# Kun faktiske tallverdier logges (ikke nullstilling) -- en