Sortering, side_fairway-fiks, ny poi_type fairway/stone_fence (ADR-084 del 5-6)

Hindringslisten manglet eksplisitt nærmest-spilleren-først-sortering --
fikset. Kryssjekk mot kildedata avdekket 12 kjente side_fairway-feil,
løst via full reimport av Tjømes 194 koordinatpunkter fra et nytt,
standardisert CSV-format (kjørt separat mot ekte teecup_db, ikke del
av denne commiten). To nye hindringstyper (fairway/stone_fence) med
egne ikoner.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Erol Haagenrud 2026-08-18 08:36:31 +02:00
parent 8a1f1f83fa
commit 1bc6b0b74d
7 changed files with 197 additions and 3 deletions

View file

@ -0,0 +1,25 @@
-- =====================================================================
-- TeeCup — migrasjon 082
-- Nye POI-typer "fairway" og "stone_fence" (voll/steingjerde)
-- =====================================================================
-- Konkret anledning (ADR-084 del 5): full reimport av Tjøme Golfklubb
-- sitt koordinat-regneark (standardisert kolonneformat, se ADR-084 del
-- 2-4) inneholdt to TYPE-verdier uten tilsvarende poi_type: "Fairway"
-- (enkeltpunkt-referanse midt i fairwayen) og "Voll" (jordvoll/
-- steingjerde). Bruker lastet opp egne ikoner (fairway.png,
-- stonefence.png) og ba om at disse legges til som egne typer.
--
-- `fairway` og `stone_fence` legges til course_poi_type-domenet
-- (migrasjon 079) -- gjelder automatisk begge koordinattabellene.
-- =====================================================================
\set ON_ERROR_STOP on
ALTER DOMAIN course_poi_type DROP CONSTRAINT course_poi_type_check;
ALTER DOMAIN course_poi_type ADD CONSTRAINT course_poi_type_check
CHECK (VALUE IN (
'green', 'green_bunker', 'fairway_bunker', 'water', 'creek',
'trees', 'marker_100', 'marker_150', 'marker_200',
'dogleg', 'road', 'tee_front', 'tee_back',
'rock', 'layup', 'landmark', 'fairway', 'stone_fence'
));

View file

@ -8616,6 +8616,94 @@ teecup_frontend && up -d`, ingen migrasjon. Rene containerlogger,
`https://teecup.golf/logg-inn` 200 OK. Ikon-mangel-lista er nå TOM --
alle klassifiserte hindringstyper har eget ikon.
### ADR-084 del 5: sortering, side_fairway-datafeil funnet, standardisert CSV-format (2026-08-18)
Bruker rapporterte to nye avvik fra ekte bruk: (1) hindringslisten
sorteres "motsatt" av forventet, (2) hull 7 sitt vannhinder fremstår
som senter selv om det faktisk ligger til venstre.
**(1) Sorteringsfiks:** `groupDiagramHazards()` (hole-target-
distance.tsx) manglet den eksplisitte "nærmest spilleren først"-
sorteringen ADR-083 sin opprinnelige flate liste hadde -- falt tilbake
til rå API-/innsettingsrekkefølge, som verken reflekterte avstand eller
oppdaterte seg når spilleren beveget seg. Fikset med
`entities.sort((a, b) => a.below - b.below)`.
**(2) Data-diagnose:** kryssjekket alle punkter i den gamle CSV-en som
eksplisitt oppga venstre/høyre mot databasens `side_fairway` -- fant 12
avvik (fjellknaus/vann/trær på hull 4/5/7/13/14/16), alle satt til
`center` i databasen når kilden sa noe annet. Mønster: punkter som IKKE
fulgte det vanlige "Forkant/Bakkant [side] [type]"-friteksten ble
tilsynelatende satt til `center` som fallback ved en tidligere import.
Bekreftet at lapping av enkeltpunkter ikke var veien videre -- for
upålitelig datagrunnlag til å stole på uten en fullstendig, ren kilde.
**Standardisert CSV-format avtalt** (kolonner: `ID,HULL,TYPE,PLASS,
PUNKT,LAT/LNG`) -- erstatter den gamle friteksten som krevde skjør
NLP-aktig parsing. `ID` er kun unik INNENFOR ett hull (samme prinsipp
som `hazard_group` allerede var designet for), tom `ID` = enkeltstående
punkt (som Tee/Green), ingen ID-kollisjon selv om flere hull gjenbruker
samme fysiske hindring (bekreftet mønster fra tidligere runder).
**Ingen migrasjon denne delen.**
### ADR-084 del 6: full reimport av Tjøme (194 punkter), to nye poi_type (2026-08-18)
Bruker leverte hele 18-hulls-fila i det avtalte formatet. Grundig
validering før noe ble kjørt (se scratchpad-analyse): fant og avklarte
med bruker seks konkrete ting -- to ukjente TYPE-verdier (`Fairway`,
`Voll`, løst med nye ikoner + migrasjon 082, se under), ett par uten
PUNKT til å skille forkant/bakkant (hull 15 sitt vann -- løst ved
brukerens egen regel: punktet som slutter på "683" er bakkant), én
tydelig kopier-lim-feil (hull 11 sin andre "Tee"-rad skulle vært
"Tre" -- bekreftet), seks rader med fortsatt ugyldige UTM/EPSG:25833-
koordinater (denne gangen løst med en ordentlig projeksjons-
transformasjon via `pyproj`, EPSG:25833→4326 -- konvergerte på under
en millimeters avvik fra forrige rundes elimineringsbaserte gjetning,
god kryssbekreftelse av begge metodene), og ett hull 18-veipunkt som
bevisst fjernes (fantes i databasen, ikke i den nye fila -- bekreftet
riktig av bruker).
**Migrasjon 082:** `fairway` og `stone_fence` lagt til
`course_poi_type`-domenet -- bruker lastet opp egne ikoner
(`fairway.png`, `stonefence.png`) for disse. `stone_fence` er den
norske "Voll" (jordvoll/steingjerde) sitt engelske domenenavn.
**Full reimport, ikke patch:** hull 4 sine green-/greenbunker-
koordinater viste seg vesentlig endret mellom gammel database og ny
fil (bl.a. det jeg i forrige runde identifiserte som "bakre
greenbunker" via elimineringslogikk var faktisk feil -- ekte bakre
greenbunker har helt andre koordinater i den nye, autoritative fila).
Dette gjorde inkrementell patching for risikabelt -- kjørte i stedet
`DELETE`+`INSERT` i én transaksjon for HELE banen (180 gamle rader
byttet ut med 194 nye), beregnet direkte fra kolonnene (ikke
friteksttolkning). Genererings-/valideringsskript i scratchpad
(engangs, ikke innsjekket).
**PLASS="Bakre"** (kun hull 4 sin greenbunker) trengte ingen
særbehandling -- beregnet `alongPercent` viste at punktet geometrisk
ligger godt innenfor normalsonen (94-97%, ikke bak green sin bakkant
på 101%+), så det rendres helt vanlig i midtbanen uten å trigge
"bak green"-sonen fra del 2. Verdt å vite: "Bakre" er en beskrivende
etikett fra klubben, ikke nødvendigvis bokstavelig "forbi flagget".
**Verifisert:** `tsc --noEmit` rent, `vitest run` 55/55, full
`./scripts/run_backend_tests.sh` 111/111 (migrasjon 082). Egen
scratch-database seedet med EKTE Tjøme-data (kopiert fra produksjon,
read-only kilde) -- reimport-SQL-en kjørt mot scratch-kopien FØRST,
bekreftet 194/39 riktig, `poi_type`-fordeling matchet plan eksakt.
Visuell bekreftelse (scratch API+frontend) av `fairway`- og
`stone_fence`-ikonene på hull 2/3, samt at sorteringsfiksen virker
riktig med ekte reimportert data (stigende avstand bekreftet hull
1/2/3). Lys+mørk bekreftet. Scratch-stacken revet ned.
**Rullet ut 2026-08-18** -- bruker bekreftet migrasjon, full reimport
og kode hver for seg. Migrasjon 082 og reimport-SQL (DELETE 180/
INSERT 194, én transaksjon) kjørt mot ekte `teecup_db`, deretter
`docker compose build teecup_frontend && up -d`. Hull 7 sitt vann
bekreftet `side_fairway='left'` etter reimport (matcher kildedataen,
rettet fra den kjente `center`-feilen).
---
## Utviklingsplan (rekkefølge)

View file

@ -12232,3 +12232,48 @@ Neste steg:
build teecup_frontend && up -d`, ingen migrasjon. Rene
containerlogger, `https://teecup.golf/logg-inn` 200 OK.
Ikon-mangel-lista er nå tom.
105. **Sortering, side_fairway-diagnose, standardisert CSV-format
(ADR-084 del 5) — 2026-08-18.** Hindringslisten manglet en
eksplisitt "nærmest spilleren først"-sortering (falt tilbake til
rå API-rekkefølge) -- fikset med `sort((a,b) => a.below - b.below)`
i `groupDiagramHazards()`. Kryssjekket samtidig alle punkter i den
gamle CSV-en med eksplisitt venstre/høyre mot databasens
`side_fairway` -- fant 12 avvik (satt til `center` når kilden sa
noe annet), som bekreftet at enkeltpunkt-lapping ikke holdt.
Avtalte i stedet et standardisert kolonneformat
(`ID,HULL,TYPE,PLASS,PUNKT,LAT/LNG`) med bruker for fremtidig
reimport -- `ID` unik kun innenfor ett hull, samme prinsipp som
`hazard_group`.
106. **Full reimport av Tjøme, to nye poi_type (ADR-084 del 6) —
2026-08-18.** Bruker leverte hele 18-hulls-fila i det avtalte
formatet. Validering avdekket og avklarte seks ting: to nye
TYPE-verdier (`Fairway`/`Voll`, egne ikoner fra bruker + migrasjon
082 for `fairway`/`stone_fence`), ett par uten PUNKT løst via
brukerens regel (siste siffer i koordinaten avgjør forkant/
bakkant), én bekreftet kopier-lim-feil (hull 11), seks UTM/
EPSG:25833-korrupte rader løst med ordentlig `pyproj`-projeksjon
(konvergerte på under 1mm avvik fra forrige rundes elimineringsvis
gjettede verdier -- god kryssbekreftelse), og ett bevisst fjernet
veipunkt (hull 18).
Hull 4 sine green-/greenbunker-koordinater viste seg vesentlig
endret mellom database og ny fil -- inkludert det forrige runde
identifiserte som "bakre greenbunker" via eliminasjon, som var feil
koordinater. For risikabelt å patche inkrementelt -- kjørte i
stedet full `DELETE`+`INSERT` (180 gamle rader → 194 nye) i én
transaksjon, beregnet direkte fra kolonnene.
**Verifisert:** `tsc --noEmit` rent, `vitest run` 55/55, full
`pytest` 111/111 (migrasjon 082). Reimport-SQL kjørt FØRST mot en
scratch-kopi av ekte Tjøme-data -- 194/39 riktig, fordeling
matchet plan eksakt. Visuell bekreftelse av `fairway`/
`stone_fence`-ikonene og sorteringsfiksen med ekte reimportert
data (hull 1/2/3), lys+mørk. Scratch-stacken revet ned.
**Rullet ut 2026-08-18** -- bruker bekreftet migrasjon, reimport
og kode hver for seg. Migrasjon 082 + reimport (DELETE 180/INSERT
194, én transaksjon) kjørt mot ekte `teecup_db`, deretter `docker
compose build teecup_frontend && up -d`. Hull 7 sitt vann
bekreftet `side_fairway='left'` etter reimport.

View file

@ -12,7 +12,19 @@
import { MapPin, TriangleAlert } from "lucide-react"
import { cn } from "@/lib/utils"
export type HazardKind = "sand" | "water" | "creek" | "rock" | "tree" | "dogleg" | "layup" | "landmark" | "road" | "generic"
export type HazardKind =
| "sand"
| "water"
| "creek"
| "rock"
| "tree"
| "dogleg"
| "layup"
| "landmark"
| "road"
| "fairway"
| "stone_fence"
| "generic"
export type DiagramHazard = {
key: string
@ -106,6 +118,8 @@ const _ICON_SRC: Partial<Record<HazardKind, string>> = {
layup: "/hole-diagram/hazard-layup.png",
landmark: "/hole-diagram/hazard-landmark.png",
road: "/hole-diagram/hazard-road.png",
fairway: "/hole-diagram/hazard-fairway.png",
stone_fence: "/hole-diagram/hazard-stonefence.png",
}
function HazardIcon({ kind, size = 32 }: { kind: HazardKind; size?: number }) {

View file

@ -60,12 +60,26 @@ const _HAZARD_LABELS: Record<string, string> = {
layup: "Layup-punkt",
landmark: "Landemerke",
road: "Vei",
fairway: "Fairway",
stone_fence: "Voll",
}
// ADR-084: hvilket ikon en hindringstype får i diagrammet. "generic"
// (typer uten dedikert ikon -- i dag ingen) faller tilbake til lucide
// sin TriangleAlert -- se hole-diagram-view.tsx.
type HazardKind = "sand" | "water" | "creek" | "rock" | "tree" | "dogleg" | "layup" | "landmark" | "road" | "generic"
type HazardKind =
| "sand"
| "water"
| "creek"
| "rock"
| "tree"
| "dogleg"
| "layup"
| "landmark"
| "road"
| "fairway"
| "stone_fence"
| "generic"
const _HAZARD_KIND: Record<string, HazardKind> = {
green_bunker: "sand",
fairway_bunker: "sand",
@ -77,6 +91,8 @@ const _HAZARD_KIND: Record<string, HazardKind> = {
layup: "layup",
landmark: "landmark",
road: "road",
fairway: "fairway",
stone_fence: "stone_fence",
}
// Grupperer rå hindringspunkter til hindrings-ENTITETER for diagrammet.
@ -157,7 +173,13 @@ function groupDiagramHazards(
location: p.location,
})
}
return entities
// ADR-083-konvensjonen ("sortert nærmest spilleren først") manglet her --
// uten denne falt rekkefølgen tilbake til rå API-/innsettingsrekkefølge,
// som ikke sier noe om avstand og heller ikke oppdaterer seg når
// spilleren beveger seg. `below` er alltid den nærmeste av forkant/
// enkeltpunkt-avstanden, så stigende sortering på den gir riktig
// "nærmest spilleren først" for både parrede og enkeltstående hindringer.
return entities.sort((a, b) => a.below - b.below)
}
export function HoleTargetDistance({

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB