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:
parent
8a1f1f83fa
commit
1bc6b0b74d
7 changed files with 197 additions and 3 deletions
25
082_course_poi_type_fairway_stonefence.sql
Normal file
25
082_course_poi_type_fairway_stonefence.sql
Normal 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'
|
||||||
|
));
|
||||||
|
|
@ -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 --
|
`https://teecup.golf/logg-inn` 200 OK. Ikon-mangel-lista er nå TOM --
|
||||||
alle klassifiserte hindringstyper har eget ikon.
|
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)
|
## Utviklingsplan (rekkefølge)
|
||||||
|
|
|
||||||
45
CHANGELOG.md
45
CHANGELOG.md
|
|
@ -12232,3 +12232,48 @@ Neste steg:
|
||||||
build teecup_frontend && up -d`, ingen migrasjon. Rene
|
build teecup_frontend && up -d`, ingen migrasjon. Rene
|
||||||
containerlogger, `https://teecup.golf/logg-inn` 200 OK.
|
containerlogger, `https://teecup.golf/logg-inn` 200 OK.
|
||||||
Ikon-mangel-lista er nå tom.
|
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.
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,19 @@
|
||||||
import { MapPin, TriangleAlert } from "lucide-react"
|
import { MapPin, TriangleAlert } from "lucide-react"
|
||||||
import { cn } from "@/lib/utils"
|
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 = {
|
export type DiagramHazard = {
|
||||||
key: string
|
key: string
|
||||||
|
|
@ -106,6 +118,8 @@ const _ICON_SRC: Partial<Record<HazardKind, string>> = {
|
||||||
layup: "/hole-diagram/hazard-layup.png",
|
layup: "/hole-diagram/hazard-layup.png",
|
||||||
landmark: "/hole-diagram/hazard-landmark.png",
|
landmark: "/hole-diagram/hazard-landmark.png",
|
||||||
road: "/hole-diagram/hazard-road.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 }) {
|
function HazardIcon({ kind, size = 32 }: { kind: HazardKind; size?: number }) {
|
||||||
|
|
|
||||||
|
|
@ -60,12 +60,26 @@ const _HAZARD_LABELS: Record<string, string> = {
|
||||||
layup: "Layup-punkt",
|
layup: "Layup-punkt",
|
||||||
landmark: "Landemerke",
|
landmark: "Landemerke",
|
||||||
road: "Vei",
|
road: "Vei",
|
||||||
|
fairway: "Fairway",
|
||||||
|
stone_fence: "Voll",
|
||||||
}
|
}
|
||||||
|
|
||||||
// ADR-084: hvilket ikon en hindringstype får i diagrammet. "generic"
|
// ADR-084: hvilket ikon en hindringstype får i diagrammet. "generic"
|
||||||
// (typer uten dedikert ikon -- i dag ingen) faller tilbake til lucide
|
// (typer uten dedikert ikon -- i dag ingen) faller tilbake til lucide
|
||||||
// sin TriangleAlert -- se hole-diagram-view.tsx.
|
// 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> = {
|
const _HAZARD_KIND: Record<string, HazardKind> = {
|
||||||
green_bunker: "sand",
|
green_bunker: "sand",
|
||||||
fairway_bunker: "sand",
|
fairway_bunker: "sand",
|
||||||
|
|
@ -77,6 +91,8 @@ const _HAZARD_KIND: Record<string, HazardKind> = {
|
||||||
layup: "layup",
|
layup: "layup",
|
||||||
landmark: "landmark",
|
landmark: "landmark",
|
||||||
road: "road",
|
road: "road",
|
||||||
|
fairway: "fairway",
|
||||||
|
stone_fence: "stone_fence",
|
||||||
}
|
}
|
||||||
|
|
||||||
// Grupperer rå hindringspunkter til hindrings-ENTITETER for diagrammet.
|
// Grupperer rå hindringspunkter til hindrings-ENTITETER for diagrammet.
|
||||||
|
|
@ -157,7 +173,13 @@ function groupDiagramHazards(
|
||||||
location: p.location,
|
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({
|
export function HoleTargetDistance({
|
||||||
|
|
|
||||||
BIN
frontend/public/hole-diagram/hazard-fairway.png
Normal file
BIN
frontend/public/hole-diagram/hazard-fairway.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3 KiB |
BIN
frontend/public/hole-diagram/hazard-stonefence.png
Normal file
BIN
frontend/public/hole-diagram/hazard-stonefence.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.9 KiB |
Loading…
Reference in a new issue