Andre byggesteg ferdig: databaseskjemaet.
020_personal_rounds.sql — sju nye tabeller (round, round_participant, round_hole, og fire for den globale egendefinert-bane-katalogen), ingen RLS (samme app-lags-mønster som personlig profil). Scratch-verifisert med 9 sjekker kjørt som appens egen rolle (ikke superbruker): begrensninger (XOR user_id/gjestenavn, maks én eier per runde, kildekombinasjon teeoff/custom), kaskade-sletting, og en direkte bekreftelse av at GIR-utledningen (approach_result='hit' AND (score-putts) <= par-2) gir riktig svar mot ekte testdata. test_isolation.sql fortsatt 12/12.
This commit is contained in:
parent
80e293cfd4
commit
e3008be9bf
4 changed files with 284 additions and 10 deletions
209
020_personal_rounds.sql
Normal file
209
020_personal_rounds.sql
Normal file
|
|
@ -0,0 +1,209 @@
|
|||
-- =====================================================================
|
||||
-- TeeCup — frittstående rundeføring med detaljert statistikk
|
||||
-- (migrasjon 020, ADR-033)
|
||||
-- =====================================================================
|
||||
-- Frittstående runder er eid av en BRUKER (`app_user.id`), ikke en
|
||||
-- organisasjon (Beslutning A) -- INGEN RLS på disse tabellene. Samme
|
||||
-- allerede etablerte mønster som personlig profil (015)/HCP-historikk
|
||||
-- (018)/sekundær e-post (017): `plain_connection()` (ingen
|
||||
-- `app.current_org`), autorisasjon håndheves eksplisitt i app-laget med
|
||||
-- `WHERE owner_user_id = $1` i hver spørring.
|
||||
--
|
||||
-- Banedata (Beslutning C, bekreftet med bruker): offisielle teeoff-baner
|
||||
-- slås opp LIVE ved behov (ingen lokal kopi/import, kun en referanse +
|
||||
-- et navne-snapshot for visning). Egendefinerte baner som ikke finnes i
|
||||
-- teeoff havner i en NY, GLOBAL banekatalog (`personal_course` +
|
||||
-- tilhørende hull/utslag/rating-tabeller) -- delt på tvers av ALLE
|
||||
-- TeeCup-brukere (ikke org-scopet som den eksisterende `course`-tabellen),
|
||||
-- med søk-før-opprett tenkt håndtert i API-/frontend-laget for å begrense
|
||||
-- duplikater (ikke håndhevet i skjemaet).
|
||||
--
|
||||
-- `personal_course_tee_rating` har BEVISST ingen `scope`-kolonne (ulikt
|
||||
-- den org-scopede `tee_rating`) -- Beslutning G sin Net-Par-tilnærming
|
||||
-- for uspilte hull gjør at frittstående runder alltid regnes som en
|
||||
-- 18-hulls-ekvivalent gjennom ÉN formel, uansett om 9 eller 18 hull
|
||||
-- faktisk ble spilt. Ingen egen front_9/back_9-rating trengs derfor her.
|
||||
--
|
||||
-- Hver runde snapshotter par/stroke-index PER SPILT HULL på selve
|
||||
-- `round_hole`-raden (samme reproduserbarhets-prinsipp som ADR-007 sin
|
||||
-- handicap-snapshot) -- en fremtidig endring i teeoff sin banedata, eller
|
||||
-- en redigering av en `personal_course`, skal ALDRI endre en allerede
|
||||
-- spilt rundes tall retroaktivt.
|
||||
--
|
||||
-- Statistikk-modellen (Beslutning B): et fast sett navngitte felt per
|
||||
-- hull, ikke fri slag-for-slag-logging. GIR er bevisst IKKE en egen
|
||||
-- lagret kolonne -- den er alltid DERIVERBAR ved lesing
|
||||
-- (`approach_result = 'hit' AND (score - putts) <= par - 2`), se
|
||||
-- ADR-033.
|
||||
--
|
||||
-- Bevisst v1-avgrensning: en `round` er kun synlig/redigerbar for sin
|
||||
-- `owner_user_id` -- en lenket deltaker (`round_participant.user_id`
|
||||
-- satt) får IKKE egen tilgang til runden i denne runden (notert som
|
||||
-- åpent punkt i ADR-033, ikke løst her).
|
||||
-- =====================================================================
|
||||
|
||||
\set ON_ERROR_STOP on
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- Global banekatalog for egendefinerte (ikke-teeoff) baner
|
||||
-- ---------------------------------------------------------------------
|
||||
|
||||
CREATE TABLE personal_course (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name text NOT NULL,
|
||||
created_by_user_id uuid NOT NULL REFERENCES app_user(id) ON DELETE CASCADE,
|
||||
created_at timestamptz NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE TABLE personal_course_hole (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
personal_course_id uuid NOT NULL REFERENCES personal_course(id) ON DELETE CASCADE,
|
||||
hole_number smallint NOT NULL CHECK (hole_number BETWEEN 1 AND 18),
|
||||
par smallint NOT NULL CHECK (par BETWEEN 3 AND 6),
|
||||
stroke_index smallint NOT NULL CHECK (stroke_index BETWEEN 1 AND 18),
|
||||
UNIQUE (personal_course_id, hole_number),
|
||||
UNIQUE (personal_course_id, stroke_index)
|
||||
);
|
||||
|
||||
CREATE TABLE personal_course_tee (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
personal_course_id uuid NOT NULL REFERENCES personal_course(id) ON DELETE CASCADE,
|
||||
name text NOT NULL,
|
||||
UNIQUE (personal_course_id, name)
|
||||
);
|
||||
|
||||
CREATE TABLE personal_course_tee_rating (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
personal_course_tee_id uuid NOT NULL REFERENCES personal_course_tee(id) ON DELETE CASCADE,
|
||||
-- Kun m/f, ikke 'x' -- en WHS-rating er alltid for ett bestemt kjønn
|
||||
-- (samme presedens som org-scopet tee_rating, ADR-029).
|
||||
gender text NOT NULL CHECK (gender IN ('m', 'f')),
|
||||
course_rating numeric(4,1) NOT NULL,
|
||||
slope_rating smallint NOT NULL CHECK (slope_rating BETWEEN 55 AND 155),
|
||||
par smallint NOT NULL,
|
||||
UNIQUE (personal_course_tee_id, gender)
|
||||
);
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- Selve runden
|
||||
-- ---------------------------------------------------------------------
|
||||
|
||||
CREATE TABLE round (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
owner_user_id uuid NOT NULL REFERENCES app_user(id) ON DELETE CASCADE,
|
||||
|
||||
course_source text NOT NULL CHECK (course_source IN ('teeoff', 'custom')),
|
||||
-- 'teeoff': live oppslag, kun referanse + navn-snapshot lagres.
|
||||
teeoff_facility_slug text,
|
||||
teeoff_course_id text,
|
||||
-- 'custom': ekte FK til den globale katalogen over.
|
||||
personal_course_id uuid REFERENCES personal_course(id),
|
||||
CHECK (
|
||||
(course_source = 'teeoff'
|
||||
AND teeoff_facility_slug IS NOT NULL AND teeoff_course_id IS NOT NULL
|
||||
AND personal_course_id IS NULL)
|
||||
OR
|
||||
(course_source = 'custom'
|
||||
AND personal_course_id IS NOT NULL
|
||||
AND teeoff_facility_slug IS NULL AND teeoff_course_id IS NULL)
|
||||
),
|
||||
-- Snapshot for visning uten et nytt live-oppslag hver gang runden åpnes.
|
||||
course_name_snapshot text NOT NULL,
|
||||
tee_name_snapshot text NOT NULL,
|
||||
|
||||
played_at date NOT NULL,
|
||||
-- Fritt starthull (Beslutning E) -- 9/18 under er kun et UI-standardvalg,
|
||||
-- IKKE håndhevet (spilleren kan avslutte etter et vilkårlig antall hull).
|
||||
start_hole smallint NOT NULL DEFAULT 1 CHECK (start_hole BETWEEN 1 AND 18),
|
||||
holes_planned smallint NOT NULL DEFAULT 18 CHECK (holes_planned IN (9, 18)),
|
||||
|
||||
completed_at timestamptz,
|
||||
created_at timestamptz NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE INDEX ON round (owner_user_id);
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- Deltakere i runden -- eieren selv ELLER andre i flighten (Beslutning D)
|
||||
-- ---------------------------------------------------------------------
|
||||
|
||||
CREATE TABLE round_participant (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
round_id uuid NOT NULL REFERENCES round(id) ON DELETE CASCADE,
|
||||
|
||||
-- Nøyaktig én av user_id/guest_name -- en ekte TeeCup-bruker som
|
||||
-- spiller med, ELLER et rent navn uten konto (samme prinsipp som
|
||||
-- org-scopet `player` uten `user_id`).
|
||||
user_id uuid REFERENCES app_user(id),
|
||||
guest_name text,
|
||||
CHECK (
|
||||
((user_id IS NOT NULL)::int + (guest_name IS NOT NULL)::int) = 1
|
||||
),
|
||||
|
||||
is_owner boolean NOT NULL DEFAULT false,
|
||||
|
||||
-- Snapshot ved tilføyelse (samme reproduserbarhets-prinsipp som ADR-007
|
||||
-- sin handicap-snapshot) -- en senere profilendring skal ikke endre en
|
||||
-- allerede spilt rundes tall retroaktivt.
|
||||
gender text NOT NULL CHECK (gender IN ('m', 'f', 'x')),
|
||||
handicap_index_snapshot numeric(4,1), -- NULL = ingen HCP-sporing for denne deltakeren
|
||||
course_handicap_snapshot smallint,
|
||||
|
||||
-- Fylles ved fullføring (ADR-033 Beslutning F/G) -- kun sant/satt når
|
||||
-- minimums-/gyldighetskravene er oppfylt.
|
||||
counts_for_handicap boolean NOT NULL DEFAULT false,
|
||||
score_differential numeric(4,1),
|
||||
|
||||
created_at timestamptz NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE INDEX ON round_participant (round_id);
|
||||
CREATE INDEX ON round_participant (user_id);
|
||||
-- Maks én markert eier per runde.
|
||||
CREATE UNIQUE INDEX round_participant_one_owner ON round_participant (round_id) WHERE is_owner;
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- Hull-for-hull -- rating-snapshot OG statistikk, per deltaker
|
||||
-- ---------------------------------------------------------------------
|
||||
|
||||
CREATE TABLE round_hole (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
round_participant_id uuid NOT NULL REFERENCES round_participant(id) ON DELETE CASCADE,
|
||||
hole_number smallint NOT NULL CHECK (hole_number BETWEEN 1 AND 18),
|
||||
|
||||
-- Rating-snapshot (par/stroke-index på TIDSPUNKTET runden ble spilt) --
|
||||
-- se moduldoc-kommentaren øverst om hvorfor dette IKKE er en live-referanse.
|
||||
par smallint NOT NULL CHECK (par BETWEEN 3 AND 6),
|
||||
stroke_index smallint NOT NULL CHECK (stroke_index BETWEEN 1 AND 18),
|
||||
|
||||
played boolean NOT NULL DEFAULT false,
|
||||
score smallint CHECK (score IS NULL OR score BETWEEN 1 AND 20),
|
||||
putts smallint CHECK (putts IS NULL OR putts BETWEEN 0 AND 10),
|
||||
club_off_tee text,
|
||||
-- Kun meningsfullt på par 4/5 (håndheves i app-laget, ikke her).
|
||||
tee_shot_result text CHECK (tee_shot_result IS NULL OR tee_shot_result IN ('fairway', 'left', 'right')),
|
||||
-- "Innspillsslaget" = siste slag før første putt, uansett hullets par
|
||||
-- (ADR-033 Beslutning B) -- GIR er DERIVERT herfra ved lesing, ikke en
|
||||
-- egen lagret kolonne: approach_result='hit' AND (score-putts) <= par-2.
|
||||
approach_result text CHECK (approach_result IS NULL OR approach_result IN ('hit', 'long', 'short', 'left', 'right')),
|
||||
chip_count smallint CHECK (chip_count IS NULL OR chip_count >= 0),
|
||||
bunker_shot_count smallint CHECK (bunker_shot_count IS NULL OR bunker_shot_count >= 0),
|
||||
penalty_strokes smallint CHECK (penalty_strokes IS NULL OR penalty_strokes >= 0),
|
||||
first_putt_distance_m numeric(4,1) CHECK (first_putt_distance_m IS NULL OR first_putt_distance_m >= 0),
|
||||
|
||||
UNIQUE (round_participant_id, hole_number)
|
||||
);
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- Rettigheter -- INGEN RLS her (Beslutning A). teecup_app filtrerer selv
|
||||
-- med WHERE owner_user_id = $1 (round) / gjennom round_id (de to andre) i
|
||||
-- hver spørring, samme mønster som handicap_history/user_secondary_email.
|
||||
-- ---------------------------------------------------------------------
|
||||
|
||||
GRANT SELECT, INSERT, UPDATE, DELETE ON personal_course TO teecup_app;
|
||||
GRANT SELECT, INSERT, UPDATE, DELETE ON personal_course_hole TO teecup_app;
|
||||
GRANT SELECT, INSERT, UPDATE, DELETE ON personal_course_tee TO teecup_app;
|
||||
GRANT SELECT, INSERT, UPDATE, DELETE ON personal_course_tee_rating TO teecup_app;
|
||||
GRANT SELECT, INSERT, UPDATE, DELETE ON round TO teecup_app;
|
||||
GRANT SELECT, INSERT, UPDATE, DELETE ON round_participant TO teecup_app;
|
||||
GRANT SELECT, INSERT, UPDATE, DELETE ON round_hole TO teecup_app;
|
||||
|
|
@ -1829,6 +1829,30 @@ finnes? Påvirker om `handicap_history` (018) skal gjenbrukes uendret
|
|||
eller trenger en ny kolonne som skiller "manuelt satt" fra "beregnet fra
|
||||
runde".
|
||||
|
||||
**Skjemaet (migrasjon `020_personal_rounds.sql`) er ✅ SKREVET OG
|
||||
SCRATCH-VERIFISERT 2026-07-22,** som andre byggesteg (etter motoren).
|
||||
Sju nye tabeller: `round` (header, `owner_user_id`-eid, ingen RLS),
|
||||
`round_participant` (deltakere — lenket bruker ELLER gjestenavn, XOR-
|
||||
håndhevet via CHECK; maks én markert eier per runde via partiell unik
|
||||
indeks), `round_hole` (rating-SNAPSHOT + statistikk per deltaker per
|
||||
hull — GIR er bevisst IKKE en egen kolonne, kun deriverbar ved lesing:
|
||||
`approach_result='hit' AND (score-putts) <= par-2`, verifisert eksakt
|
||||
mot ekte testdata), pluss fire tabeller for den globale banekatalogen
|
||||
(`personal_course`/`_hole`/`_tee`/`_tee_rating` — sistnevnte BEVISST uten
|
||||
`scope`-kolonne, ulikt org-tabellen, siden Net-Par-tilnærmingen gjør
|
||||
9-hulls-spesifikk rating overflødig). `round`/`personal_course_*` har
|
||||
INGEN RLS (Beslutning A) — autorisasjon i app-laget.
|
||||
**Scratch-verifisert, 9 sjekker** (kjørt som `teecup_app_scratch`, ikke
|
||||
superbruker): duplikat kjønn på samme utslag avvist, teeoff+custom-felt
|
||||
samtidig avvist (CHECK), verken/begge user_id+guest_name avvist (XOR-
|
||||
CHECK), to markerte eiere på samme runde avvist, duplikat hullnummer per
|
||||
deltaker avvist, ugyldig approach_result-verdi avvist, kaskade-sletting
|
||||
av en runde fjerner alle dens deltakere+hull men lar ANDRE runder stå
|
||||
urørt. `test_isolation.sql` fortsatt 12/12 (ingen RLS-regresjon på
|
||||
eksisterende tabeller). **Gjenstår:** API-lag og frontend — ingen av
|
||||
disse er startet, og migrasjonen er IKKE kjørt mot ekte `teecup_db` ennå
|
||||
(venter på egen bekreftelse, som all annen skriving mot ekte database).
|
||||
|
||||
**Motor-komponenten (punkt 1-11) er ✅ BYGGET OG TESTET 2026-07-22,**
|
||||
som første, isolerte byggesteg (ren Python, ingen DB/API/frontend ennå —
|
||||
matcher ADR-005s "test i isolasjon FØR resten"). Nye funksjoner i
|
||||
|
|
@ -1884,12 +1908,14 @@ Alle tre store åpne punktene fra første utkast (banedata, WHS 9-hulls-
|
|||
regel, full HCP-indeksformel) er enten eksplisitt bekreftet med bruker
|
||||
(Beslutning C) eller presist kildebelagt fra den offisielle WHS Rules of
|
||||
Handicapping 2024 (Beslutning F/G) — ikke lenger antatt eller tilnærmet.
|
||||
**Første byggesteg ferdig samme dag:** hele HCP-indeks-motor-komponenten
|
||||
(Beslutning G, punkt 1-11) er bygget og testet i `handicap_engine.py`
|
||||
(41/41 tester, se detalj under Beslutning G). Gjenstår: migrasjon (nye
|
||||
tabeller for runde/deltaker/statistikk), API-lag, frontend — samme
|
||||
inkrementelle, scratch-verifiserte rytme som resten av prosjektet, ingen
|
||||
av disse er startet ennå.
|
||||
**To byggesteg ferdig samme dag:** (1) hele HCP-indeks-motor-komponenten
|
||||
(Beslutning G, punkt 1-11) bygget og testet i `handicap_engine.py`
|
||||
(41/41 tester), (2) full databasemigrasjon (`020_personal_rounds.sql`,
|
||||
sju tabeller) skrevet og scratch-verifisert (9 sjekker, se detalj under
|
||||
Beslutning G/skjema-avsnittet). Gjenstår: API-lag, frontend, OG selve
|
||||
kjøringen av migrasjonen mot ekte `teecup_db` (venter på egen
|
||||
bekreftelse) — samme inkrementelle, scratch-verifiserte rytme som resten
|
||||
av prosjektet.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
30
CLAUDE.md
30
CLAUDE.md
|
|
@ -46,6 +46,22 @@ Les dette først i hver økt. Det koder hva vi har bestemt og hvordan vi jobber.
|
|||
- Media (bilder/video) skal i objektlagring (MinIO), ikke i Postgres. Postgres
|
||||
holder bare metadata + nøkkel.
|
||||
|
||||
## Tilgjengelighet — frontend (ufravikelig, gjelder ALT, eksisterende og fremtidig)
|
||||
- Brukeren instruerte eksplisitt 2026-07-22: ALL frontend — det som
|
||||
allerede finnes OG alt som designes med V0 fremover — skal være
|
||||
lesbart, forståelig og betjenbart for noen med noe redusert syn UTEN
|
||||
briller, så langt det praktisk lar seg gjøre. Dette er en STÅENDE
|
||||
forventning til alt fremtidig UI-arbeid, ikke en engangsting for én
|
||||
skjerm.
|
||||
- Praktisk konsekvens: god kontrast, stor nok skrift, store nok
|
||||
trykkflater, ikke ikon-only uten tekst-label for viktige handlinger,
|
||||
ikke avhengig av finmotorikk/skarpt syn for å bruke appen.
|
||||
- Gjelder begge retninger: (a) ta dette eksplisitt med som krav når en ny
|
||||
V0-prompt skrives eller en V0-eksport gjennomgås, og (b) rett
|
||||
opportunistisk opp eksisterende skjermer når de likevel røres i en
|
||||
annen runde — ingen egen stor retrofit-runde er igangsatt eller bedt
|
||||
om ennå.
|
||||
|
||||
## Arbeidsmåte
|
||||
- Inkrementelt. Ingenting tas for gitt før det er testet. Bekreft hvert steg før
|
||||
du går videre.
|
||||
|
|
@ -2306,9 +2322,17 @@ Neste steg:
|
|||
uten pytest da det ikke er installert i miljøet), flere verifisert mot
|
||||
regelbokens egne tallregneeksempler (Rule 5.2a, Rule 5.1c, Diagram 5.8,
|
||||
Diagram 3.1b). Ren Python, ingen DB/API/frontend rørt ennå — matcher
|
||||
ADR-005s "test i isolasjon FØR resten". Se ADR-033 i
|
||||
ARCHITECTURE_DECISIONS.md for full detalj og gjenstående steg
|
||||
(migrasjon, API, frontend — ingen påbegynt).
|
||||
ADR-005s "test i isolasjon FØR resten".
|
||||
**Deretter, samme dag:** full databasemigrasjon skrevet
|
||||
(`020_personal_rounds.sql`, sju nye tabeller: `round`/
|
||||
`round_participant`/`round_hole` + fire for en global egendefinert-
|
||||
bane-katalog) og scratch-verifisert (9 sjekker som
|
||||
`teecup_app_scratch`, ikke superbruker — CHECK-constraints, XOR
|
||||
user_id/guest_name, kaskade-sletting, GIR-derivering bekreftet mot
|
||||
ekte data). INGEN RLS på disse tabellene (Beslutning A). `test_
|
||||
isolation.sql` fortsatt 12/12. **IKKE kjørt mot ekte `teecup_db`
|
||||
ennå** — venter på egen bekreftelse. API-lag og frontend heller ikke
|
||||
startet. Se ADR-033 i ARCHITECTURE_DECISIONS.md for full detalj.
|
||||
4. **Del 1 (fri, ukrevd sekundær-e-post) er nå BYGGET OG LIVE** (2026-07-21,
|
||||
se status over). **Del 2 (ekte konto-sammenslåing) fortsatt IKKE
|
||||
designet:** hva skjer hvis den ønskede adressen ALLEREDE tilhører en
|
||||
|
|
|
|||
|
|
@ -1368,6 +1368,12 @@ tom-skjermens endelige form kan bestemmes.
|
|||
|
||||
## Frittstående rundeføring + detaljert statistikk (uten turnering/organisasjon) — 🔨 ADR-033 SKREVET OG KILDEBELAGT, BYGGING PÅBEGYNT 2026-07-22
|
||||
|
||||
**Fremdrift 2026-07-22:** HCP-indeks-motor bygget+testet
|
||||
(`handicap_engine.py`, 41/41 tester) OG full databasemigrasjon skrevet+
|
||||
scratch-verifisert (`020_personal_rounds.sql`, 9 sjekker). Se ADR-033 i
|
||||
ARCHITECTURE_DECISIONS.md for full detalj. Gjenstår: kjøre migrasjonen mot
|
||||
ekte `teecup_db` (venter på bekreftelse), API-lag, frontend.
|
||||
|
||||
**Se ADR-033 i ARCHITECTURE_DECISIONS.md for den fulle, besluttede
|
||||
arkitekturen** (eierskapsmønster, statistikk-datamodell, HCP-indeksmotor).
|
||||
Brukeren bekreftet 2026-07-22 at teeoff-banedata skal hentes via LIVE
|
||||
|
|
@ -1640,8 +1646,17 @@ dedikert designrunde.
|
|||
|
||||
## UX / frontend (senere fase)
|
||||
|
||||
- 🔀 **Tilgjengelighet — STÅENDE krav, ikke lenger et enkeltpunkt
|
||||
(skjerpet 2026-07-22, se CLAUDE.md):** all frontend, eksisterende og
|
||||
fremtidig (inkl. alle nye V0-skjermer), skal være lesbar/forståelig/
|
||||
betjenbar for noen med noe redusert syn UTEN briller. Det tidligere,
|
||||
vagere punktet under ("høy kontrast, store knapper...") er nå en
|
||||
KONKRET instans av dette generelle, varige kravet — ikke en egen,
|
||||
isolert senere-fase-oppgave. Ingen dedikert retrofit-runde igangsatt
|
||||
ennå; rettes opportunistisk når skjermer likevel røres, og tas inn i
|
||||
enhver ny V0-prompt fremover.
|
||||
- 📋 Høy kontrast, dark/light, store +/- knapper, stor «Neste hull»-knapp
|
||||
(banebruk i sollys/med solbriller).
|
||||
(banebruk i sollys/med solbriller) — konkret eksempel på punktet over.
|
||||
- ✅ Offline-first (ADR-006) — BYGGET 2026-07-19 (ADR-028), se eget punkt
|
||||
under. Scoreregistrering (hole-scores/hole-results) fungerer nå offline
|
||||
med automatisk synk.
|
||||
|
|
|
|||
Loading…
Reference in a new issue