Tech-infra: phases, country quizType, bounds, groepen voor Geobas 7 & 8 #60

Closed
opened 2026-04-09 09:09:20 +02:00 by Ghost · 3 comments
Ghost commented 2026-04-09 09:09:20 +02:00 (Migrated from codeberg.org)

Doel

Bouw de infrastructurele uitbreidingen die nodig zijn om het gameplay-design uit #58 mogelijk te maken. Niet-destructief: bestaande sets blijven bit-voor-bit werken.

Blocked by: #59 (regressie-baseline moet eerst af)
Design reference: #58
Validates with: Baltische staten pilot issue (volgt)

Architectuur-strategie — regressiepreventie

Alle wijzigingen zijn additief en opt-in. Bestaande sets missen de nieuwe velden en vallen automatisch terug op huidig gedrag.

Principes

  1. Additief, niet vervangend — nieuwe velden (`bounds`, `clickCorrectKm`, `phases`, `group`) zijn optioneel
  2. Branch op aanwezigheid — `renderQuestion()` en `loadLevel()` early-return naar huidig pad als `phases` ontbreekt
  3. Nieuwe data in nieuwe arrays — `ALL_COUNTRIES`, `ALL_REGIONS`, `ALL_MOUNTAINS` staan los van bestaande arrays
  4. Nieuwe GeoJSON-bestanden — `landen-europa.geojson`, `landschap.geojson`; bestaande bestanden niet aanraken
  5. Regressietests zijn blocker#59 moet groen blijven na elke sub-commit

Gedeelde code — mitigatie per wijziging

Wijziging Gedeeld? Regressie-strategie
Groep-selectiescherm boven level-select (#39) Ja Nieuwe tussenlaag; bestaand `#level-select` hergebruikt per groep. Bestaande sets krijgen default `group: 5` of `group: 6`. Daily + bonus groep-onafhankelijk.
`clickResult(distKm, setNumber)` signature-uitbreiding Ja Default-param; fallback op `CLICK_CORRECT_KM` / `CLICK_CLOSE_KM` constanten als `set.clickCorrectKm` ontbreekt
`resetMapView(setNumber)` vervangt 4× hardgecodeerde `NL_BOUNDS` Ja Helper returnt identieke call (`NL_BOUNDS`, `maxZoom: 8`) als `set.bounds` ontbreekt
`renderQuestion()` phases-branch Ja Early-return als `!set.phases`
`loadLevel()` phases-pad Ja Idem

Uit te rollen in kleine testbare stappen

Elke stap op feature-branch `feature/geobas-7-8-infra`. Elke stap eindigt met groene #59 + alle bestaande tests.

Stap 1 — Groep-selectielaag (#39)

  • Nieuwe groep-selectiescherm boven `_renderLevelSelect()`
  • Bestaande sets krijgen `group: 5` of `group: 6` veld (data-only wijziging)
  • `sessionStorage.selectedGroup` onthoudt keuze; back-knop voor wisselen
  • Daily + bonus altijd zichtbaar
  • Regressie check: #59 groen

Stap 2 — Optionele `bounds` + klik-drempels

  • `const EU_BOUNDS = 34, -25], [72, 45`
  • `const WORLD_BOUNDS = -60, -180], [75, 180`
  • `resetMapView(setNumber)` helper; 4 hardgecodeerde `NL_BOUNDS` calls vervangen
  • `clickResult(distKm, setNumber)` leest `set.clickCorrectKm` / `clickCloseKm` met fallback
  • Bestaande sets missen deze velden → fallback-gedrag identiek aan nu
  • Regressie check: #59 groen

Stap 3 — `country` quizType

  • Nieuwe globals `countryLayers`, `countryQuizLayer` naast bestaande `provinceLayers`
  • `countryDataPromise` laadt `landen-europa.geojson`
  • `setHighlightCountry()` identiek aan `setHighlightProvince()`
  • `renderQuestion()` krijgt nieuwe case `'country'`
  • Data: Natural Earth 1:50m Admin 0, geknipt tot Europa, NL-namen uit `NAME_NL` of handmatige mapping
  • Regressie check: #59 groen (het nieuwe codepad raakt bestaande sets niet)

Stap 4 — Phases-mechaniek

  • `SETS[x].phases` — optioneel array van `{ id, label, quizType, source }`
  • `loadLevel()` bouwt `activeCities` uit alle fases, elk item krijgt `phase` property
  • `currentPhaseIndex` state; `buildPool()` filtert op huidige fase
  • `renderQuestion()` checkt fase-voltooiing (alle items in fase `streak >= mastery`): bij voltooid → 1.5s overgangs-UI → `currentPhaseIndex++` → opnieuw rendern
  • Viewport past zich aan eerste item van nieuwe fase aan
  • Voortgangs-indicator in score-balk: "Landen 2/20"
  • `sessionStorage` voortgang per `{setNumber}_{phaseId}`
  • Bestaande sets zonder `phases` → early-return naar huidig pad
  • Regressie check: #59 groen

Stap 5 — Unit tests voor nieuwe utilities

  • `buildPool(setNumber, phaseIndex)` asserties
  • `clickResult(distKm, setNumber)` met set-specifieke drempels
  • Fase-overgangs-logica (fake streaks, verifieer overgang triggeren)
  • Backwards-compat: `SETS[61]` (geen phases) blijft identiek gedrag

Data-pipelines

  • Natural Earth 1:50m Admin 0 → Europa-clip → `landen-europa.geojson`. NL-namen via `NAME_NL` property waar beschikbaar, handmatige override waar nodig (Estland/Letland/Litouwen etc.)
  • OSM Overpass (bestaand) → Europese rivieren voor latere sets; niet nodig in deze infra-story
  • Landschap (gebergten, woestijnen, meren) → later in rollout-milestone, niet in infra-scope

Uit scope voor deze story

  • Wereld-GeoJSON voor sets 8.x (komt in de rollout-milestone als nodig)
  • Gebergten / woestijnen / eilanden data (komt in rollout)
  • Performance-optimalisatie van polygon-rendering (later als meting aantoont dat het nodig is)
  • "Oefen alleen één fase" knop (v1.16 overweging)

Files die wijzigen

Bestand Wijziging
`cities.js` `ALL_COUNTRIES` array, `group`-veld op bestaande sets, `EU_BOUNDS` export
`index.html` Groep-selectielaag, `resetMapView()`, phases-branching, `country` quizType, voortgangs-indicator
`landen-europa.geojson` Nieuw — Natural Earth Europa clip
`data/process-countries.js` Nieuw — script om Natural Earth te knippen en NL-namen te mappen
`test.js` Unit tests voor `buildPool`, `clickResult`, phases-logica

Acceptatiecriteria

  • Alle 5 stappen uitgerold, elk met groene #59
  • Bestaande sets 5.4, 5.5, 5.6, 5.7, 6.1–6.7, 98, 99 visueel en functioneel ongewijzigd
  • Nieuwe unit tests groen
  • `npm test` groen
  • Feature branch klaar voor pilot-level om bovenop te bouwen
  • Geen merge naar `dev` vóór pilot validatie (volgende issue)

Gerelateerd

  • Blocked by: #59
  • Design spec: #58
  • Bevat: #39 (groep-selectie)
  • Validatie: Baltische staten pilot (volgt)
## Doel Bouw de infrastructurele uitbreidingen die nodig zijn om het gameplay-design uit #58 mogelijk te maken. Niet-destructief: bestaande sets blijven bit-voor-bit werken. **Blocked by:** #59 (regressie-baseline moet eerst af) **Design reference:** #58 **Validates with:** Baltische staten pilot issue (volgt) ## Architectuur-strategie — regressiepreventie Alle wijzigingen zijn **additief en opt-in**. Bestaande sets missen de nieuwe velden en vallen automatisch terug op huidig gedrag. ### Principes 1. **Additief, niet vervangend** — nieuwe velden (\`bounds\`, \`clickCorrectKm\`, \`phases\`, \`group\`) zijn optioneel 2. **Branch op aanwezigheid** — \`renderQuestion()\` en \`loadLevel()\` early-return naar huidig pad als \`phases\` ontbreekt 3. **Nieuwe data in nieuwe arrays** — \`ALL_COUNTRIES\`, \`ALL_REGIONS\`, \`ALL_MOUNTAINS\` staan los van bestaande arrays 4. **Nieuwe GeoJSON-bestanden** — \`landen-europa.geojson\`, \`landschap.geojson\`; bestaande bestanden niet aanraken 5. **Regressietests zijn blocker** — #59 moet groen blijven na elke sub-commit ### Gedeelde code — mitigatie per wijziging | Wijziging | Gedeeld? | Regressie-strategie | |-----------|----------|---------------------| | Groep-selectiescherm boven level-select (#39) | Ja | Nieuwe tussenlaag; bestaand \`#level-select\` hergebruikt per groep. Bestaande sets krijgen default \`group: 5\` of \`group: 6\`. Daily + bonus groep-onafhankelijk. | | \`clickResult(distKm, setNumber)\` signature-uitbreiding | Ja | Default-param; fallback op \`CLICK_CORRECT_KM\` / \`CLICK_CLOSE_KM\` constanten als \`set.clickCorrectKm\` ontbreekt | | \`resetMapView(setNumber)\` vervangt 4× hardgecodeerde \`NL_BOUNDS\` | Ja | Helper returnt identieke call (\`NL_BOUNDS\`, \`maxZoom: 8\`) als \`set.bounds\` ontbreekt | | \`renderQuestion()\` phases-branch | Ja | Early-return als \`!set.phases\` | | \`loadLevel()\` phases-pad | Ja | Idem | ## Uit te rollen in kleine testbare stappen Elke stap op feature-branch \`feature/geobas-7-8-infra\`. Elke stap eindigt met groene #59 + alle bestaande tests. ### Stap 1 — Groep-selectielaag (#39) - Nieuwe groep-selectiescherm boven \`_renderLevelSelect()\` - Bestaande sets krijgen \`group: 5\` of \`group: 6\` veld (data-only wijziging) - \`sessionStorage.selectedGroup\` onthoudt keuze; back-knop voor wisselen - Daily + bonus altijd zichtbaar - **Regressie check:** #59 groen ### Stap 2 — Optionele \`bounds\` + klik-drempels - \`const EU_BOUNDS = [[34, -25], [72, 45]]\` - \`const WORLD_BOUNDS = [[-60, -180], [75, 180]]\` - \`resetMapView(setNumber)\` helper; 4 hardgecodeerde \`NL_BOUNDS\` calls vervangen - \`clickResult(distKm, setNumber)\` leest \`set.clickCorrectKm\` / \`clickCloseKm\` met fallback - Bestaande sets missen deze velden → fallback-gedrag identiek aan nu - **Regressie check:** #59 groen ### Stap 3 — \`country\` quizType - Nieuwe globals \`countryLayers\`, \`countryQuizLayer\` naast bestaande \`provinceLayers\` - \`countryDataPromise\` laadt \`landen-europa.geojson\` - \`setHighlightCountry()\` identiek aan \`setHighlightProvince()\` - \`renderQuestion()\` krijgt nieuwe case \`'country'\` - Data: Natural Earth 1:50m Admin 0, geknipt tot Europa, NL-namen uit \`NAME_NL\` of handmatige mapping - **Regressie check:** #59 groen (het nieuwe codepad raakt bestaande sets niet) ### Stap 4 — Phases-mechaniek - \`SETS[x].phases\` — optioneel array van \`{ id, label, quizType, source }\` - \`loadLevel()\` bouwt \`activeCities\` uit alle fases, elk item krijgt \`phase\` property - \`currentPhaseIndex\` state; \`buildPool()\` filtert op huidige fase - \`renderQuestion()\` checkt fase-voltooiing (alle items in fase \`streak >= mastery\`): bij voltooid → 1.5s overgangs-UI → \`currentPhaseIndex++\` → opnieuw rendern - Viewport past zich aan eerste item van nieuwe fase aan - Voortgangs-indicator in score-balk: *"Landen 2/20"* - \`sessionStorage\` voortgang per \`{setNumber}_{phaseId}\` - Bestaande sets zonder \`phases\` → early-return naar huidig pad - **Regressie check:** #59 groen ### Stap 5 — Unit tests voor nieuwe utilities - \`buildPool(setNumber, phaseIndex)\` asserties - \`clickResult(distKm, setNumber)\` met set-specifieke drempels - Fase-overgangs-logica (fake streaks, verifieer overgang triggeren) - Backwards-compat: \`SETS[61]\` (geen phases) blijft identiek gedrag ## Data-pipelines - **Natural Earth** 1:50m Admin 0 → Europa-clip → \`landen-europa.geojson\`. NL-namen via \`NAME_NL\` property waar beschikbaar, handmatige override waar nodig (Estland/Letland/Litouwen etc.) - **OSM Overpass** (bestaand) → Europese rivieren voor latere sets; niet nodig in deze infra-story - **Landschap** (gebergten, woestijnen, meren) → later in rollout-milestone, niet in infra-scope ## Uit scope voor deze story - Wereld-GeoJSON voor sets 8.x (komt in de rollout-milestone als nodig) - Gebergten / woestijnen / eilanden data (komt in rollout) - Performance-optimalisatie van polygon-rendering (later als meting aantoont dat het nodig is) - "Oefen alleen één fase" knop (v1.16 overweging) ## Files die wijzigen | Bestand | Wijziging | |---------|-----------| | \`cities.js\` | \`ALL_COUNTRIES\` array, \`group\`-veld op bestaande sets, \`EU_BOUNDS\` export | | \`index.html\` | Groep-selectielaag, \`resetMapView()\`, phases-branching, \`country\` quizType, voortgangs-indicator | | \`landen-europa.geojson\` | **Nieuw** — Natural Earth Europa clip | | \`data/process-countries.js\` | **Nieuw** — script om Natural Earth te knippen en NL-namen te mappen | | \`test.js\` | Unit tests voor \`buildPool\`, \`clickResult\`, phases-logica | ## Acceptatiecriteria - [ ] Alle 5 stappen uitgerold, elk met groene #59 - [ ] Bestaande sets 5.4, 5.5, 5.6, 5.7, 6.1–6.7, 98, 99 visueel en functioneel ongewijzigd - [ ] Nieuwe unit tests groen - [ ] \`npm test\` groen - [ ] Feature branch klaar voor pilot-level om bovenop te bouwen - [ ] Geen merge naar \`dev\` vóór pilot validatie (volgende issue) ## Gerelateerd - Blocked by: #59 - Design spec: #58 - Bevat: #39 (groep-selectie) - Validatie: Baltische staten pilot (volgt)
Ghost commented 2026-04-09 09:14:47 +02:00 (Migrated from codeberg.org)

Branch-strategie: dit werk gaat op een feature branch (bijv. feature/geobas-7-8-infra) i.p.v. direct op dev, zodat het via Cloudflare Pages preview deploys op het web getest kan worden voordat het naar dev/staging gaat.

**Branch-strategie:** dit werk gaat op een feature branch (bijv. `feature/geobas-7-8-infra`) i.p.v. direct op `dev`, zodat het via Cloudflare Pages preview deploys op het web getest kan worden voordat het naar `dev`/`staging` gaat.
Ghost commented 2026-04-09 09:19:34 +02:00 (Migrated from codeberg.org)

TDD-correctie op de uitrolvolgorde:

We werken strict red-green-refactor. Elke stap begint met het schrijven van falende tests die het gewenste gedrag vastleggen — pas daarna implementatiecode. De stappen zijn:

  1. Stap 0 — Regressie-harnas (#59): alleen tests, geen feature-code
  2. Stap 1 — Groep-selectie: eerst falende Playwright-specs (expect(groupButtons).toHaveCount(4), navigatie naar groep 7), dan pas UI
  3. Stap 2bounds + clickCorrectKm: eerst falende unit tests voor clickResult(80, 70) === 'correct' vs. clickResult(80, 61) === 'close', dan pas logica
  4. Stap 3country quizType: eerst falende tests voor loadLevel + country-polygoon op kaart, dan GeoJSON + rendering
  5. Stap 4phases: eerst falende unit tests voor buildPool(set, phaseId), fase-transitie, sessionStorage-voortgang, dan pas renderQuestion/loadLevel
  6. Stap 5 — Baltische staten (#61): eerst Playwright spec tests/baltische-staten.spec.js volledig uitschrijven (rood), dan pas data + set 70

Nooit implementatie vóór de test.

**TDD-correctie op de uitrolvolgorde:** We werken strict red-green-refactor. Elke stap begint met het schrijven van **falende tests** die het gewenste gedrag vastleggen — pas daarna implementatiecode. De stappen zijn: 1. **Stap 0** — Regressie-harnas (#59): alleen tests, geen feature-code 2. **Stap 1** — Groep-selectie: eerst falende Playwright-specs (`expect(groupButtons).toHaveCount(4)`, navigatie naar groep 7), dan pas UI 3. **Stap 2** — `bounds` + `clickCorrectKm`: eerst falende unit tests voor `clickResult(80, 70) === 'correct'` vs. `clickResult(80, 61) === 'close'`, dan pas logica 4. **Stap 3** — `country` quizType: eerst falende tests voor `loadLevel` + country-polygoon op kaart, dan GeoJSON + rendering 5. **Stap 4** — `phases`: eerst falende unit tests voor `buildPool(set, phaseId)`, fase-transitie, `sessionStorage`-voortgang, dan pas `renderQuestion`/`loadLevel` 6. **Stap 5** — Baltische staten (#61): eerst Playwright spec `tests/baltische-staten.spec.js` volledig uitschrijven (rood), dan pas data + set 70 Nooit implementatie vóór de test.
Ghost commented 2026-04-11 20:40:18 +02:00 (Migrated from codeberg.org)

Geïmplementeerd in feature/geobas-phases, gemerged naar dev. Pilot (Baltische staten, set 70) goedgekeurd door user.

Geïmplementeerd in feature/geobas-phases, gemerged naar dev. Pilot (Baltische staten, set 70) goedgekeurd door user.
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
jelmer/topoquiz#60
No description provided.