Voeg 28 herkenbare kleurplaten en creatieve niveaus toe (v0.4.66-beta) #4

Open
bes-r wants to merge 207 commits from bes-r/kleurplaten-v0-4-66 into main AGit

207 commits

Author SHA1 Message Date
Ramon
24816c0d64 feat: breid kleurplaten uit en verfijn details (v0.4.66-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 42s
2026-07-28 23:05:49 +02:00
Ramon
0841962824 feat: voeg thematische kleurplaten toe (v0.4.65-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 44s
2026-07-28 22:34:15 +02:00
Ramon
fcb117eb54 fix: lijn het stippenpatroon uit binnen elk blokformaat (v0.4.64-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 50s
Gewijzigde functionaliteiten:

- De open stippen in de doelvakken stonden links-boven in hun rastercel in
  plaats van gecentreerd, waardoor het patroon scheef oogde; ze staan nu op
  dezelfde as als de gevulde stippen.

- De stippen van de geldblokken en van alle cijferblokken in een smalgemaakte
  widget staken onder het blok uit. De stipmaat komt nu uit een variabele die
  elk bloktype naast zijn eigen hoogte zet, in plaats van uit losse
  hardgecodeerde regels per widget.

- De smalle-widget-weergave verkleint alleen nog de breedte; blokhoogtes
  blijven gelijk, want juist het verkleinen van de hoogte duwde het raster naar
  buiten. Letterblokken krijgen daar een passend kleiner cijfer/letterformaat.

- Nieuw vangnet: het raster houdt altijd zijn maat en het label geeft mee als
  een blokformaat krap is, zodat een nieuw blokformaat dit niet opnieuw kan
  veroorzaken.

Tests: 196 geslaagd (4 nieuw in test/dot-grid.test.js; die vier vallen ook
daadwerkelijk om op de oude CSS). Daarnaast in de browser opgemeten voor alle
zeven blokcontexten, bij normale en smalle widgetbreedte, plus screenshots en
een controle in de echte leerlingweergave.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0126hjBPD2ggZ2LEoDYZSW7S
2026-07-26 08:13:02 +02:00
Ramon
50b9f32e91 feat: voeg voortgangdetail toe aan de taalwidgets (v0.4.63-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 1m56s
Gewijzigde functionaliteiten:

- Letterblokken logt per afgerond woord hoeveel pogingen het kostte en welke
  letter op welke plek fout ging (beide invoerwijzen: blokken slepen en typen).

- Ballonnenwoord logt nu ook een verloren woord; dat leverde tot nu toe geen
  enkele voortgang op. Een gewonnen woord telt de fout geraden letters mee.

- Flitswoorden stuurt de bestaande zelfcheck ("Gelukt" / "Nog oefenen") door
  naar de voortgang; die uitkomst werd eerder weggegooid.

- Hakken & plakken krijgt dezelfde zelfcheck en daarmee als laatste taalwidget
  een goed/fout-moment; de oefening zelf verandert niet.

- Voortgang-tab toont de fouten van taal: naast fout afgesloten opdrachten ook
  "na N pogingen goed" (letterblokken kent geen faalmoment) en zelfchecks.

- Reeksstappen met flitswoorden of hakken & plakken wachten nu op een echt
  afgerond moment in plaats van meteen te completeren.

Tests: 192 geslaagd (7 nieuw), plus live nagelopen in de leerlingweergave met
echte interactie per widget en een screenshot van de Voortgang-tab.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0126hjBPD2ggZ2LEoDYZSW7S
2026-07-26 03:16:28 +02:00
Ramon
043831e1dd feat: make assignments independent from boards
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 1m28s
2026-07-25 22:15:52 +02:00
Ramon
05f3dbe56c feat: simplify assignment sequence sharing
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 55s
2026-07-24 23:08:44 +02:00
Ramon
b8e9e46819 fix: patch Fastify static security vulnerabilities
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 1m20s
2026-07-24 22:46:22 +02:00
Ramon
a7180d8390 feat: combine assignments and class management
Some checks failed
dev - build & deploy naar test / build-and-deploy (push) Failing after 56s
2026-07-24 22:36:15 +02:00
Ramon
131ffc2f38 feat: breid live klasinteractie grafisch uit
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 47s
2026-07-24 13:40:18 +02:00
Ramon
90851f960a feat: voeg live leersessies toe aan klasdashboard
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 1m38s
2026-07-24 10:53:42 +02:00
Ramon
29b12e6c81 fix: verhelp hoge find-my-way kwetsbaarheid
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 1m17s
2026-07-23 23:22:03 +02:00
Ramon
b2f6a69897 fix: maak leerkrachtfuncties zichtbaar in voorbeeldmodus
Some checks failed
dev - build & deploy naar test / build-and-deploy (push) Failing after 1m10s
2026-07-23 23:15:08 +02:00
Ramon
ae8d0d4bb4 feat: voeg leerpaden dashboard en avatarbeloningen toe
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 1m23s
2026-07-23 21:23:54 +02:00
Ramon
9dc896964d fix: maak mobiele opdrachten volledig zichtbaar
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 1m11s
2026-07-23 19:05:53 +02:00
Ramon
ff6dbc5c2e fix: voorkom witte onderstrook op mobiel
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 53s
2026-07-23 17:34:47 +02:00
Ramon
c33eb71640 fix: centreer letter- en cijferdoelvakken
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 1m4s
Gewijzigde functionaliteiten:

- Centreert doelvakken in letter-, reken-, klok-, geld-, plaatswaarde- en wereldwidgets.

- Houdt lange woordrijen scrollbaar zonder de eerste vakken af te snijden.

- Centreert kleinere geplaatste cijferblokken binnen hun doelvak.

- Verwijdert de links uitgelijnde compacte woordrij.

Tests: 160 geslaagd.
2026-07-23 17:06:26 +02:00
Ramon
34c4d6e1a4 feat: laat avatars dansen na afgeronde opdrachten
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 42s
Gewijzigde functionaliteiten:

- Voegt vijf afwisselende avatardansen toe.

- Houdt lichaam, haar en accessoires als een verbonden SVG-figuur.

- Danst na afgeronde woordgroepen, flitsrondes, galgjerondes en rekenrondes.

- Respecteert verminderde beweging met een stil feestbeeld.

Tests: 159 geslaagd; npm audit: 0 kwetsbaarheden.
2026-07-23 07:07:30 +02:00
Ramon
4544306ccd feat: voeg avatarsoortvarianten toe (v0.4.50-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 1m8s
2026-07-22 23:40:36 +02:00
Ramon
2b40488208 fix: patch fast-uri kwetsbaarheid (v0.4.49-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 1m15s
2026-07-22 23:21:23 +02:00
Ramon
6832043470 feat: maak avatarhaar natuurlijker (v0.4.48-beta)
Some checks failed
dev - build & deploy naar test / build-and-deploy (push) Failing after 43s
2026-07-22 23:13:20 +02:00
Ramon
7237cb6290 feat: breid compacte avatars uit (v0.4.47-beta)
Some checks failed
dev - build & deploy naar test / build-and-deploy (push) Failing after 35s
2026-07-22 19:59:15 +02:00
Ramon
d0522d7e33 feat: verbeter anatomie en accessoires van avatars (v0.4.46-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 58s
2026-07-21 23:25:12 +02:00
Ramon
a922caaa56 fix: behoud groep 1 beeldankers voor letters
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 44s
2026-07-21 22:29:24 +02:00
Ramon
dc3c591c76 feat: stem taalwidgets af op beginnende geletterdheid
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 1m5s
2026-07-21 22:27:44 +02:00
Ramon
6f593e05b2 fix: corrigeer woordplaatjes in taalbibliotheek (v0.4.44-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 1m1s
2026-07-21 22:01:41 +02:00
Ramon
ba4483d5d3 feat: breid taalbibliotheek uit met 1000 woorden (v0.4.43-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 59s
2026-07-21 18:50:47 +02:00
Ramon
17ee47dd09 fix: maak bordniveaus instelbaar (v0.4.42-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 42s
2026-07-21 07:58:56 +02:00
Ramon
fabe721991 feat: voeg leerjaarprofielen toe aan taal en rekenen (v0.4.41-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 39s
2026-07-20 22:45:01 +02:00
Ramon
629329894d feat: laat systeemmanager leerlingwidgets toevoegen (v0.4.40-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 53s
2026-07-20 16:06:33 +02:00
Ramon
b81f5ac5dd feat: voeg rolvoorbeeld voor systeemmanager toe (v0.4.39-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 56s
2026-07-20 14:08:37 +02:00
Ramon
9bab7f39c0 feat: koppel widgets aan kerndoelen (v0.4.38-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 39s
2026-07-19 21:46:38 +02:00
Ramon
322147d3d1 feat: voeg curriculumwiki voor volwassenen toe (v0.4.37-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 1m1s
2026-07-19 21:13:11 +02:00
Ramon
216ab8d5dd docs: leg SLO-kerndoelen 2026 vast (v0.4.36-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 39s
2026-07-19 20:58:17 +02:00
Ramon
8ccfa5dc8c feat: voortgang flinke UI-upgrade + bug (1 opdracht i.p.v. groep) + grafiek (v0.4.35-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 1m17s
- Bug gevonden en bevestigd (niet blind aangenomen): math.js riep
  onProgress maar op ÉÉN plek aan, in endRound(), NA een heel blok van
  10 sommen, met alleen het geaggregeerde totaal. Eén sessie van 10
  sommen - "een groep opdrachten" - leverde dus precies 1 rij op in
  progress_events, niet 10, en maakte "welke som ging fout" onmogelijk
  te zien (alleen een totaaltelling per blok).
- Fix: onProgress verplaatst naar check(), bij elke afgeronde som (goed
  op de eerste keer, of opgeven na 3 pogingen) - een sessie van 10
  sommen levert nu 10 progress_events-rijen op, elk met een nieuw
  optioneel detail-veld (welke som, gegeven antwoord, juist antwoord).
  letters.js/ball.js blijven deze ronde ongemoeid (hun granulariteit
  veroorzaakte niet deze bug).
- Nieuwe kolom progress_events.detail (JSONB, nullable, puur additief -
  db/020_progress_detail.sql). POST /my/progress accepteert het
  optioneel; te groot/geen plain object wordt stilzwijgend genegeerd
  zonder de rest van de log-poging te laten falen (detail is decoratief,
  geen kernfunctionaliteit).
- Voortgang-tab (admin.js) herontworpen, zelfde ontwerptaal als de
  eerdere School-navigator-herbouw: vakgebied-tabs, een
  klassenmanagement-infobadge (Groep {n} · Niveau {n}, opgehaald via de
  bestaande /levels/pupil/:id-route) zodat resultaten meteen tegen het
  toegewezen niveau afgezet kunnen worden, een met de hand getekende
  SVG-nauwkeurigheidsring + staafdiagram (goed/fout per dag, laatste 14
  dagen - geen library, zelfde aanpak als avatar.js) en een "recente
  fouten"-lijst die precies toont welke som fout ging. De bestaande
  ruwe tijdlijn blijft eronder staan, niets is verwijderd.
- Terzijde gevonden en gefixt: .am-btn.active bestond nergens in de
  CSS, waardoor de vakgebied-tabs (hier én in Klassenmanagement,
  v0.4.34-beta) geen enkele visuele aanduiding hadden welke actief was.
- Tests: test/progress-logging.test.js uitgebreid met 4 tests voor het
  detail-veld (opgeslagen, te groot genegeerd, geen plain object
  genegeerd, afwezig blijft null). Volledige testsuite: 132/132.
- Live geverifieerd: een math.js-sessie met een mix van goede/foute
  sommen doorlopen en bevestigd dat er 3 aparte POST /my/progress-
  aanroepen gebeuren voor 3 sommen (niet 1 aggregaat), elk met het
  juiste detail; de herbouwde Voortgang-tab geopend met gemockte data
  en met screenshots bevestigd dat de nauwkeurigheidsring (38% = 3/8,
  rekenkundig geverifieerd), het klassenmanagement-infobadge, de
  staafdiagram en de "recente fouten"-lijst (met de daadwerkelijke som)
  correct tonen, én dat de active-tab-fix ook op de Klassenmanagement-
  tab zichtbaar is.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014EPxzBVRXZZnBPvSAaPAbJ
2026-07-19 15:56:14 +02:00
Ramon
e7bb76b76d feat: klassenmanagement - niveaugroep + niveau per leerling per vakgebied (v0.4.34-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 1m9s
- Grootste openstaande roadmap-punt. Nieuwe tabel pupil_levels
  (db/019_pupil_levels.sql, zelfde class_id/pupil_id-vorm als
  assignments) legt per vakgebied (taal/rekenen/world) een niveaugroep
  vast (groep 1-8, gebaseerd op de leerjaren van de basisschool waaraan
  de leerdoelen gekoppeld zijn) + niveau (1-3, fijnmazige verfijning
  BINNEN die groep). Klas-standaard met individuele leerling-overrides,
  net zo laagdrempelig instelbaar als de standaard - het speciaal-
  onderwijs-geval waar dat vanaf het begin de norm is.
- Server: GET/PUT/DELETE /levels/class/:id en /levels/pupil/:id
  (src/api.js) hergebruiken exact het assignments-patroon (upsert via
  partial-unique-index, pupil-eerst-dan-klas-resolutie), plus
  GET /my/level voor de leerling-kant. Zelfde permissie
  (assignments.manage) en sameSchool/teacherOnly/pupilAccessible-
  guards als de bestaande toewijzingsroutes.
- Nieuwe admin-tab "Klassenmanagement": klas + vakgebied kiezen, een
  klas-standaard instellen, en per leerling de effectieve groep/niveau
  zien (overerft van de klas tenzij een eigen afwijking is ingesteld)
  met bewerk- en terug-naar-standaard-knoppen.
- ECHTE inhoudskoppeling, niet alleen een standaardwaarde: rekenen is
  het eerste vakgebied waarvan de SLO/TULE-leerlijn direct in
  getalgrenzen te vertalen is (groep 3 t/m 20, groep 4 t/m 100, groep 5
  t/m 1000, groep 6 t/m 10.000). Nieuwe SLO_MATH_RANGES/mathRangeFor()
  in data.js; math.js's gen() gebruikt dit voor de daadwerkelijke
  getallen zodra een leerling een groep heeft (S.yearGroup), met het
  bestaande niveau 1-3 als verfijning daarbinnen. Zonder groep blijft
  het oude vaste 10/20/100-gedrag exact bestaan.
- pupil.js geeft groep/niveau door aan taal/rekenen-widgets bij het
  mounten: niveau is een standaardwaarde (een al opgeslagen bord-niveau
  blijft leidend), groep wordt voor rekenen-widgets altijd meegegeven
  (er is geen "oud" groep-concept om te respecteren). Terzijde ook de
  stille .catch() op de nieuwe async renderPupilWidgets() opgelost.
- Taal/wereldoriëntatie krijgen deze ronde nog geen eigen
  inhoudskoppeling (vraagt een eigen contentbron per groep, nog niet
  uitgezocht) - eerlijk benoemd als vervolgstap, geen loze belofte.
- Tests: test/pupil-levels.test.js (10 tests) dekt de server-routes
  (mocked-pool-patroon) én - via dezelfde vm-techniek als elders in
  test/widgets.test.js voor MONEY_LEVELS - een ECHTE (niet regex-)test
  van mathRangeFor die bevestigt dat elke groep de juiste getalgrens
  oplevert en niveau nooit boven de groep-grens uitkomt. Twee bugs
  gevonden en gefixt tijdens het schrijven van deze tests: null-yearGroup
  werd per ongeluk als groep 1 behandeld i.p.v. "geen groep", en de
  testrol had geen klas-eigenaarschap waardoor 403 in plaats van 200
  terugkwam. Volledige testsuite: 128/128.
- Live geverifieerd in de sandbox: klas-standaard + leerling-override
  instellen in de nieuwe admin-tab, en drie scenario's in de
  leerling-omgeving die bevestigen dat de daadwerkelijk gegenereerde
  sommen binnen de juiste groep-grens blijven (geen klassenmanagement →
  ongewijzigd oud gedrag; groep zonder eigen bord-niveau → volledige
  groep-grens; groep mét een al opgeslagen bord-niveau → dat niveau
  blijft leidend, geschaald naar de juiste groep-grens).
- public/js/data.js bevatte al niet-gerelateerde, nog niet gecommitte
  wijzigingen van vóór deze sessie (extra taalthema's/woorden) - alleen
  de SLO_MATH_RANGES/mathRangeFor-hunk is hier meegenomen (git add -p),
  de rest blijft bewust ongemoeid staan, net als test/language-library.test.js.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014EPxzBVRXZZnBPvSAaPAbJ
2026-07-19 15:31:26 +02:00
Ramon
36695a06f6 fix: leerling in werken-modus kreeg abusievelijk readonly:true (v0.4.33-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 46s
- Roadmap-punt "de voortgangen werken niet" onderzocht (niet blind
  herbouwd - eerst gediagnosticeerd via de code en git-geschiedenis).
- Gevonden: pupil.js zette sinds v0.3.15-beta (toen kijken/werken-modus
  werd toegevoegd) readonly:true in BEIDE takken van de modus-keuze -
  een kopieerfout, want de hele reden voor die commit was net dat
  "werken" de leerling wél moet laten werken. In "werken"-modus hoort
  er geen readonly-vlag te staan; "kijken" (blijft ongewijzigd) is de
  enige modus die dat nodig heeft.
- Concreet effect: de twee widgets die opts.readonly daadwerkelijk
  lezen (letters.js/anchor.js) verborgen voor leerlingen in
  werken-modus onterecht hun eigen bewerk-gereedschap (woordenlijst-
  editor, opslaan/bibliotheek) - gereedschap dat een leerling in
  werken-modus wél hoort te zien. De kernoefening zelf (spellen,
  slepen) werd hierdoor niet geblokkeerd, dus dit verklaart niet de
  volledige klacht - overige widgets negeren opts.readonly toch al.
- Tegelijk de stille `.catch(()=>{})` op het voortgang-loggen vervangen
  door `console.warn` bij een mislukte POST /my/progress: een mislukte
  log (verlopen sessie, weggehaalde toewijzing, servergolf) verdween
  eerder spoorloos, wat een "werkt niet"-klacht onmogelijk te
  onderzoeken maakte.
- Nieuwe test/progress-logging.test.js dekt het serverpad dat nog
  helemaal geen tests had: leerling-eigen toewijzing wint van
  klasbrede, thuiskind-zonder-school valt terug op de gekoppelde
  ouder, geen-toewijzing geeft 400 zonder insert, niet-leerling geeft
  403, ongeldige widgetId/widgetType geeft 400 - alle zes bevestigen
  dat de SQL/toewijzingslogica zelf klopt, wat het probleem verder
  vernauwt tot de nu twee gefixte punten hierboven of iets dat alleen
  in de echte omgeving van de gebruiker reproduceerbaar is.
- Live geverifieerd: werken-modus toont nu het bewerk-gereedschap in
  letters.js (voorheen verborgen), kijken-modus blijft exact
  ongewijzigd (overlay + verborgen gereedschap). Volledige testsuite:
  118/118.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014EPxzBVRXZZnBPvSAaPAbJ
2026-07-19 14:39:00 +02:00
Ramon
643a00c1c3 feat: personage-aanmoediging uitgebreid naar klok, geld, plaatswaarde en spellen (v0.4.32-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 55s
- De math.js-pilot (v0.4.23-beta: eigen personage kort naast "Goed!" bij
  een juist antwoord) hergebruikt in vier andere widgets, zoals destijds
  al voorzien in de roadmap: klok (mountClock), geld (mountMoney),
  plaatswaarde (mountPlacevalue) en de wereldoriëntatie-spelopdracht
  (mountWorldQuiz - dekt bomen/vogels/planten in één keer - en
  mountTopography).
- Zelfde patroon overal: bij S.feedback==='good' (of S.spellSolved) en
  een ingesteld personage verschijnt renderAvatarFace(...,"md") met de
  av-cheer-animatie naast het bestaande feedbackbericht - puur visueel,
  geen nieuw feedbacktype. Zonder personage blijft het gedrag exact
  ongewijzigd.
- Geverifieerd met echte oplos-interacties (niet alleen mounten): klok
  (typemodus + toetsenbord), geld (typemodus + toetsenbord), plaatswaarde
  (blokken plaatsen via toetsenbord-Enter) en de spelopdracht (letters
  plaatsen via toetsenbord-Enter) - in alle vier verschijnt het
  personage daadwerkelijk in de feedback-HTML na een echt juist
  antwoord. Volledige testsuite: 112/112.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014EPxzBVRXZZnBPvSAaPAbJ
2026-07-19 14:03:58 +02:00
Ramon
c183c8f931 perf: opstart-fetches /auth/me en /me/data parallel i.p.v. serieel (v0.4.31-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 37s
- Beide verzoeken hangen alleen af van dezelfde sessie-cookie, niet van
  elkaars antwoord - ze werden tot nu toe na elkaar aangeroepen
  (hydrateFromServer() startte pas na een voltooide /auth/me), wat een
  hele round-trip extra kost bij elke opstart voor staf/thuisgebruikers.
- app.js vraagt ze nu tegelijk op via Promise.allSettled; hydrateFromServer()
  krijgt het /me/data-resultaat optioneel meegegeven i.p.v. het zelf
  (opnieuw) op te halen. Voor een leerling/ouder wordt dat resultaat
  genegeerd (zij krijgen sowieso geen whiteboard-data) - nooit verspild
  werk, soms ongebruikt, wat de server niet meer kost dan de bestaande
  losse aanroep die er toch al was.
- De twee andere hydrateFromServer()-aanroepen (na inloggen, na een
  save-conflict) geven bewust niets mee en halen gewoon vers op, zoals
  voorheen - alleen de allereerste opstart kan dit parallelliseren.
- Geverifieerd met de volledige testsuite (112/112) en drie losse
  boot-scenario's in de sandbox (gast/staf/leerling): in alle drie komen
  /auth/me en /me/data binnen ~1ms van elkaar aan (voorheen serieel), en
  blijft het bestaande gedrag (gast blijft gast, staf krijgt het bord,
  leerling krijgt de afgeschermde weergave) exact hetzelfde.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014EPxzBVRXZZnBPvSAaPAbJ
2026-07-19 13:43:32 +02:00
Ramon
4e4aeb4b6d feat: exporteren van vers-gegenereerde wachtwoorden als CSV (v0.4.30-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 38s
- "Exporteer als CSV"-knop toegevoegd aan het bestaande multireset-
  resultatenscherm (klas-wachtwoorden resetten in de School-navigator),
  naast de bestaande "kopieer alles"-knop.
- BELANGRIJKE BEPERKING, bewust zo: dit exporteert alleen wat op dit
  scherm al staat (net-gegenereerde wachtwoorden). Wachtwoorden worden
  na het zetten nergens leesbaar bewaard (alleen gehashet in de
  database) - er is dus geen "haal wachtwoorden van bestaande accounts
  op"-mogelijkheid en die komt er ook niet.
- CSV bevat gebruikersnaam (het echte inlogveld) naast de naam, ook al
  toont het scherm zelf alleen de naam - zonder gebruikersnaam is een
  uitdeelvel niet bruikbaar om mee in te loggen.
- Hergebruikt de csvValue()/downloadCsv()-helpers uit de vorige
  resultaten-exportfeature (v0.4.29-beta) - eerste echte tweede
  gebruiker, dus die keuze om ze lokaal in admin.js te houden i.p.v.
  te verplaatsen was terecht.
- Geverifieerd met de volledige testsuite (112/112) en een live
  browserdoorloop: klas-wachtwoorden resetten (dubbele bevestigingsklik)
  → CSV-download met correcte escaping van een leerlingnaam met komma
  én aanhalingsteken.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014EPxzBVRXZZnBPvSAaPAbJ
2026-07-19 13:31:10 +02:00
Ramon
8fe6fc10cc feat: exporteren van resultaten per klas (CSV) (v0.4.29-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 51s
- Nieuwe sectie "Exporteren per klas" in de bestaande Voortgang-tab: klas
  kiezen + "Exporteer als CSV" downloadt de volledige activiteitenlijst
  van die klas (leerling, widget, pogingen, goed, sterren, datum/tijd).
- Bouwt voort op de bestaande route GET /progress/class/:id, die tot nu
  toe geen enkele frontend-consument had.
- Server: nieuwe optionele ?limit=-queryparameter (begrensd op 5000) -
  de export vraagt expliciet meer dan de standaard activiteitenweergave
  (200) op, zodat een drukke klas niet stilzwijgend wordt afgekapt in het
  exportbestand. Zonder de parameter blijft het bestaande gedrag (200)
  ongewijzigd.
- Eerste CSV-export in deze codebase: kleine lokale csvValue()/
  downloadCsv()-helpers in admin.js (komma/quote/newline-escaping,
  BOM zodat Excel-NL accenten en komma-scheiding herkent) - bewust nog
  niet gedeeld/verplaatst naar core.js, want er is nu nog maar één
  gebruiker (de geplande wachtwoorden-export kan dit later hergebruiken).
- Tests: test/progress-export.test.js (limit wordt doorgegeven, te hoge
  waarde wordt afgekapt op 5000, standaardgedrag zonder parameter blijft
  200) + volledige testsuite (112/112). Ook live geverifieerd: klas
  kiezen zonder selectie toont een hint i.p.v. te crashen, een echte
  CSV-download met correcte escaping van komma's/aanhalingstekens in
  een leerlingnaam, en de vertaalde widget-namen in de kolommen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014EPxzBVRXZZnBPvSAaPAbJ
2026-07-19 12:54:48 +02:00
Ramon
09a1326c7e feat: meer personage-accessoires incl. zonnebril (v0.4.28-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 1m10s
- Nieuwe hoofdaccessoires: zonnebril, koptelefoon, feesthoedje.
- Nieuwe lichaamsaccessoires: ketting, rugtas (bandjes over de
  schouders, zichtbaar van voren).
- Server-validatie (src/api.js) en vertalingen (nl+en) meegewerkt met
  dezelfde nieuwe waarden - anders zou de client een optie tonen die de
  server als "ongeldig hoofdaccessoire" afwijst.
- Geen wijziging aan de bestaande pet/kroon-onderdrukkingsregel nodig:
  zonnebril/koptelefoon/feesthoedje bedekken het bovenhoofd niet volledig,
  dus haar blijft er gewoon zichtbaar naast/onder.
- Geverifieerd: alle select-opties komen aan in de instellingen-editor,
  een PUT met de nieuwe waarden slaagt (bestaande server-validatie
  accepteert ze nu), en alle soort/accessoire-combinaties oogden goed in
  screenshot (zonnebril op de dino, koptelefoon op het monster,
  feesthoedje + ketting samen, rugtas op het dier).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014EPxzBVRXZZnBPvSAaPAbJ
2026-07-19 11:55:25 +02:00
Ramon
817f12b70d fix: dino-rugstekels en beer-staart oogden vreemd (v0.4.27-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 35s
- Dino: rugstekels stonden als een rij spitse vormen voor de hals/borst
  ("Ga als designer kijken" - gebruiker vond dit "wat vreemd"), wat als
  een rare kraag oogde. Verplaatst naar een klein randje bovenop de kop
  (zoals kleine hoorntjes) - dichter bij de anatomische plek (rug/kruin)
  en rustiger op klein formaat.
- Dier (beer): had een los staartje opzij op dezelfde hoogte en met
  vrijwel dezelfde vorm/grootte als de armen/benen, waardoor het als een
  extra ledemaat oogde. Verwijderd - een beer laat van de voorkant
  sowieso nauwelijks iets van zijn staart zien, dus dit is ook
  anatomisch kloppender dan een zichtbaar zij-staartje.
- Overwogen: SVG vs. PNG-lagen als basis. SVG blijft de juiste keuze
  hier - lichaams-/haarkleur zijn vrije kleurkiezers (elke hex-waarde),
  wat via fill-attributen triviaal is maar bij PNG een vast palet of
  canvas-hertintplugin zou vereisen; SVG schaalt bovendien scherp op
  alle drie weergavegroottes zonder aparte assets.
- Geverifieerd: alle vijf bestaande scenario's, volledige testsuite,
  en een School-navigator met een echte klas (leerling met dier-
  personage toont nu geen vreemd zij-staartje meer).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014EPxzBVRXZZnBPvSAaPAbJ
2026-07-19 11:44:55 +02:00
Ramon
46696b0d7d refactor: personage-tekening volledig herbouwd als SVG (v0.4.26-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 1m40s
- Kernprobleem: de CSS-laagjesversie (losse divs met percentage-posities
  en z-index) had onderdelen die los van het lichaam hingen en een
  tekenvolgorde die niet klopte (soort-specifieke delen soms achter
  hoofd/lijf verstopt, soms er los voor zwevend). SVG lost dit
  structureel op: tekenvolgorde = laagvolgorde, geen z-index nodig, en
  elk onderdeel is een gebogen path/ellips die het silhouet van het
  vorige onderdeel ruim overlapt in plaats van ernaast te zweven.
- Onderzocht hoe gangbare avatar-generators (DiceBear, Avataaars) dit
  aanpakken: vaste 100x100 viewBox, onderdelen als SVG-groepen in de
  juiste volgorde, kleur via directe fill-waarden i.p.v. CSS-variabelen
  in SVG. Dat patroon hier toegepast, geen code overgenomen.
- Elke soort (dino/monster/dier) is nu een samenhangend lichaam: poten,
  armen, staart/oren, buikvlek en gezicht overlappen allemaal duidelijk
  met het hoofd/lijf. Dino: rugstekels, snuit met neusgaten, glimlach.
  Monster: hoorntjes, brede mond met slagtandjes, asymmetrische ogen.
  Dier: ronde oren, beer-snuit, kleine staart.
- Haar (spits/krullen/paardenstaart/mohawk) en accessoires (pet/kroon/
  bril/strik/sjaal/cape/badge) opnieuw getekend zodat ze ook echt op
  hun naam lijken, i.p.v. simpele gekleurde blokjes.
- Regel toegevoegd: een pet of kroon dekt het hele bovenhoofd af, dus
  onderliggend haar wordt dan niet getekend (gaf anders rommelige,
  half verstopte plukjes rond de rand) - een paardenstaart blijft wel
  zichtbaar, want die hangt naar opzij.
- Kleuren (lichter voor buik/snuit, donkerder voor poten/staart/
  rugstekels) worden nu berekend uit de gekozen lichaamskleur zelf
  (avatarShade-helper), i.p.v. via CSS filter:brightness().
- CSS: alle oude .av-* laag-regels (~65 regels) verwijderd; alleen
  afmetingen (sm/md/lg) en de bestaande instellingen/widget/
  aanmoedigings-CSS blijven staan.
- Geverifieerd: alle vijf bestaande scenario's (opslaan, widget,
  School-navigator-badge met een echte klas vol verschillende
  personages, math.js-aanmoediging, ongeldige input), plus uitgebreide
  screenshot-rondes van losse onderdelen, alle soort/haar/accessoire-
  combinaties en alle drie weergavegroottes (24/44/180px) vóór het
  committen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014EPxzBVRXZZnBPvSAaPAbJ
2026-07-19 10:19:19 +02:00
Ramon
4438fad52b fix: dino-personage krijgt een echt dinolichaam i.p.v. een blote romp (v0.4.25-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 1m5s
- Buikvlek (lichter gekleurde ovaal) op de romp - een klassiek dino-kenmerk
  dat meteen de "kleurvlek zonder vorm"-indruk wegneemt.
- Twee kleine pootjes onderaan en twee stompe armpjes opzij (T-rex-stijl) -
  het lichaam stond eerder als een rond blok zonder ledematen.
- Staart herzien naar een echte taps toelopende vorm (clip-path) i.p.v. de
  ronde druppelvorm van hiervoor.
- Alleen voor soort "dino" - monster/dier ongewijzigd, geen regressie
  (gecontroleerd via de screenshot-galerij van alle drie soorten samen).
- Geverifieerd op alle vijf bestaande scenario's (opslaan, widget,
  School-navigator-badge, math.js-aanmoediging, ongeldige input) én
  opnieuw op alle drie weergavegroottes (24/44/180px) vóór het committen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014EPxzBVRXZZnBPvSAaPAbJ
2026-07-19 09:57:48 +02:00
Ramon
9bf91f0bd1 fix: personage-tekening had een gezicht noch duidelijke dino-vorm (v0.4.24-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 36s
- Elk personage kreeg ogen (was volledig gezichtsloos - de kernoorzaak van de
  lage beeldkwaliteit: een gekleurde vlek zonder gezicht oogt nooit als een
  figuur, ongeacht soort/haar/accessoires).
- Dino kreeg een snuitje met neusgaten, een duidelijk zichtbaar staartje en
  een derde, groter/donkerder rugstekel-plaatje - hiervoor waren de
  rugstekels aanwezig maar onzichtbaar (z-index onder het lijf/hoofd, zie
  vorige commit), nu bewust vóór het silhouet getekend zodat ze altijd tonen.
- Snuitje stond eerst z-index-onder de rugstekels (dus zelf ook onzichtbaar,
  identieke fout als hierboven) - z-index verhoogd zodat het snuitje altijd
  vóór de rugstekels ligt, wat ook anatomisch klopt (snuit zit vooraan).
- Geverifieerd met alle vijf scenario's uit de vorige verificatie (opslaan,
  widget, School-navigator-badge, math.js-aanmoediging) plus een losse
  screenshot-galerij op alle drie weergavegroottes (24/44/180px).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014EPxzBVRXZZnBPvSAaPAbJ
2026-07-19 09:50:18 +02:00
Ramon
24d89b8bb5 feat: eigen personage (avatar) voor leerlingen, ouders en staf (v0.4.23-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 36s
- Nieuwe migratie db/018_user_avatar.sql: kolom avatar_data (jsonb) op users.
- publicUser() geeft avatar overal automatisch mee (login, /auth/me,
  /admin/users) - bestaande school/klas-rechten regelen vanzelf wie welke
  personages ziet, geen nieuwe permissie-sleutel nodig.
- Nieuwe route PUT /me/avatar (open voor elke ingelogde rol, zelfde patroon
  als /me/data): valideert soort/kleuren/haar/accessoires, slaat de eigen rij op.
- Nieuwe gedeelde module public/js/avatar.js: personage samenstellen uit
  soort (dino/monster/dier - elk met een vast eigen lichaamsdeel, ook de
  gevraagde dinostekels), lichaams- en haarkleur, haarstijl en hoofd-/
  lichaamsaccessoires; gedeelde editor-UI voor zowel de instellingen-sectie
  "Mijn personage" als de nieuwe widget.
- Instellingen-sectie "Mijn personage" (cms.js-patroon) - de leerling-toegang,
  want widgets van categorie "class" zijn niet toewijsbaar in het
  afgeschermde leerling-speelscherm.
- Widget 🦖 toegevoegd aan het bord (categorie "class") voor staf en
  volledige-whiteboard-gebruikers.
- School-navigator (admin.js): leerkracht/beheerder ziet nu het personage
  van elk klaslid in de personenlijst i.p.v. altijd de initialen-cirkel.
- Voorbereiding gerelateerd roadmappunt: math.js toont het eigen personage
  kort naast "Goed!" als aanmoediging (pilot in één widget, geen nieuw
  feedbacktype); zonder ingesteld personage blijft het gedrag ongewijzigd.
- Vertalingen (nl+en) voor de nieuwe widget, instellingen-sectie en editor.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014EPxzBVRXZZnBPvSAaPAbJ
2026-07-19 07:34:25 +02:00
Ramon
8b57922307 fix: schoolbeheerder zichtbaar als groepsleiding + A+-knop verspringt niet meer (v0.4.22-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 36s
- Een schoolbeheerder (of systeemmanager) die aan een klas gekoppeld werd,
  kwam daar niet zichtbaar te staan: de klas-detailweergave en de
  staf-telling op de klastegel filterden op role==="teacher", terwijl de
  server al sinds v0.3.38 elke stafrol (teacher/admin/super) toestaat in
  class_teachers. Puur een weergavebug op de client - de koppeling zelf
  werkte al goed. Nieuwe isClassStaff()-helper matcht nu exact de
  serverkant se toegestane rollenset.
- De "+" in de A+-zoomknop (toolbar én het per-widget contentzoom-knopje)
  gebruikte de CJK-volle-breedte "+" (U+FF0B) naast de gewone letter "A" -
  dat teken valt vermoedelijk terug op een ander lettertype dan Quicksand,
  waardoor de relatieve positie t.o.v. de "A" verspringt zodra
  document.body.style.zoom verandert. Vervangen door de gewone ASCII "+"
  (net als de A−-knop al een normaal minteken gebruikt, niet de volle-
  breedte variant).
2026-07-19 01:06:39 +02:00
Ramon
9920fd3855 feat: vier sociaal-emotionele widgets, waaronder een geluidsmeter (v0.4.21-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 36s
- Geluidsmeter: meet het klasgeluid live via de microfoon in een verticale
  meter (rustig/pratend/te luid). Twee aanpasbare streefniveaus ("Rustig
  tot" / "Te luid vanaf") laten de leerkracht de meter afstemmen op het
  eigen lokaal en apparaat. Microfoon staat standaard uit en start alleen
  na een expliciete klik; er wordt niets opgenomen of verstuurd, alles
  blijft lokaal in de browser. Stopt de microfoonstream vanzelf zodra de
  widget van het bord verdwijnt, ook als "Stop" niet eerst is ingedrukt.
- Gevoelszones: individuele check-in met vier zones (blauw/groen/geel/
  rood, Zones of Regulation-stijl) - elke zone geeft een korte uitleg én
  een concrete tip om jezelf te helpen. Anders dan de bestaande
  Gevoelsmeter (mood.js), die een anonieme klaspoll is.
- Ademhalingsoefening: een groeiende/krimpende cirkel begeleidt rustig
  ademhalen in drie instelbare tempo's (4-4, 4-7-8, box breathing),
  met rondjesteller.
- Complimentenmachine: trekt een willekeurig compliment uit twintig
  kindvriendelijke complimenten, met dezelfde spin-en-onthul-animatie als
  de namenkiezer.
- Alle vier volledig tweetalig (nl/en), toegevoegd aan de mobiele-dekking-
  test, en geverifieerd in de browser inclusief een echte (fake) micro-
  foonstream voor de geluidsmeter.
2026-07-19 00:44:39 +02:00
Ramon
63490719d6 fix: letterblokken bij wereldoriëntatie verschillen nu ook per niveau (v0.4.20-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 51s
- De nieuwe "Letterblokken"-werkvorm (v0.4.18) verklapte op elk niveau
  altijd elke letter - alleen de soorten-/plaatsenpool werd moeilijker,
  de spelopdracht zelf bleef identiek. Bij de originele letterblokken-
  widget (letters.js) maakt niveau juist de opdracht zelf moeilijker:
  niveau 1 verklapt alles, niveau 3 niets.
- Zelfde schaal nu ook hier: niveau 1 toont elke letter, niveau 2 ongeveer
  de helft (willekeurig gekozen, vast per opdracht), niveau 3 toont geen
  enkele letter. Het puntenpatroon per vak blijft op elk niveau zichtbaar
  als tastbare hint, ook wanneer de letter zelf verborgen is.
- Geverifieerd: niveau 1 toont 11/11 letters, niveau 2 ~helft, niveau 3
  0/13 (met de puntenpatronen nog intact).
2026-07-19 00:23:39 +02:00
Ramon
705bb7800a fix: niveaus bij wereldoriëntatie nu als knoppenrij, net als de andere oefenwidgets (v0.4.19-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 56s
- Bomen/vogels/planten/topografie verstopten "Niveau" als een los
  keuzeveld onderin het inklapbare Instellingen-paneel; de oefenklok,
  het geldwidget, plaatswaarde en rekenwidgets tonen niveau altijd als
  een knoppenrij bovenaan, direct zichtbaar tijdens het spelen.
- Niveau is nu overal dezelfde knoppenrij (Niveau 1/2/3, met uitleg per
  knop via title, net als bij de oefenklok) direct in de bovenbalk naast
  de score - geen Instellingen meer nodig om niveau te wisselen.
- Niveau wisselen zet score en reeks terug naar 0, zoals bij de andere
  oefenwidgets (voorheen bleef de score gewoon doorlopen).
- Topografie: de knoppenrij verdwijnt bij "Landsdelen", waar niveau toch
  al niet van toepassing was - zelfde gedrag als voorheen, nu alleen
  consistent met de rest.
2026-07-19 00:16:09 +02:00
Ramon
5cdc854e69 feat: flitskaarten en letterblokken bij wereldoriëntatie (v0.4.18-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 37s
- Bomen, vogels en wilde planten krijgen twee nieuwe werkvormen naast
  Leren/Quiz: Flitskaarten (naam kort tonen, dan zelftoets - zelfde opzet
  als het losse Flitswoorden-widget) en Letterblokken (de naam met
  sleepblokken spellen, zelfde mechaniek als de letterblokken-widget,
  inclusief puntenpatroon per letter).
- Topografie krijgt dezelfde twee werkvormen: flitskaarten tonen de kaart
  met de plek pas gelabeld na onthullen, letterblokken laat de naam van de
  gemarkeerde provincie/plaats/rivier/werelddeel spellen.
- Letterblokken werkt ook bij namen met spaties (bv. "Witte
  paardenkastanje") - spaties worden een visuele tussenruimte, geen vak.
- Geverifieerd door alle vier widgets (bomen/vogels/planten/topografie)
  volledig te spelen: flitskaart onthullen + zelftoets, en een woord
  volledig spellen puur op basis van de getoonde puntenpatronen.
2026-07-18 19:35:08 +02:00
Ramon
daad79c8b9 fix: vakken tonen nu het puntenpatroon van het júíste cijfer, zoals bij letterblokken (v0.4.17-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 56s
- De vorige puntenpatroon-fix (v0.4.16) loste alleen op dat de tien
  cijferblokken onderling verschillen. De écht ontbrekende stap: bij de
  letterblokken en de rekenwidgets (madd/msub/mmul/mdiv/mpct) toont een
  leeg vakje altijd het puntenpatroon van het cijfer/de letter die er
  hoort te staan - een tastbare hint, ongeacht wat er al ligt. Bij de
  oefenklok en het geldwidget toonde het vakje in plaats daarvan niets
  (leeg) of het patroon van wat er toevallig al in lag - geen hint.
- Oefenklok (blockAnswer), geldwidget (digitAnswer) en de nieuwe
  plaatswaarde-oefening (buildAnswer) tonen nu overal het patroon van het
  juiste doelcijfer per vak, consistent met letterblokken/rekenwidgets.
- Geverifieerd door drie oefeningen (geldrekenen niveau 2/3, oefenklok
  niveau 3, plaatswaarde niveau 3) volledig op te lossen met uitsluitend
  de puntenpatronen als leidraad (geen tekst gelezen) - in alle gevallen
  "Goed gedaan!".
2026-07-18 16:33:07 +02:00
Ramon
bab1018142 fix: cijferblokken kregen elk een eigen puntenpatroon + niveaus voor plaatswaarde (v0.4.16-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 35s
- De cijferblokken (oefenklok, geldwidget) hergebruikten de braille a-j-
  patronen, die nooit de onderste rij (posities 3/6) gebruiken - daardoor
  leken alle tien blokken op elkaar. Eigen DIGIT_DOTCODE-tabel die alle
  zes stippen inzet, geeft elk cijfer nu een echt eigen vorm.
- Plaatswaardetabel-widget had geen enkele oefenvorm (alleen een vrij
  invoerveld); nieuwe "Bouwen"-stand met drie niveaus (T/E, H/T/E, of
  HD/TD/D/H/T/E) laat kinderen een getal opbouwen door cijferblokken in
  de juiste kolom te slepen, met score/reeks en directe feedback - zelfde
  bouwsteen als de oefenklok/het geldwidget. De vrije verkenstand blijft
  ongewijzigd bestaan.
- Bijvangst: instellingenvelden met .hidden (bv. "24-uursklok" bij de
  oefenklok) werden nooit echt verborgen door een CSS-specificiteitsbotsing
  (.edu-controls label versloeg [hidden]); toegevoegde regel herstelt dit
  voor alle leerwidgets.
2026-07-18 15:46:24 +02:00
Ramon
e555876fa4 feat: cast bord/widget vanaf whiteboard naar klas of leerling (v0.4.15-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 38s
- Nieuwe Cast-knop (📡) op de whiteboard-toolbar opent een sheet om het
  geopende bord - of één widget erop met kijken/werken - direct naar een
  klas of leerling uit te zenden, zonder om te weg via Instellingen.
- Hergebruikt de bestaande PUT/DELETE /assignments/class|pupil routes
  ongewijzigd; geen serverwijziging nodig.
- Instellingen > Toewijzingen blijft bestaan maar toont nu alleen de
  huidige toewijzing + een "Loskoppelen"-knop (aanmaken/wijzigen gebeurt
  voortaan via Cast).
2026-07-18 13:26:26 +02:00
Ramon
3c3638d114 feat: "School" herbouwd als drill-down navigator (v0.4.14-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 56s
Volledige herbouw van het "School"-tabblad naar het goedgekeurde concept
(tegel-overzicht -> gefocust detailscherm), i.p.v. drie secties op één lange
pagina. Zelfde patroon op elk niveau:
- "alle scholen" (systeemmanager): tegel per school + Systeemmanagers/Ouders/
  Zonder school + "+ School"
- een school: tegel per klas + Schoolbeheerder/Niet ingedeeld/Ouders/
  Aanmeldingen + "+ Klas"; "⋯" toont schoolbeheer (naam/verwijderen, alleen
  systeemmanager)
- een klas: Groepsleiding en Leerlingen als twee eigen sublijstjes, elk met
  een eigen "+"; "⋯" toont klasbeheer (verplaatsen/resetten/verwijderen)
- een platte groep: één lijst, evt. met "+"

Personen en aanmeldingen openen nu in een sheet (bestaande userTools()/
requestTools() vrijwel ongewijzigd hergebruikt) i.p.v. een los detailpaneel.
Zoeken vult, op tegel-niveau, het scherm met een systeembrede resultatenlijst.
Een leerkracht (groepsleiding) blijft de eenvoudige platte leerlingenlijst
zien, ongewijzigd.

Vervallen (overbodig dankzij drill-down, elke lijst is al kort en gefocust):
het hele inklap-/inspring-mechanisme (group(), openGroups/closedGroups,
editToggle, classHeadRow, applyUserFilter, .am-classhead, .am-indent), het
oude master-detail-paneel (selectedUserKey/syncSelection/renderDetail), en de
generieke "Nieuwe gebruiker"-knop (elke tegel se eigen "+" dekt dit al,
rol+context-correct).

Geen serverwijziging - pure client-herbouw van navigatie/weergave.
Geverifieerd in een echte headless Chromium voor systeemmanager (root +
school + klas + sheet + "+Groepsleiding" koppelt nog echt), schoolbeheerder
(eigen school, geen schoolkiezer/kebab-op-schoolniveau) en groepsleiding
(platte lijst, ongewijzigd).
2026-07-18 09:47:16 +02:00
Ramon
8580e46f4c fix: School-menu opnieuw ontworpen naar één consistente visuele taal (v0.4.13-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 1m0s
Was rommelig/te veel niveaus door TE veel verschillende stijlen op dezelfde
pagina: kaarten (Scholen) naast platte rijen (Gebruikers), een teal-getint
klasrijtje, een grijs getint paneel om Scholen - vier stijlen die om
aandacht streden i.p.v. één samenhangend geheel.

- Scholen gebruikt nu dezelfde platte .am-list/.am-row-stijl als de
  klassen/gebruikers-boom eronder i.p.v. losse kaarten in een eigen paneel;
  het paneel (.am-panel) is weg
- de ingeklapte beheerderslijst per school is weg - die informatie stond al
  in Gebruikers (gegroepeerd per school bij "alle scholen"), dubbel tonen
  droeg alleen bij aan de herrie
- klasrij heeft geen eigen teal-kader meer (alleen de naam iets zwaarder);
  hiërarchie loopt nu via een lichte inspringing (.am-indent) voor
  Groepsleiding/Leerlingen en hun rijen/+-knoppen, niet via kleur
- nieuwe editToggle()-helper: gebruikers-, klas- en schoolrijen delen nu
  dezelfde "Bewerken"-knop-implementatie i.p.v. drie keer bijna-dezelfde
  code, met een eigen openSchoolTools-Set (schoolrol- en klas-id's kunnen
  samenvallen met gebruikers-id's)
- geverifieerd in een echte headless Chromium: Scholen en Gebruikers ogen nu
  als één systeem, klas-substructuur is duidelijk ingesprongen, en de
  bestaande functionaliteit (rename/delete/reset/koppelen) werkt nog
2026-07-18 06:16:37 +02:00
Ramon
8db67b9cd6 fix: overzicht en scheiding in de Scholen-sectie van School (v0.4.12-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 1m15s
De losse schoolkaarten stonden zonder eigen kader los in de pagina en liepen
zonder duidelijke grens over in de Gebruikers-sectie eronder - verwarrend
omdat dezelfde schoolnaam daar soms letterlijk direct weer opduikt (nu als
groepskop i.p.v. kaart).

- Scholen krijgt een eigen omkaderd paneel (.am-panel) dat alle schoolkaarten
  en "+ School" samenbindt tot één zichtbaar geheel
- duidelijke scheidingslijn + meer ruimte vóór de volgende sectiekop, maar
  alleen ná een echte sectie (geen ongewenste lijn boven Gebruikers wanneer
  Scholen niet getoond wordt, bv. bij een gekozen school)
- geverifieerd in een echte headless Chromium: zowel de "alle scholen"-
  weergave (met paneel) als de weergave voor een gekozen school (zonder,
  geen regressie)
2026-07-18 05:46:26 +02:00
Ramon
5b4c3163a5 feat: Klassen en Gebruikers samengevoegd tot één boom per school (v0.4.11-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 51s
- klas, Groepsleiding en Leerlingen staan nu letterlijk bij elkaar: elke klas
  krijgt een eigen rij (naam + "Bewerken" voor verplaatsen/resetten/
  verwijderen, overgenomen uit het oude losse Klassen-paneel) met daaronder
  twee eigen sublijstjes - Groepsleiding (leerkrachten gekoppeld aan die
  klas) en Leerlingen - elk met een eigen "+"-knop
- "+ Groepsleiding" bij een klas maakt de nieuwe leerkracht niet alleen aan,
  maar koppelt die ook meteen aan die klas (hergebruikt de bestaande, al
  geteste POST /admin/classes/:id/teachers-route - geen serverwijziging)
- Schoolbeheerder blijft een eigen, vlakke groep los van de klassenboom (ook
  als een schoolbeheerder toevallig aan een klas gekoppeld is, om dubbele
  vermeldingen te voorkomen); Niet ingedeeld bundelt leerkrachten zonder klas
  en leerlingen zonder klas
- renderKlassenPanel is verwijderd (zijn inhoud leeft nu in de klas-tak van
  renderGebruikersPanel); de losse "Klassen"-kop in het School-tabblad is weg
- nieuwe openClassTools-Set voor het in-/uitklappen van klasbeheer, apart van
  openRows (klas- en gebruiker-id's kunnen samenvallen)
- geverifieerd in een echte headless Chromium: klasrij + twee sublijsten per
  klas, Schoolbeheerder/Niet ingedeeld correct gevuld, en "+ Groepsleiding"
  koppelt de nieuwe leerkracht daadwerkelijk aan de klas (classIds bevestigd)
2026-07-18 05:31:00 +02:00
Ramon
e088f83d1f fix: schoolkiezer reageert nu echt op Scholen/Klassen binnen "School" (v0.4.10-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 35s
- Scholen-blok toont alleen bij "alle scholen" (selSchool leeg), Klassen-blok
  alleen bij een gekozen school - voorheen toonde Scholen altijd, ongeacht de
  kiezer erboven, wat leek alsof het paneel de kiezer negeerde
- de kiezer defaultet voor de systeemmanager weer op "alle scholen" (was
  omgezet naar de eerste school in een eerdere commit; teruggedraaid op
  uitdrukkelijk verzoek)
- geverifieerd in een echte headless Chromium: bij "alle scholen" tonen
  Scholen+Gebruikers, bij een gekozen school Klassen+Gebruikers, en wisselen
  werkt in beide richtingen
2026-07-18 05:11:38 +02:00
Ramon
56125c6968 feat: Scholen, Klassen en Gebruikers samengevoegd tot één menu-item "School" (v0.4.09-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 40s
- ADMIN_SECTIONS: de drie losse tabbladen zijn samengevoegd tot 1 sectie
  ("school"); zoeken op een school-, klas- of gebruikersnaam werkt nog
  hetzelfde, navigeert nu alleen naar de ene samengevoegde sectie
- nieuwe renderSchoolPanel() zet de drie bestaande, ongewijzigde
  deelpanelen (renderScholenPanel/renderKlassenPanel/renderGebruikersPanel)
  na elkaar, elk met een eigen kop - geen van de drie is herschreven, alleen
  samengesteld, om het risico op regressies te beperken
- rolgedrag blijft exact zoals het was (nu allemaal binnen die ene sectie):
  systeemmanager ziet Scholen+Klassen+Gebruikers en de schoolkiezer,
  schoolbeheerder ziet Klassen+Gebruikers voor de eigen school (geen
  schoolkiezer, geen Scholen-blok), groepsleiding ziet alleen Gebruikers
  (geen Klassen-blok) en daarbinnen alleen de leerling-gerelateerde knoppen
- geverifieerd in een echte headless Chromium voor alle drie rollen: juiste
  secties, juiste knoppen, juiste zichtbaarheid van de schoolkiezer

Backup van de oude driedelige UI staat als git-tag
ui-before-merged-beheer-v0.4.08 (commit e34bda5).
2026-07-18 05:04:43 +02:00
Ramon
e34bda5251 test: expliciete regressietest voor de beperkte rechten van groepsleiding (v0.4.08-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 42s
Geen gedragswijziging - dit legt vast (en bevestigt) wat al klopte: een
groepsleiding kan geen rol wijzigen, geen gebruiker aan een school
koppelen/losmaken, geen klas aanmaken en geen school beheren. Alleen
systeemmanager (en voor klassen: ook schoolbeheerder) mag dit.
2026-07-18 04:49:10 +02:00
Ramon
e2ee4820dc fix: schoolbeheerder aan klas koppelen, systeemmanager-promotie dichten, UI-afstand (v0.4.07-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 36s
- db/017: de class_teachers-trigger uit migratie 006 stond alleen 'teacher'
  toe en blokkeerde daarmee (met een verwarrende "groepsleiding en klas..."
  foutmelding) wat de applicatielaag allang toestond voor schoolbeheerder en
  systeemmanager - de trigger is nooit meegegroeid toen die rollen later ook
  aan een klas gekoppeld mochten worden. Nu ook admin/super toegestaan,
  super school-onafhankelijk zoals de rest van de app dat al behandelt.
- rolwijziging kon een bestaande groepsleiding/schoolbeheerder via een simpel
  dropdown-veld naar systeemmanager promoveren, zonder enige bevestiging -
  in tegenstelling tot de nieuwe systeemmanager-aanmaak (met wachtwoord-
  bevestiging). 'super' is nu geen geldig doel meer voor PATCH .../users/:id
  (ook niet via het extraRoles-mechanisme); het rolwijzigingsveld zelf toont
  zich niet meer voor een bestaande systeemmanager. Alleen de aparte
  aanmaakstap (met bevestiging) kan nog een systeemmanager opleveren.
- meer verticale ruimte tussen rijen in het beheerpaneel (was vrijwel 0),
  zodat je niet per ongeluk de verkeerde rij raakt
- de "+ ..."-toevoegknoppen staan nu rechts uitgelijnd i.p.v. links, zodat ze
  duidelijker als aparte actie ogen i.p.v. als onderdeel van de lijst

Geverifieerd in een echte headless Chromium: rolwijziging toont voor een
groepsleiding alleen nog teacher/admin als opties.
2026-07-18 04:40:39 +02:00
Ramon
111e48b044 fix: toevoegformulier duidelijk anders dan een bestaande-gebruikersrij (v0.4.06-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 34s
Een uitgeklapt "+ ..."-formulier (nieuwe schoolbeheerder/leerkracht/leerling/
school/klas) zag er in het beheerpaneel bijna hetzelfde uit als het
bewerkpaneel van een bestaande gebruiker - beide gewoon een rij velden
zonder duidelijk onderscheid.

- .am-add krijgt nu een eigen kader (accentkleur, stippellijn) i.p.v. de
  neutrale achtergrond van een gebruikersrij
- het formulier toont bovenaan een titel die herhaalt wát je toevoegt (bv.
  "LEERLING"), ook zodra de knoptekst erboven uit beeld is
- de dichtgeklapte "+ ..."-knop zelf krijgt ook de accentkleur, zodat
  collapsed en uitgeklapt dezelfde "dit is toevoegen"-taal spreken
- geverifieerd in een echte headless Chromium: duidelijk visueel onderscheid
  tussen een toevoegformulier en een echte gebruikersrij
2026-07-18 04:22:17 +02:00
Ramon
e5890280cc feat: snel-toevoegen-knop onder elke groep in Gebruikers (v0.4.05-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 34s
Net als bij systeemmanagers (vorige commit) krijgt nu elke groep in de
Gebruikers-tab (schoolbeheerder, groepsleiding, en elke klas incl. "geen
klas") direct een eigen "+ ..."-knop eronder om iemand toe te voegen zonder
naar een ander tabblad te hoeven. Bij een klas staat die klas al vast
ingevuld (presetClassId, bestond al als parameter maar werd nog nergens
gebruikt). Een groep blijft zichtbaar zolang er iets aan toegevoegd kan
worden, ook als hij nu leeg is (bv. een gloednieuwe klas zonder leerlingen) -
anders was er nergens een knop om de eerste aan toe te voegen.

Geverifieerd in een echte headless Chromium (gemockte /api/** responses):
groepen en knoppen verschijnen zoals verwacht, en de klas-select bij een
klasgroep staat al goed vooringesteld.
2026-07-18 04:14:27 +02:00
Ramon
c6638d63f1 feat: systeemmanager aanmaken verplaatst naar Gebruikers + eigen wachtwoord ter bevestiging (v0.4.04-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 36s
- het aanmaken van een systeemmanager stond onder Scholen, los van de rest
  van het gebruikersbeheer - verplaatst naar de Gebruikers-tab (bij "alle
  scholen", naast de bestaande systeemmanagers-groep)
- extra veiligheidsstap: de aanmaker moet het eigen wachtwoord invullen ter
  bevestiging vóórdat een nieuwe systeemmanager wordt aangemaakt - server
  verifieert dit (POST /admin/users), niet alleen de client
- wie dit al mocht (alleen systeemmanagers, via creatableRoles) blijft
  ongewijzigd - de bevestigingsstap is een aanvullende, geen vervangende,
  controle
2026-07-18 04:00:30 +02:00
Ramon
cae700f76d fix: leerling verplaatsen naar een andere klas ververst het paneel niet (v0.4.03-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 33s
De klas-select bij een leerling (uitwisselen naar een andere klas) miste de
reload() die elders bij een klaswijziging wel gebeurt: de server sloeg de
nieuwe klas gewoon op, maar het paneel liet nog de oude toestand zien - leek
dus alsof verplaatsen niet werkte. Test toegevoegd die de serverkant van
deze route bevestigt (die werkte al correct); de fix zelf is puur de
ontbrekende reload() in public/js/admin.js.
2026-07-18 03:51:21 +02:00
Ramon
45f66044f2 fix: alle DELETE-verzoeken faalden op een lege JSON-body (v0.4.02-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 38s
De echte, uiteindelijke oorzaak achter elke "serverfout" die niet door een
route-eigen foutafhandeling kwam (klas verwijderen, en zeer waarschijnlijk
ook de oorspronkelijke gebruiker-verwijderen-bug): de client stuurde bij élk
verzoek altijd "Content-Type: application/json" mee, ook bij een DELETE
zonder body. Fastify's standaard JSON-parser weigert zo'n leeg lichaam met
"Body cannot be empty when content-type is set to 'application/json'" -
vóórdat er ook maar één hook of route-handler heeft kunnen draaien, dus nog
vóór req.user gezet wordt en vóór enige try/catch in een route. Dat verklaart
waarom eerdere per-route foutafhandeling dit nooit kon vangen: de fout zat
vóór elke route.

- public/js/core.js: api() stuurt Content-Type alleen nog mee als er
  werkelijk een JSON-body is
- src/body-parser.js (nieuw): serverside vangnet dat een leeg lichaam bij
  Content-Type: application/json gewoon toestaat i.p.v. te weigeren -
  ongeacht wat een client meestuurt
- test/body-parser.test.js: reproduceert de exacte foutmelding tegen een
  echte Fastify-requestcyclus (de gemockte-pool-tests konden dit principieel
  nooit vangen, vandaar dat dit alle eerdere testrondes overleefde)
2026-07-18 03:44:39 +02:00
Ramon
4517f592f7 chore: versienummering terug naar tweecijferig patchformaat (v0.4.01-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 55s
0.3.99 rolde per ongeluk door naar 0.4.0/0.4.1 i.p.v. het gebruikelijke
tweecijferige patchformaat (0.4.00, 0.4.01, ...) - hersteld.
2026-07-18 03:40:51 +02:00
Ramon
6742e07363 fix: altijd de echte serverfout tonen + klasnamen uniek per school (v0.4.1-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 35s
- de generieke errorhandler gaf alleen detail mee als req.user al gezet was;
  bleek de fout zelf al vóór/tijdens dat moment te zitten (zoals bij klas
  verwijderen), dan bleef het toch de kale "serverfout" - nu altijd de echte
  oorzaak, dit is een intern beheertool zonder publieke bezoekers
- klasnamen konden onbeperkt dubbel aangemaakt worden binnen dezelfde school
  (geen enkele controle) - POST /admin/classes weigert dit nu met 409, en een
  nieuwe unieke index (school_id, lower(name)) is het echte vangnet
- migratie 016 hernoemt eerst bestaande dubbele klasnamen (niets verwijderd)
  vóórdat de unieke index wordt gezet: anders was de migratie zelf op deze
  database mislukt en had de app niet meer opgestart
2026-07-18 03:39:04 +02:00
Ramon
4a31dc9351 fix: klas verwijderen toont echte oorzaak i.p.v. kale serverfout (v0.4.0-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 43s
- DELETE /admin/classes/:id had geen try/catch: elke mislukking (bv. een FK
  die nog niet cascade/set-null is op deze database) viel terug op de
  generieke handler en toonde alleen "serverfout" zonder aanknopingspunt
- zelfde aanpak als eerder bij het verwijderen van een gebruiker: de echte
  Postgres-foutmelding komt nu terug i.p.v. een kale "serverfout"
- test toegevoegd voor zowel het gewone pad als de foutmelding
2026-07-18 03:28:31 +02:00
Ramon
be8ecc5378 fix: gebruikerslijst per school laadde nooit (SELECT DISTINCT/ORDER BY) (v0.3.99-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 1m13s
- linkedParents() gebruikte "SELECT DISTINCT p.* ... ORDER BY lower(p.username)":
  Postgres weigert dit omdat de ORDER BY-expressie niet letterlijk in de
  select-lijst staat. Deze query loopt bij élke school-gescopede
  gebruikerslijst (elke schoolbeheerder, en elke systeemmanager die een
  specifieke school kiest i.p.v. "alle scholen") - dus die lijst laadde
  nooit, klassen werden om dezelfde reden niet (opnieuw) opgehaald, en
  "alle scholen" was de enige werkende weergave
- fix: lower(p.username) expliciet als kolom (sort_key) in de select-lijst,
  ORDER BY daarop i.p.v. op de losse expressie
- regressietest die de exacte SQL-vorm vastlegt (een gemockte pool voert geen
  echte SQL uit en had deze Postgres-grammaticafout niet kunnen vangen)
2026-07-18 03:19:36 +02:00
Ramon
205ba74eff fix: beheerpaneel toont laadfout i.p.v. stilletjes leeg te blijven (v0.3.98-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 34s
- reload() in het beheerpaneel (scholen/klassen/gebruikers) ving elke fout
  stilletjes op en zette alles terug naar lege lijsten, zonder enige melding -
  dat gaf een verwarrend leeg paneel bij een specifieke school terwijl "alle
  scholen" wel werkte, zonder enig aanknopingspunt waarom
- de echte oorzaak verschijnt nu bovenin het paneel (amLoadError), zodat een
  volgende mislukking direct te diagnosticeren is i.p.v. te moeten gokken
2026-07-18 03:08:55 +02:00
Ramon
4ffb69ca61 fix: gebruiker verwijderen toont echte oorzaak i.p.v. kale serverfout (v0.3.97-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 1m19s
- DELETE /admin/users/🆔 hele handler (niet alleen deleteUserFully) in
  één try/catch, zodat ook een fout vóór het verwijderen zelf (bv. de
  opzoekquery) de echte reden teruggeeft i.p.v. terug te vallen op de
  generieke 500 "serverfout"
- generieke errorhandler logt voortaan altijd het volledige fouteobject en
  geeft ingelogde gebruikers de werkelijke foutmelding mee i.p.v. alleen
  "serverfout"
- test toegevoegd die dit nieuwe pad dekt
2026-07-17 22:27:20 +02:00
Ramon
e48a3a4e46 fix: gebruiker verwijderen werkt gegarandeerd - ruimt afhankelijke rijen zelf op (v0.3.96-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 51s
- De "serverfout" bij verwijderen komt van een foreign key die op de live-database geen ON DELETE CASCADE heeft, waardoor DELETE FROM users faalt zodra er nog een gekoppelde rij bestaat
- Nieuw: de verwijderroute haalt in één transactie eerst alle afhankelijke rijen weg (sessies, rollen, klaskoppelingen, toewijzingen, voortgang, ouderkoppelingen, aanmeldingen, reservekopieën, gedeelde items, afbeeldingen, borden/mappen) en verwijdert daarna de gebruiker - dit werkt ongeacht de exacte FK-instelling en heeft migratie 015 niet nodig
- Mocht verwijderen tóch falen, dan komt nu de echte databasereden terug (constraint-detail) i.p.v. een kale "serverfout", zodat de oorzaak zichtbaar is
- 3 servertests: volledige opruiming in transactievolgorde (afhankelijke rijen vóór users), echte foutreden bij een gesimuleerde fout; 97 tests groen

LET OP: dit werkt pas na deploy van deze versie; v0.3.94 (huidige live) bevat de fix nog niet.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149FgUQvuwxKKEdvQGmNngF
2026-07-17 21:50:48 +02:00
Ramon
e3036580ce fix: gebruiker verwijderen werkt weer (herstel foreign-key cascade) (v0.3.95-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 32s
- Verwijderen gaf op de live-database een 500 "serverfout". Oorzaak: op databases die zijn ontstaan vóór alle foreign keys ON DELETE CASCADE waren, houdt een tabel de oude constraint (CREATE TABLE IF NOT EXISTS werkt een bestaande constraint nooit bij), waardoor DELETE FROM users een foreign-key-fout geeft
- Migratie 015: zoekt elke FK naar users(id) die niet cascade en niet set-null is en zet die alsnog op ON DELETE CASCADE (bewuste SET NULL-constraints blijven ongemoeid). Draait bij de volgende deploy en is idempotent
- Verwijderroute vangt een resterende FK-fout (23503) op als een begrijpelijke 409 i.p.v. een kale serverfout
- Geverifieerd: alle INSERT INTO users-paden vangen al 23505 op (gebruikersnaam uniek per school); dezelfde naam in verschillende scholen is bewust toegestaan (inloggen kiest de school) en staat sinds 0.3.94 per school gegroepeerd
- 3 nieuwe servertests (FK-fout -> 409, normale verwijdering, migratie-inhoud); 97 tests groen

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149FgUQvuwxKKEdvQGmNngF
2026-07-17 21:39:29 +02:00
Ramon
30818dc5f2 fix: gebruikers gegroepeerd per school in alle-scholen-weergave + zichtbare verwijderfouten (v0.3.94-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 35s
- In de "alle scholen"-weergave stonden gebruikers op rol gegroepeerd, waardoor je niet zag bij welke school ze horen (Ramon/Rubi/leerlingb1b leken los te staan). Ze worden nu per school gegroepeerd (inklapbaar), met systeemmanagers, ouders en losse accounts apart eronder - je ziet meteen wie bij De Ziep hoort
- Bij één gekozen school blijft de indeling op rol/klas; die rolgroepen zijn nu ook inklapbaar
- Verwijderfouten (en andere actie-fouten in het detailpaneel) verschijnen nu in het detailpaneel zelf i.p.v. alleen bovenaan (buiten beeld op mobiel). Als een verwijdering serverzijdig faalt, zie je nu de reden - het lijkt niet langer of "niets gebeurt"
- Verwijderen zelf is end-to-end geverifieerd (DELETE verstuurd, gebruiker verdwijnt); een gesimuleerde 409 toont de melding in het paneel en laat de gebruiker staan
- 7 nieuwe Playwright-checks (school-groepering, zichtbare fout, geslaagde verwijdering) + volledige regressie van 8 suites; 94 servertests groen

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149FgUQvuwxKKEdvQGmNngF
2026-07-17 21:21:05 +02:00
Ramon
c86abcf794 fix: onzichtbare knopteksten, lege klassenlijst en correcte klas-schoolregels (v0.3.93-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 32s
- Onzichtbare knoppen opgelost: .tbtn houdt standaard witte tekst (wit-op-blauw), maar in het beheer staat hij op een lichte achtergrond -> tekst was wit-op-wit. Nu expliciet donkere tekst; de primaire accentknop houdt bewust witte tekst
- Systeemmanager kreeg standaard "alle scholen" waardoor klassen leeg leken en niet toe te voegen waren; er wordt nu meteen een concrete school gekozen (klassen/gebruikers direct gevuld). Contextbalk laat wisselen; "alle scholen" blijft een bewuste keuze
- Lege school toont nu een duidelijke uitleg dat bestaande klassen bij een andere school kunnen horen, met verwijzing naar de schoolkeuze
- Correcte gegevensregels: classes.school_id is NOT NULL met ON DELETE CASCADE, dus een klas kan niet "los" bestaan (die eerdere aanname is teruggedraaid). Een klas is nu te VERPLAATSEN naar een andere school (PATCH weigert null/ongeldig); een verwijderde school neemt zijn klassen mee (cascade) - dat verklaart verdwenen klassen
- Bij een leerling naar een andere school koppelen blijft de klas behouden als die al bij de doelschool hoort
- Verificatie uitgebreid met een echte kleurcontrast-scan (vangt wit-op-wit) over alle secties + de default-school-flow; alle 94 servertests en 8 Playwright-suites groen

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149FgUQvuwxKKEdvQGmNngF
2026-07-17 20:22:36 +02:00
Ramon
aee1c59fbd fix: leerlingen zichtbaar bij gekozen school + uniforme controls in het beheer (v0.3.92-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 35s
- Leerlingen stonden onder standaard-ingeklapte klasgroepen, dus met een gekozen school leek de lijst leeg terwijl de detailweergave de juiste school toonde. Klasgroepen staan nu standaard open zodra een school is gekozen (de schoolkeuze wás al het filter); bewust dichtklappen wordt onthouden
- Losse klassen (school verwijderd) waren nergens zichtbaar: de systeemmanager ziet ze nu zonder gekozen school met een uitleg, en kan ze via een School-veld terugkoppelen; nieuwe PATCH /admin/classes/:id + GET ?school=none (super) met servertests
- Bij het aan een school koppelen van een leerling blijft de klasindeling behouden als die klas al bij de doelschool hoort (eerst klas terugkoppelen, dan de leerlingen)
- UI-consistentie: één uniforme control-hoogte (32px) voor álle knoppen, selects en invoervelden in Instellingen - einde aan de grote maatverschillen; T() valt terug op NL en dan de sleutelnaam zodat een knop nooit zonder tekst kan staan
- Status in de gebruikerstabel als compacte glyph (● in gebruik / ○ wacht) met uitleg bij aanwijzen i.p.v. een afgekapte "nog niet ing…"-chip
- Geverifieerd in headless Chromium: nieuwe suite (21 checks: zichtbaarheid met schoolfilter, losse klassen, geen lege knoppen, uniforme hoogte over 8 secties) + volledige regressie van 5 bestaande suites

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149FgUQvuwxKKEdvQGmNngF
2026-07-17 19:46:09 +02:00
Ramon
15618348dc style: alle menu's nagelopen - alles verborgen tot erom gevraagd wordt (v0.3.91-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 33s
- Voortgang: tijdlijn toont 30 regels per keer met een "meer tonen (n)"-knop i.p.v. 200 regels ineens
- Inhoud: de vier blokken (welkomstwoord, melding, widget-uitleg, systeembrede inhoud) zijn inklapbare groepskaarten - alleen het welkomstwoord staat standaard open; open-status overleeft her-renders
- Account: de drie wachtwoordvelden verschijnen pas na een klik op de kop "Wachtwoord"
- Daarmee volgt elke sectie hetzelfde principe: compacte koppen met samenvatting, detail pas op verzoek, verwante items in één kader
- Geverifieerd in headless Chromium (9 nieuwe checks) + volledige regressie van de vier bestaande suites (56 checks)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149FgUQvuwxKKEdvQGmNngF
2026-07-17 14:35:24 +02:00
Ramon
b4eee9f78f feat: gebruikers aan een school koppelen en losmaken (v0.3.90-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 52s
- PATCH /admin/users/:id ondersteunt schoolId (alleen systeemmanager, rollen teacher/admin/pupil): null = losmaken, anders koppelen met bestaanscheck (404); bij wissel worden klas, klaskoppelingen en (voor leerlingen) oude toewijzingen opgeruimd; naamconflicten in doelschool of school-loze naamruimte geven een nette 409
- Detailpaneel toont voor de systeemmanager een School-veld bij deze rollen - losse accounts (ooit aan een school gekoppeld) zijn hiermee terug te zetten en bewust los te maken; werkt ook in de beheerder-subrijen op het Scholen-tabblad
- Gebruikers-tab (alle scholen): losse accounts staan in een eigen inklapbare groep "Zonder school (n)" i.p.v. onopvallend tussen de rolgroepen; de oudergroep is nu ook inklapbaar
- 3 nieuwe servertests (koppelen incl. opruiming, losmaken, 404, geen rechten/no-op voor admin en parent, 409 bij naamconflict) + 10 Playwright-checks voor de volledige flow

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149FgUQvuwxKKEdvQGmNngF
2026-07-17 14:30:41 +02:00
Ramon
08618ba0b3 feat: Scholen, Klassen en Toewijzingen als groepskaarten (v0.3.89-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 31s
- Scholen: één gezamenlijk kader per school - getinte kop met grijs schoolicoon, naam en de beheerder-teller als uitklaptoggle; beheerders standaard verborgen en als compacte subrijen (36px) met status-glyph (● actief / ○ nog niet geactiveerd, uitleg via title); hernoemen/verwijderen klapt uit binnen hetzelfde kader - geen verwarring meer tussen scholen en beheerders
- Klassen: kaart per klas met leerlingtal in de kop; de reset-/verwijderacties verborgen tot Bewerken
- Toewijzingen: kaart per klas met de huidige stand compact in de kop; bord-/widget-/moduskeuze klapt uit via Bewerken
- Het status-glyph en de kaartkop-wrap zijn onderdeel van het gedeelde groepskaart-component; bewust klein grijs schoolicoon terug (functioneel onderscheid, emoji-scan-uitzondering)
- Geverifieerd in headless Chromium (14 checks) + screenshots 390px/desktop

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149FgUQvuwxKKEdvQGmNngF
2026-07-17 14:27:19 +02:00
Ramon
c3492ab2ca feat: Opslag per school met groepskaart-component (v0.3.88-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 55s
- Nieuw herbruikbaar groepskaart-component (amGroupCard): één kader om items die bij elkaar horen - koprij met grijs icoon, titel, samenvatting-als-uitklaptoggle en Bewerken; compacte subrijen; open-status overleeft re-renders (injecteerbare Set zodat ook andere modules hem gebruiken)
- Opslag-tab volledig herbouwd: eerst één school kiezen (of "Systeem (zonder school)" voor systeemmanagers/ouders/losse accounts) i.p.v. alle scholen én alle gebruikers plat met altijd-open editors
- Na keuze één kaart: schoolnaam + quota-samenvatting in de kop (schoolquota bewerken klapt uit), daaronder alleen de gebruikers van díe school als compacte regels; bewerkvelden pas na "Bewerken" per rij; zoeken binnen de school
- "Standaard"-optie benoemt nu de echte rolstandaard ("Standaard (200 MB)") via defaultBytes
- Mobiel: beheer-rijen stapelen niet meer verticaal (kaartkop en subrijen wrappen netjes; subrij ± twee compacte regels i.p.v. >100px)
- Geverifieerd in headless Chromium (13 checks, o.a. dat schoolkeuze en open bewerkrij een her-render overleven - module-state) + screenshots 390px/desktop

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149FgUQvuwxKKEdvQGmNngF
2026-07-17 14:20:41 +02:00
Ramon
ebe622588f style: tekstknoppen en consistente secties in het beheer - emoji-sweep afgerond (v0.3.87-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 45s
- Alle resterende emoji uit het beheer: kopieerknoppen zijn tekstknoppen ("kopieer"), wachtwoord-genereerknop heet "genereer", "alles kopiëren" zonder klembord-icoon, schoolrijen zonder 🏫, contextbalk-label is het woord "School", bevestiging is "zeker?" (de rode armed-stijl is het signaal), kopieer-feedback een net vinkje
- Scholen-tabblad: "Bewerken"-tekstknoppen i.p.v. het ✏-potlood; zoek-placeholders zonder vergrootglas-emoji
- CMS-widgetkeuze zonder emoji-prefix in de opties
- Playwright-emoji-scan over alle vijf beheersecties (knoppen/labels/groepen schoon, ▸▾✕✓+ toegestaan) + volledige master-detail-regressie (19 checks) groen

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149FgUQvuwxKKEdvQGmNngF
2026-07-17 07:08:17 +02:00
Ramon
af86ff5c47 feat: gebruikersbeheer als master-detail met vast bewerkpaneel (v0.3.86-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 34s
- Gebruikers staan in een echte tabel (initiaal-avatar + naam | functie | klas | status) met kolomkoppen en uitgelijnde kolommen; klikken op een rij selecteert (accent-markering) zonder her-render, dus het zoekveld houdt focus
- Rechts een vast detailpaneel: bewerken (functie, klaskoppeling, klas, wachtwoord, acties), aanmeldverzoeken afhandelen én nieuwe gebruikers aanmaken gebeuren allemaal dáár - één plek, één patroon
- Eenmalige wachtwoorden/codes verschijnen als badge in het paneel; na aanmaken is de nieuwe gebruiker direct geselecteerd; selectie overleeft herladen en wordt gevalideerd tegen de data
- Aanmeldverzoeken zijn gewone tabelrijen met een "nieuw"-chip; de losse toevoeg-formulieren per klas zijn vervangen door één "Nieuwe gebruiker"-knop in de werkbalk (met rolkeuze)
- Smal scherm: het detailpaneel wordt een overlay met sluitknop (onder de tabel stapelen is onbruikbaar bij grote scholen)
- Menu-items herzien: de sectie heet "Scholen" (geen "Systeem > Systeem"-verdubbeling meer) en de Systeem-groep is geordend als Scholen / Inhoud / Opslag
- Eerste emoji-sweep in de omgebouwde delen (actieknoppen zijn tekstknoppen); zoekfilter en inklapbare klasgroepen werken ongewijzigd
- Geverifieerd in headless Chromium (19 checks, incl. focusbehoud, overlay-gedrag en selectie-na-reload)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149FgUQvuwxKKEdvQGmNngF
2026-07-17 07:06:18 +02:00
Ramon
8b4bd47407 style: zakelijk ontwerpsysteem voor Instellingen (v0.3.85-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 33s
- Volledig gescoped op #settingsModal zodat het bord speels blijft: systeemfont i.p.v. Quicksand, controls 32px (40px op aanraakschermen), vlakke 1px-randen i.p.v. schaduwen en pastel-pills
- Rijen worden tabelregels met scheidingslijnen en hover; groepskoppen zijn subtiele sticky sectierijen; navigatie-actief is neutraal grijs met accent-inzetlijn; iconen gedempt in grijstinten
- Knoppen één systeem: subtiel omrand, danger als rode tekst die pas gevuld rood wordt na wapenen; chips/resultaten/segmentknoppen omrand vlak
- Hoog contrast expliciet teruggebracht binnen de nieuwe scope; sectiekop-icoon in eigen span zodat CSS hem kan dempen

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149FgUQvuwxKKEdvQGmNngF
2026-07-16 20:42:53 +02:00
Ramon
526e4e5d52 feat: CMS-sectie Inhoud voor de systeemmanager (v0.3.84-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 56s
- Nieuwe sectie "Inhoud" in Instellingen (groep Systeem, alleen systeemmanager, doorzoekbaar via het sectieregister)
- Welkomstwoord (NL/EN) verschijnt op het inlogscherm, direct aanpasbaar zonder release
- Melding voor alle gebruikers: aan/uit, niveau informatie/belangrijk, per taal; verschijnt als wegklikbare banner onder de menubalk en elke wijziging krijgt een nieuw id zodat een eerder weggeklikte melding opnieuw verschijnt
- Widget-uitleg: per widget een eigen beschrijving die de standaardtekst in de widgetbibliotheek vervangt (leeg = standaard, placeholder toont de standaardtekst)
- Snelkoppelingen naar de bestaande kanalen voor systeembrede inhoud: gedeelde bibliotheek (borden & ankerdiagrammen, map 🌐 Systeem) en de afbeeldingencatalogus
- settings.js kreeg een generiek haakje (showSettingsDom) zodat modules met een eigen paneel zich in het sectieregister kunnen voegen
- Geverifieerd in headless Chromium (15 checks): banner + dismiss + nieuw-id-gedrag, welkomstwoord, bewerken/opslaan, galerij-override, sectie onzichtbaar voor andere rollen

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149FgUQvuwxKKEdvQGmNngF
2026-07-16 19:33:49 +02:00
Ramon
aa4c5faaf9 feat: server-kant CMS voor de systeemmanager (v0.3.83-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 31s
- Migratie 014: site_content (sleutel/waarde, JSONB) voor site-inhoud die zonder release aanpasbaar moet zijn
- GET /content (publiek): welkomstwoord, update-melding en widget-uitleg in één antwoord - het inlogscherm toont het welkomstwoord al vóór het inloggen
- PUT /admin/content/:key (alleen systeemmanager, nieuwe permissie content.manage): upsert per toegestane sleutel (welcome/announcement/widgetInfo) met maat-limieten
- 4 servertests: publiek lezen, upsert door super, 403/401 voor anderen, whitelist/vorm/omvang-validatie

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149FgUQvuwxKKEdvQGmNngF
2026-07-16 19:29:08 +02:00
Ramon
2fff8a3aa5 perf: gzip-vangnet in nginx voor geproxyde responses (v0.3.82-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 1m4s
- gzip on + gzip_proxied any (zonder die laatste comprimeert nginx geproxyde responses helemaal niet) + gzip_vary + min_length 1024 voor css/js/json/svg/tekst
- Geen dubbele compressie: responses die al Content-Encoding dragen (brotli/gzip uit de app) laat nginx ongemoeid; dit vangt alleen wat de app mist
- Cache-beleid blijft bewust op één plek (de app), zodat lokaal en productie identiek gedragen
- Configtest erbij in security-config-stijl

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149FgUQvuwxKKEdvQGmNngF
2026-07-16 19:02:53 +02:00
Ramon
456d664718 perf: compressie, cache-headers, cache-busting en parallel ladende scripts (v0.3.81-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 1m14s
- @fastify/compress (brotli quality 4 + gzip, global): alle statische assets én API-JSON (zoals /me/data) gaan gecomprimeerd over de lijn - eerste lading van ~715 KB naar grofweg een derde
- Nieuw src/frontend.js: index.html wordt bij boot één keer gelezen, ?v=__V__ wordt vervangen door de app-versie en de pagina wordt uit het geheugen geserveerd met no-cache
- Cache-beleid per prefix: js/css een jaar immutable (veilig dankzij de geversioneerde URL's), fonts 7 dagen, afbeeldingen 1 dag met zwakke etag als 304-vangnet - herhaalbezoek kost vrijwel geen bytes meer
- Alle 31 scripts staan nu met defer in de head: parallel downloaden, uitvoeren in dezelfde dwingende volgorde (core → widgets → board → app); font-preload bewust ongeversioneerd (moet byte-gelijk blijven aan de url() in teach.css)
- Compress geregistreerd vóór de api/frontend-registraties (onSend-hook geldt alleen voor latere routes) - geborgd met een teksttest
- 6 nieuwe tests (test/frontend.test.js): versie-injectie, cache-headers per prefix, gzip+brotli round-trip, 304 op etag, defer/?v= op elk script

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149FgUQvuwxKKEdvQGmNngF
2026-07-16 19:01:25 +02:00
Ramon
cb97dc2bb1 feat: breid taalwidgets en plaatjesbibliotheek uit (v0.3.80-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 31s
2026-07-16 16:27:38 +02:00
Ramon
4356658c96 fix: versietest pint geen vast nummer meer (v0.3.79-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 43s
- De CI faalde omdat een test het versienummer hardcodeerde (0.3.77-beta) en dus bij elke reguliere versiebump breekt
- De test bewaakt nu het echte beleid: de dev-branch voert altijd een -beta-versie en de VERSION-file loopt gelijk met de const in core.js (die controle stond er al en blijft)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149FgUQvuwxKKEdvQGmNngF
2026-07-16 15:01:59 +02:00
Ramon
2a0de85152 fix: vastgezette lat kleeft altijd en vinger-jitter breekt de snap niet meer (v0.3.78-beta)
Some checks failed
dev - build & deploy naar test / build-and-deploy (push) Failing after 32s
- Op een aanraakscherm wiebelt een vinger in de eerste millimeters: de richtingstoets wees de snap daardoor af en de haal bleef de vinger volgen
- Vastgezet gereedschap (🔒) kleeft nu onvoorwaardelijk binnen 28px van de rand - geen richtingstoets; het slot betekent "hier teken ik langs"
- Losse lat: richting wordt over een langere basis gemeten (10px i.p.v. 7) met een ruimere hoek (40° i.p.v. 30°), zodat vinger-jitter de evenwijdige intentie niet meer maskeert
- Inktlaag kreeg touch-action:none zodat de browser vingerhalen nooit als scroll-gebaar afvangt
- Geverifieerd met échte touch-events (CDP) inclusief nagebootste vinger-jitter: 7 nieuwe checks (vastgezet kleeft mét jitter, op de lat tekenen zonder verschuiven, los evenwijdig kleeft, wegdraaiend blijft vrij) + de vier bestaande muis-suites (42 checks) blijven groen

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149FgUQvuwxKKEdvQGmNngF
2026-07-16 14:45:51 +02:00
Ramon
7a5d7c57ff feat: maak widgets speelser en kindvriendelijker (v0.3.77-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 41s
2026-07-16 14:15:28 +02:00
Ramon
85268050fd feat: slot op liniaal/geodriehoek en richtingsbewust langs de lat tekenen (v0.3.76-beta)
Some checks failed
dev - build & deploy naar test / build-and-deploy (push) Failing after 34s
- Slot-knop (🔓/🔒) op liniaal én geodriehoek: vastgezet gereedschap kan niet meer verschuiven of draaien (draaiknop verdwijnt), er kan alleen nog langs getekend worden; tweede klik ontgrendelt
- Naast de lat beslist nu de richting i.p.v. één vaste afstand: binnen 22px van een rand wacht de haal de eerste ~7px beweging af - loopt die grofweg evenwijdig aan de rand (≤30°), dan kleeft hij, anders blijft hij vrij; een tik zet gewoon een stip
- Daarmee is langs de lat tekenen betrouwbaar (ook met dikke digibord-vingers) zónder dat de lat vrije halen in de buurt grijpt
- Op de lat zelf blijft de intentie ondubbelzinnig: direct kleven binnen 24px van de rand
- Geverifieerd in headless Chromium: 12 nieuwe checks (richtingsregel, stip-tik, slot aan/uit, vastgezet = onverplaatsbaar maar betekenbaar) + de drie bestaande suites (35 checks) blijven groen

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149FgUQvuwxKKEdvQGmNngF
2026-07-16 14:04:15 +02:00
Ramon
5d12d2f8ec feat: kleinere snapzone, dunnere pennen, potlood met karakter en kalligrafische vulpen (v0.3.75-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 40s
- Snapzone naast de liniaal/geodriehoek verkleind van 24 naar 10px: vrije halen in de buurt worden niet meer "gegrepen"; op de lat zelf blijft de ruime 24px-zone gelden
- Diktekiezer uitgebreid met dun (1 en 2, naast 3/5/8)
- ✏️ heet nu Potlood en tekent zo: een zachte, gelijkmatige lijn (~85% dekking) via de overlay-laag, dus égaal ook waar de haal zichzelf kruist
- Vulpen schrijft nu echt kalligrafisch met een 45°-penpunt: dik in de neerhaal, dun in de ophaal (gemeten 11px vs 1,5px bij dikte 5); stylusdruk versterkt het effect
- Geverifieerd in headless Chromium (9 checks, pixelmetingen van dekking, snapzones en lijndiktes)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149FgUQvuwxKKEdvQGmNngF
2026-07-16 13:55:36 +02:00
Ramon
6e7f24eb40 fix: pen op de lat tekent nu langs de rand i.p.v. de lat te verslepen (v0.3.74-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 27s
- In de praktijk zet je de pen óp de liniaal-/geodriehoekrand, zoals bij een echte lat - maar dat versleepte het gereedschap, waardoor "langs de lat tekenen" niets leek te doen
- Landt de pen (pen/vulpen/stift, penmodus actief) binnen 24px van een tekenrand - ook óp de lat zelf - dan start een vastgeklikte haal en blijft het gereedschap liggen; de events lopen via pointer capture gewoon door naar de inktlaag
- Verder van de rand blijft het gereedschap gewoon te verslepen, en de draaiknop houdt voorrang
- Startzone naast de lat verruimd van 16 naar 24px (digibord-vingers)
- Geverifieerd in headless Chromium: 7 nieuwe checks (tekenen op de randzone zonder de lat te verschuiven, verslepen vanuit het midden, draaien in penmodus, idem geodriehoek) + de bestaande 14 snap-checks blijven groen

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149FgUQvuwxKKEdvQGmNngF
2026-07-16 13:46:18 +02:00
Ramon
abafcafe3a feat: breid natuurwidgets uit
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 30s
2026-07-16 13:43:46 +02:00
Ramon
55520ba367 feat: tekenen langs liniaal en geodriehoek + geodriehoek met twee niveaus (v0.3.72-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 27s
- Langs de lat tekenen: begint een haal binnen 16px van een rand van de liniaal of geodriehoek, dan kleeft de hele haal aan die rand - kaarsrecht, ook gedraaid (randen draaien mee); bewust wegtrekken (>60px) laat weer los; gum en vrije halen blijven onaangetast
- Gereedschappen liggen nu boven de inktlaag, zoals een echte lat op het bord: ook in penmodus te verplaatsen, draaien en instellen
- Geodriehoek herbouwd met twee niveaus: basis (grote hoofdhoeken 30/45/60/…, hele centimeters - voor jonge leerlingen) en volledig (graden per 2° met dubbele schaal links- én rechtsom, millimeters, evenwijdige hulplijnen per cm - voor meetkunde in de bovenbouw en daarna)
- Geodriehoek: cm-schaal vanaf 0 in het midden zoals echt, maat in hele cm op de knop (6/8/12 cm), 90°-markering, begrensd op de bordbreedte; alleen de driehoek zelf vangt aanrakingen zodat er vlak naast de schuine randen getekend kan worden
- Geverifieerd in headless Chromium (14 checks, o.a. pixelmetingen van rechtgetrokken halen op rechte én 30°-gedraaide randen)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149FgUQvuwxKKEdvQGmNngF
2026-07-16 13:38:14 +02:00
Ramon
93c287979c feat: breid wereldorientatie-oefeningen uit (v0.3.71-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 30s
2026-07-16 11:44:30 +02:00
Ramon
100dc62087 feat: verbeter wereldorientatie met echte beelden (v0.3.70-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 27s
2026-07-16 10:31:50 +02:00
Ramon
88d1f9cb86 feat: voeg wereldorientatiewidgets toe (v0.3.69-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 26s
2026-07-16 09:42:45 +02:00
Ramon
22233c5f92 fix: laat de minutenwijzer de urenwijzer verzetten (v0.3.68-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 24s
2026-07-16 09:14:15 +02:00
Ramon
66fbac7221 fix: laat de oefenklok door alle 24 uren draaien (v0.3.67-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 27s
2026-07-16 08:53:09 +02:00
Ramon
ecf60304a9 fix: centreer widgetopdrachten en herstel 24-uursinvoer (v0.3.66-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 39s
2026-07-16 08:41:26 +02:00
Ramon
652e039a39 feat: vloeiende pen en stift, egale markeerstift en logischere liniaal (v0.3.65-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 31s
- Pen, vulpen en stift tekenen nu met kwadratische curves door de middelpunten van de pointer-stappen: geen hoekige knikken meer bij snelle halen (het "blikkerige" beeld)
- Markeerstift tekent tijdens de haal dekkend op een eigen doorschijnende laag en wordt bij het loslaten in één keer met vaste transparantie op de inktlaag gezet: overlappingen binnen één haal geven geen donkere vlekken meer, een tweede haal eroverheen wordt wél donkerder (zoals een echte stift)
- devicePixelRatio wordt bij elke resize vers gelezen (scherp blijven na verplaatsen naar een ander scherm of zoomen)
- Liniaal: logische lengtes in hele centimeters (5/10/15/20 cm, knop toont de actuele maat), schaal telt vanaf 0 met een kantlijn zoals een echte liniaal, lengte begrensd op de bordbreedte, en de lengte staat op de liniaal zelf
- Liniaal en geodriehoek: draaien toont live de hoek in graden en klikt vast op veelvouden van 45° (badge kleurt groen); knoppen hebben leesbare titels (Lengte / Hoog contrast)
- Geverifieerd in headless Chromium (12 checks, o.a. pixelmeting van de markeerstift-kruising en exacte 45°-snap)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149FgUQvuwxKKEdvQGmNngF
2026-07-16 08:37:23 +02:00
Ramon
3e6ab09e1f fix: ankerkiezer opent alleen op een bewuste tik en tekenbalk krimpt weer geminimaliseerd (v0.3.64-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 31s
- Oorzaak van het "vanzelf" openende uploadvenster gevonden: elk leeg plaatjesvak in een ankerdiagram had eigen pointer/click-handlers die het pannen blokkeerden en de plaatjeskiezer (met uploadtab) openden bij elke veeg die erop begon - op een telefoon was dat vrijwel elke aanraking, dus ook direct na het verversen
- Lege plaatjesvakken lopen nu via dezelfde tik/sleep-logica als de cellen (6px-drempel): vegen pant het diagram, alleen een stilstaande tik opent de kiezer; woord bewerken blijft ongewijzigd
- Tekenbalk op telefoons weer gecentreerd op inhoudsbreedte i.p.v. vastgepind aan beide randen: geminimaliseerd is hij weer smal (121px i.p.v. volle breedte), nog steeds in de eigen laag boven +/borden
- Hardening: een onbekende achtergrond-waarde in opgeslagen borddata crashte de hydrate en logde de gebruiker stilletjes uit bij verversen - valt nu terug op de standaardachtergrond
- Geverifieerd in iPhone-emulatie (8 checks): geen venster na verversen, veeg pant, tik kiest, tekenbalk smal en vrij van +

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149FgUQvuwxKKEdvQGmNngF
2026-07-16 08:09:33 +02:00
Ramon
99e807595a feat: alle widgets mobielvriendelijk maken (v0.3.64-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 51s
2026-07-16 08:02:20 +02:00
Ramon
7bd35685fe feat: sluitknop op geminimaliseerde widgets in de dock (v0.3.63-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 45s
- Elke dock-pil (geminimaliseerde widget) heeft nu een eigen ✕ om de widget direct te sluiten, zonder hem eerst terug op het bord te zetten
- Klik op de pil zelf blijft de widget herstellen; de ✕ deelt hetzelfde sluitpad als de ✕ in de widgetkop
- Groter tikvlak voor de ✕ op aanraakschermen; titels wisselen mee met de taal
- Geverifieerd in headless Chromium (8 checks, incl. serialisatie na sluiten/herstellen)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149FgUQvuwxKKEdvQGmNngF
2026-07-16 07:50:41 +02:00
Ramon
87b22efc56 fix: tekstzoom terug op telefoon en tekenbalk botst niet meer met +/borden (v0.3.62-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 28s
- A−/A+ (tekstzoom, toegankelijkheid) staan weer bovenaan in de telefoon-balk; alleen het percentage, de catalogusknop en volledig scherm blijven daar verborgen (opslaan-knop zonder minimumbreedte zodat alles past, ook op 320px)
- Echte oorzaak van het steeds opende afbeeldingen-/bordenscherm gevonden: op telefoons lagen de +-knop en de paarse bordenknop bovenop de tekenbalk - wissen/sluiten aantikken opende dus het +-menu of het bordenpaneel
- De tekenbalk ligt op telefoons nu in een eigen laag bóven de knoppenrij (groeit omhoog, dus veilig bij elke schermbreedte); + en borden houden de onderrand
- Geverifieerd op 390px én 320px (8 checks): geen overlap, sluit-/wisknop raakt echt de tekenbalk, balk past volledig, A−/A+ zichtbaar

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149FgUQvuwxKKEdvQGmNngF
2026-07-16 07:44:38 +02:00
Ramon
8b76cf3b4b fix: menubalk past op telefoon - afbeeldingenscherm opent niet meer per ongeluk (v0.3.61-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 26s
- Op telefoons (≤600px) liep de menubalk 143px over: 💾 Opslaan en ⚙ Instellingen vielen buiten beeld en 🖼 (afbeeldingscatalogus) zat precies onder de duim, waardoor het schermvullende afbeeldingen/upload-scherm steeds per ongeluk opende
- Telefoon-balk toont nu alleen de essentie (🔊, 📁, 💾, ⚙); zoom en de catalogusknop verdwijnen daar - afbeeldingen blijven bereikbaar via het +-menu
- Afbeeldingscatalogus: titelbalk met sluitknop blijft vastgeplakt in beeld tijdens scrollen, en op mobiel 100dvh i.p.v. 100vh zodat er niets achter de browserbalk wegvalt
- Geverifieerd in iPhone-emulatie (5 checks): balk past volledig, opslaan/instellingen bereikbaar, sluitknop blijft zichtbaar, catalogus via +-menu

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149FgUQvuwxKKEdvQGmNngF
2026-07-16 07:25:58 +02:00
Ramon
bdb5ef9875 feat: instellingen volledig herbouwd - sectieregister, rolweergaven en zoeken (v0.3.60-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 34s
- Nieuwe architectuur: één sectieregister (settings.js) als enige bron van waarheid; secties melden zich aan met rol-zichtbaarheid, activate() en zoekgegevens - de schil kent het beheer niet van binnen
- Nieuwe indeling: navigatie links (gegroepeerd Persoonlijk / School / Systeem), inhoud rechts met sectiekop + toelichting; zakelijk en rustig, responsief op smalle schermen
- Alles doorzoekbaar: één zoekbalk vindt secties, instellingen (trefwoorden, o.a. wachtwoord/thema/taal) én data - gebruikers, klassen en scholen op naam; klik navigeert en filtert de gebruikerslijst direct op de treffer
- Per rol alleen de essentie: gast alleen Weergave; leerling en ouder Account + Weergave; groepsleiding + Gebruikers/Toewijzingen/Voortgang; schoolbeheerder ook Klassen; systeemmanager ook Systeem en Opslag
- Thuiskinderen (leerling zonder school) krijgen nu zoals ontworpen het volledige whiteboard met eigen opslag en reservekopieën; schoolleerlingen blijven beperkt tot de toewijzing
- Oude dubbele tabbalk en #adminTabsSlot verwijderd; beheerdata laadt één keer per bezoek en wordt tussen secties hergebruikt
- 28 Playwright-checks over zes rollen (navigatie, zoeken, filteren, thuiskind-whiteboard)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149FgUQvuwxKKEdvQGmNngF
2026-07-16 07:07:53 +02:00
Ramon
42fc323ab1 fix: toon gekoppelde ouders in de gebruikerslijst van de school (v0.3.59-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 28s
- Ouders (school_id NULL) vielen buiten elke schoolgescopeerde gebruikerslijst; /admin/users levert nu ook de ouders die aan leerlingen van de school gekoppeld zijn (groepsleiding: alleen ouders van leerlingen uit eigen klassen)
- Ouder-rijen tonen de namen van hun gekoppelde kinderen (childNames)
- Servertest voor de gekoppelde-ouders-lijst

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149FgUQvuwxKKEdvQGmNngF
2026-07-16 00:23:51 +02:00
Ramon
5f9ffbfdde feat: client-kant ouderportaal (v0.3.58-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 37s
- Derde tab "Ouders" in het inlogscherm: ouderaccount registreren (naam + 2× wachtwoord) met directe login
- Nieuw ouderportaal (parent.js): kinderenlijst met school/klas of "thuis", kind toevoegen (wachtwoord eenmalig als badge bij de rij), koppelen via ouder-code, aanmelden bij een school via doorzoekbare lijst met aanmeldstatus op de rij, voortgang per kind uitklapbaar, ontkoppelen met bevestiging
- Beheer: blok "Aanmeldingen (n)" bovenaan de Gebruikers-tab met per verzoek adopteren (klas + optionele andere gebruikersnaam bij naamconflict), koppelen aan een bestaande leerling, of afwijzen
- Beheer: actie "👪 Ouder-code" op elke leerlingrij (eenmalige code als badge); groep "Ouders" in de gebruikerslijst
- Foutmeldingen in het inlogscherm nu zichtbaar op alle drie de tabs
- i18n nl/en; volledige ouder- en schoolflow geverifieerd in headless Chromium (21 checks)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149FgUQvuwxKKEdvQGmNngF
2026-07-16 00:14:05 +02:00
Ramon
9d83e13bc3 feat: server-kant ouderportaal (v0.3.57-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 36s
- Nieuwe rol parent (school_id NULL): registreert zichzelf via POST /auth/register-parent (rate-limited, stafwachtwoordregels, directe sessie)
- Migratie 013: parent_children-koppeltabel, eenmalige users.parent_code, school_link_requests (aanmeldverzoeken, uniek per kind+school)
- Ouderroutes: kinderen bekijken (met school/klas/aanmeldstatus), thuiskind aanmaken (pupil zonder school, wachtwoord eenmalig terug), koppelen via ouder-code, aanmelden bij school, ontkoppelen
- Staf: ouder-code genereren per leerling, aanmeldingen bekijken en afhandelen (adopteren in klas met optionele nieuwe gebruikersnaam, koppelen aan bestaande leerling met opruiming van lege thuisaccounts, afwijzen)
- Voortgang: thuiskind zonder toewijzing logt met de gekoppelde ouder als leerkracht (bord "thuis"); gekoppelde ouders mogen de voortgang van hun kind opvragen
- 18 nieuwe servertests (registratie, koppelmodel, aanmeldflow, resolve-acties, voortgang)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149FgUQvuwxKKEdvQGmNngF
2026-07-16 00:02:16 +02:00
Ramon
a9bf2270d0 fix: beperk rollen en klaskoppeling tot staf (v0.3.56-beta)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 38s
- Functie-select in gebruikersbeheer alleen zichtbaar voor staf-rollen (teacher/admin/super)
- Klaskoppeling-UI alleen voor staf-rollen
- Server: rolwijziging alleen tussen staf-rollen onderling (leerlingen en toekomstige ouder-accounts kunnen nooit promoveren)
- Server: klaskoppeling weigert alle niet-staf-rollen expliciet
- canPersist() sluit de komende ouderrol uit van borden-opslag
- Servertest: ouder-achtige rol krijgt geen promotie en geen klaskoppeling

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149FgUQvuwxKKEdvQGmNngF
2026-07-15 23:56:39 +02:00
Ramon
0d644ba41d feat: voeg afbeeldingscatalogus en opslagquota toe
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 27s
2026-07-15 23:45:17 +02:00
Ramon
3ad7c80bad feat: koppel geldniveaus aan realistische winkelprijzen
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 24s
2026-07-15 22:51:49 +02:00
Ramon
54a95b2c19 revert: herstel officiële biljetten 2026-07-15 22:36:42 +02:00
Ramon
ff91ae0f2b test: gebruik eigen oefenbiljetten zonder markering
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 38s
2026-07-15 22:32:20 +02:00
Ramon
2742196c11 feat: toon echt euromateriaal in geldwidget
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 47s
2026-07-15 22:19:15 +02:00
Ramon
2fa9879107 feat: maak geld realistischer en uitsleepbaar
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 23s
2026-07-15 21:59:38 +02:00
Ramon
c2e6622546 feat: breid geldrekenen uit met niveaus en spellen
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 21s
2026-07-15 21:45:40 +02:00
Ramon
2d176cfc30 feat: voeg 24-uursoptie aan oefenklok toe
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 30s
2026-07-15 21:31:57 +02:00
Ramon
d900c25339 feat: breid niveau drie en wijzerbediening uit
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 23s
2026-07-15 21:10:31 +02:00
Ramon
e0220cdd00 fix: toon klokniveaus en verplaats koppeling
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 32s
2026-07-15 21:03:59 +02:00
Ramon
6e920e32db feat: koppel klokwijzers en start direct
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 20s
2026-07-15 20:53:47 +02:00
Ramon
cd15c0435b feat: voeg klokniveaus en typmodus toe
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 21s
2026-07-15 20:47:22 +02:00
Ramon
6e17dc5982 fix: voeg vrije uurmarkeringen toe
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 21s
2026-07-15 20:38:30 +02:00
Ramon
54782781bf fix: voorkom overlap op klokwijzerplaat
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 50s
2026-07-15 20:35:49 +02:00
Ramon
4cc8d466b8 feat: voeg sleepbare tijdblokken toe
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 27s
2026-07-15 20:32:12 +02:00
Ramon
72ea486518 feat: verbeter klokopdrachten en bediening
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 44s
2026-07-15 20:23:21 +02:00
Ramon
d02f7de72d feat: maak oefenklok visueel bedienbaar
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 20s
2026-07-15 20:12:43 +02:00
Ramon
3efe57b43c feat: breid oefenklok uit met niveaus en spellen
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 27s
2026-07-15 20:05:50 +02:00
Ramon
7287e49e0c v0.3.38-beta: koppel ook schoolbeheerders en systeemmanagers aan klassen
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 23s
- De klas-koppeling (chips + "voeg toe aan klas…") staat nu bij elke
  staf-rol, niet alleen bij groepsleiding; de klasnamen staan ook in de
  rijkop ("Schoolbeheerder · Groep 4")
- Server: /admin/classes/:id/teachers accepteert alle staf-rollen; alleen
  leerlingen niet (die horen al bij één klas). Een systeemmanager is
  school-onafhankelijk en mag aan klassen van elke school; overige staf
  moet bij dezelfde school horen
- Nieuwe servertest: admin en super koppelen ok, leerling en staf van een
  andere school geweigerd
2026-07-15 16:35:55 +02:00
Ramon
804ffb98f6 v0.3.37-beta: één functie per gebruiker + klas-koppeling voor groepsleiding
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 35s
- Het extra-functies-systeem (chips + select door elkaar) is uit de UI:
  een gebruiker heeft één functie, alleen te wijzigen via de Functie-select
- Groepsleiding is nu eenvoudig aan klassen te koppelen: huidige klassen
  als chips met ✕, een select "voeg toe aan klas…" voor nieuwe koppelingen;
  de klassen staan ook in de rijkop ("Groepsleiding · Groep 4")
- /admin/users geeft de klas-koppelingen (class_teachers) per gebruiker mee
- Formulier-fouten (bv. ongeldige gebruikersnaam bij een nieuwe
  systeemmanager) verschijnen nu direct bij het formulier in plaats van
  onzichtbaar bovenaan - dit maakte aanmaken schijnbaar onmogelijk
- Wachtwoord/koppelcode van een nieuwe gebruiker verschijnt direct bij die
  gebruiker in de lijst (rij en groep klappen vanzelf open)
2026-07-15 16:20:21 +02:00
Ramon
df921d5968 v0.3.36-beta: scholen mét schoolbeheerders in het Systeem-tabblad
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 33s
- Systeem toont per school een rij in klassen-stijl (🏫, accentkleur,
  aantal schoolbeheerders) met daaronder de schoolbeheerders als duidelijk
  onderscheiden subrijen (🛡, ingesprongen, eigen randkleur)
- Beide zijn in dit menu aan te passen via hetzelfde ✏-gereedschap:
  de school heeft een Naam-veld (nieuwe route PATCH /admin/schools/:id,
  alleen systeemmanager) en de bevestigde verwijder-actie; beheerders
  hebben hun volledige gereedschap (functie, extra functies, code,
  wachtwoord, verwijderen)
- Systeem-tab laadt beheerders van álle scholen, ook als de contextbalk
  elders op één school staat
- Drie nieuwe servertests voor het hernoemen (super ok, admin 403,
  naamvalidatie)
2026-07-15 16:02:57 +02:00
Ramon
b2ca4f93d5 v0.3.35-beta: schollenlijst in Systeem + verborgen formulieren + gelijke maten
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 32s
- Systeem-tabblad toont nu een overzicht van alle scholen als volwaardige
  rijen met een bevestigde verwijder-actie
- Het school-toevoegen-formulier zit achter een "+ School"-knop (zelfde
  patroon als gebruikers) en houdt de naam-bevestiging; de uitlegtekst is
  weg - teksten kort en krachtig
- Alle formulieren en knoppen in het beheer op dezelfde controlhoogte;
  fix: de rij-flexregels van invoervelden drukten velden binnen een
  veldlabel (kolom-flex) verticaal plat
- Ontbrekende veldlabel-tekst "Naam" toegevoegd (nl/en)
2026-07-15 15:53:10 +02:00
Ramon
03b8e6a41b v0.3.34-beta: één interactiesysteem in het beheer + veilige acties
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 22s
- Elk invoerveld/select/knopgroep in het beheer heeft nu een zichtbaar
  mini-label (field-helper): Functie, Extra functies, Klas, Wachtwoord,
  Naam, Acties - een placeholder alleen is geen toelichting meer
- Acties met gevolgen (nieuw wachtwoord, nieuwe koppelcode, verwijderen,
  wachtwoord-resets) zijn een aparte knopklasse: rood-zacht, tooltip die
  het gevolg uitlegt, en een tweede klik als bevestiging (arm-then-confirm,
  wapening loopt na 4s af); alle native confirm()-dialogen zijn vervangen
- Nieuw gegenereerde wachtwoorden/koppelcodes verschijnen direct bij de
  gebruiker in de rij (badge met kopieerknop, rij klapt vanzelf open),
  niet meer bovenaan; de topbalk is alleen nog voor fouten
- Klassen zijn volwaardige rijen op dezelfde maat als de gebruikersvakken,
  met leerlingaantal en de reset/verwijder-acties als bevestigde knoppen
- Systeem-tabblad: schoolkiezer-balk daar verborgen (school-onafhankelijk);
  school aanmaken heeft nu een uitleg, een naam-label, een knop die pas
  actief wordt bij een echte naam en een bevestigingsstap met de naam erin
- Toevoegen van gebruikers/klassen: knop pas actief bij geldige naam
2026-07-15 15:37:05 +02:00
Ramon
75244cde14 v0.3.33-beta: overzichtelijker beheerpaneel zonder tab-afhankelijkheid
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 21s
- Vaste schoolkiezer-balk (🏫) boven alle beheer-tabs voor de systeem-
  manager: geen omweg meer via het Systeem-tabblad om een school te kiezen;
  de kiezer is uit het Systeem-tabblad verdwenen en de hint verwijst naar
  de balk erboven
- Gebruikers-tab: leerlingen staan onder inklapbare groepskoppen per klas
  (standaard dicht, met aantal en ▸/▾-pijl); zoeken kijkt altijd door alle
  groepen heen zodat een treffer nooit verstopt zit
- Gebruikersrijen tonen standaard alleen naam en rol/klas; alle knoppen en
  velden (rol wijzigen, extra functies, klas, wachtwoord, koppelcode,
  verwijderen) zitten achter een ✏-knopje per rij; uitgeklapte staat blijft
  behouden over her-renders
2026-07-15 05:03:30 +02:00
Ramon
54eb8b18cb v0.3.32-beta: één tabbalk in Instellingen (geen geneste beheer-tabs meer)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 21s
- De beheer-tabs (Systeem/Klassen/Gebruikers/Toewijzingen/Voortgang) staan
  nu als losse knoppen direct in de instellingen-tabbalk naast Account en
  Weergave, in plaats van een tweede tabbalk binnen het Beheer-tabblad
- admin.js vult #adminTabsSlot en herbouwt bij gebruikers-/taalwissel;
  data wordt geladen bij binnenkomst in het beheer-deel, wisselen tussen
  beheer-tabs onderling hergebruikt de geladen data
- De losse "Beheer"-knop en de geneste .ed-tabs-balk zijn verwijderd;
  de tabbalk loopt om op smalle schermen (flex-wrap)
2026-07-15 04:37:15 +02:00
Ramon
d5e0b361bf v0.3.31-beta: geef ankerdiagrammen een prominentere plek
- Ankerwidget staat nu vooraan in de widgetbibliotheek (eerste kaart)
- Nieuw -item in het +-menu: plaatst direct een ankerdiagram op het bord
- Duidelijkere uitleg wat een ankerdiagram is (woordweb voor
  woordenschatonderwijs: woorden in samenhang rond een themawoord leren),
  in de bibliotheekkaart, de widget-hint en het +-menu-label (nl/en)
2026-07-15 04:32:25 +02:00
Ramon
6d5d4ef520 v0.3.30-beta: ankerdiagrammen als vaste tak in de hoofdverkenner
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 37s
- Nieuwe generieke withBranch-combinator (explorer.js): een tweede adapter
  verschijnt als vaste map in de root van de hoofdboom; item-sleutels worden
  geprefixt en slepen tussen de takken wordt geweigerd (ander soort inhoud)
- De borden-verkenner (📁 in de menubalk) toont nu " Ankerdiagrammen" met
  daarin de eigen diagrammappen én de gedeelde 🌐/🏫-takken voor ankers -
  borden en ankerwoorden op één plek, met dezelfde regels (slepen, kopiëren,
  alleen-lezen, één-klik-mappen)
- Diagram openen vanuit de hoofdverkenner plaatst een nieuw ankerwidget op
  het huidige bord met dat diagram geladen; het 🗂-knopje op een widget
  blijft in dát widget laden (adapter naar module-niveau getild met een
  onOpen-parameter, gedeeld door beide ingangen)
2026-07-15 04:12:43 +02:00
Ramon
a919e31e4c v0.3.29-beta: alleen-lezen in de verkenner + mappen openen met één klik
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 21s
- Gedeelde items die je niet mag beheren tonen een 🔒 en weigeren hernoemen/
  verplaatsen/verwijderen direct in de client met een duidelijke melding
  (kopiëren blijft altijd werken); mappen met vergrendelde inhoud tonen 🔒
- Nieuwe knop "🔒 Alleen lezen" in de school-tak, alleen zichtbaar voor
  schoolbeheerder/systeemmanager: vergrendelt het geselecteerde item of
  (zonder selectie) de hele huidige map, en ontgrendelt bij tweede keer
- Mappen openen nu met één klik (Windows-webstijl); slepen blijft werken
  via de bewegingsdrempel en de klik direct ná een sleep wordt genegeerd;
  hernoemen/verwijderen zonder selectie werkt op de huidige map (via het
  broodkruimelpad)
2026-07-14 22:53:47 +02:00
Ramon
24180beec1 v0.3.28-beta: alleen-lezen-vlag voor gedeelde items (server)
- Nieuwe migratie db/011: shared_library.readonly (default false)
- Beheerregel aangescherpt: een vergrendeld school-item is ook voor de
  eigenaar alleen-lezen; alleen schoolbeheerder en systeemmanager kunnen
  het nog wijzigen (systeem-items waren al alleen-lezen voor iedereen
  behalve de systeemmanager) - kopiëren blijft altijd werken
- De vlag zetten/weghalen kan per item (PATCH readonly) of per map
  (PATCH /shared/:kind/folder met {from, readonly}), uitsluitend door de
  schoolbeheerder van die school of de systeemmanager
- Lijst/detail geven readonly + canLock terug voor de UI; drie nieuwe tests
2026-07-14 22:49:17 +02:00
Ramon
e21bc177e1 v0.3.27-beta: gedeelde bibliotheek in de mappenverkenner
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 21s
- withSharedBranches (explorer.js): wikkelt een eigen-inhoud-adapter en
  voegt in de root de vaste takken "🌐 Systeem" (systeembreed) en
  "🏫 School" (binnen de eigen school) toe
- Slepen tussen bomen = kopiëren: eigen bord/diagram of hele map naar een
  gedeelde tak publiceert (POST /shared, kopie - origineel blijft); gedeeld
  item of map naar de eigen boom kopieert (borden krijgen nieuw id + verse
  wids); binnen een tak is slepen echt verplaatsen (PATCH, server bewaakt)
- Dubbelklik op een gedeeld bord kopieert en opent het; op een gedeeld
  ankerdiagram laadt het in het widget
- Verkenner ondersteunt nu async adapters (init/mutaties), groene
  ok-meldingen ("Gedeeld ✓"/"Gekopieerd ✓") en een eigenaar-hint per tegel
- Gasten en leerlingen zien alleen de eigen boom
2026-07-14 22:34:54 +02:00
Ramon
939c4ee68b v0.3.26-beta: server-API voor de gedeelde bibliotheek
- Nieuwe migratie db/010: shared_library-tabel (school_id NULL =
  systeembreed, anders per school; kind board/anchor; folder als pad)
- Routes: GET /shared/:kind (lijst, gefilterd op systeembreed + eigen
  school), GET /shared/:kind/:id (met data, voor kopiëren), POST (publiceren;
  scope global vereist systeemmanager, scope school staf met school),
  PATCH/DELETE per item en PATCH /shared/:kind/folder (prefix-rewrite,
  alleen als álle items onder het pad beheerd mogen worden)
- Beheerregel: systeemmanager altijd, eigenaar altijd, schoolbeheerder voor
  items van de eigen school; leerlingen hebben geen toegang
- Nieuwe permissies shared.global.manage / shared.school.manage (beide
  permissions.js); zes nieuwe servertests
2026-07-14 22:27:16 +02:00
Ramon
6de569c892 v0.3.25-beta: hernoem rol naar systeemmanager
- roleSuper heet nu "Systeemmanager" (en: "System manager"); het
  beheertabblad en de stafgroep "Overkoepelend" heten nu "Systeem"
- Alle overige teksten en commentaren met "overkoepelend beheerder"
  meegenomen; de interne rolcode "super" blijft ongewijzigd
2026-07-14 22:24:34 +02:00
Ramon
86478ebaca v0.3.24-beta: bewaar ankerdiagrammen los van het bord (bibliotheek)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 18s
- Nieuwe ankerbibliotheek ANCHOR_LIB, opgeslagen in een eigen data-sectie
  "anchors" (server-whitelist + 5MB-cap; lijst i.p.v. object toegestaan);
  reist mee in de volledige save, hydrate, gastreset en reservekopie-herstel
- Ankerwidget: 💾 bewaart het huidige diagram (naam = middelwoord, met
  ✓-feedback; leeg diagram wordt geweigerd met een hint), 🗂 opent dezelfde
  Windows-stijl mappenverkenner met de bewaarde diagrammen (geneste mappen,
  slepen, hernoemen, verwijderen)
- Dubbelklik op een bewaard diagram laadt het in het widget (cellen +
  plaatjes, thema-spiegel en bord-autosave volgen automatisch)
- Nieuwe servertest: anchors-sectie accepteert een lijst, andere secties
  weigeren die (en andersom)
2026-07-14 22:14:37 +02:00
Ramon
e327049f1b v0.3.23-beta: beheer woordthema's in dezelfde mappenverkenner
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 33s
- 🗂-knop in de woorden-editor opent de Windows-stijl verkenner met de
  thema's van de actieve taal (★-tegels met woordaantal); dubbelklik
  selecteert het thema in de editor
- Geneste mappen via het folder-veld als pad; nieuwe lege mappen bestaan
  sessie-lokaal tot er een thema in wordt gezet (mappen zijn afgeleid van
  de themavelden)
- Ankerthema's staan vast in de map "": niet versleepbaar, hernoemen/
  verwijderen geweigerd (anchor.js beheert ze)
- Het 📁-knopje + inline map-invoer uit v0.3.21 zijn vervangen door de
  verkenner; de optgroup-weergave in de dropdowns blijft en toont het pad
2026-07-14 22:01:59 +02:00
Ramon
1151c71049 v0.3.22-beta: Windows-stijl mappenverkenner voor borden
- Nieuw public/js/explorer.js: generieke verkenner-modal met broodkruimelpad,
  werkbalk (nieuwe map/nieuw item/hernoem/verwijder met bevestigingsstap),
  raster van map- en itemtegels, dubbelklik om te openen en slepen om te
  verplaatsen (pointer-events, werkt op touch; drop-doel licht op)
- Geneste mappen zonder datamigratie: nesting zit in de mapnaam als pad met
  "/"-scheiding; server en toewijzingen (bord-id's) blijven onaangeroerd;
  "/" wordt geweigerd in nieuwe namen
- Borden-adapter in board.js: bordtegels met boardThumb-preview, actief bord
  gemarkeerd en gevolgd bij verplaatsen/hernoemen (prefix-rewrite), map
  verwijderen alleen als leeg, laatste bord onverwijderbaar
- 📁-knop in de menubalk opent de verkenner; het oude mappenpaneel
  (renderBoardsPanel + #boardsPanel + CSS) is vervangen; de boardStrip-
  snelwissel blijft; curSlot() heelt lege actieve mappen zelf
2026-07-14 21:58:24 +02:00
Ramon
f2243c13c4 v0.3.21-beta: groepeer woordthema's in mappen
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 18s
- Thema's krijgen een optioneel folder-veld; de theme-dropdown in de
  woorden-editor en de kaart-dropdowns in de widgets (fillWordSourceSel)
  groeperen per map met optgroups, mapl0ze thema's bovenaan
- Nieuw 📁-knopje in de editor zet het gekozen thema in een map (leeg veld
  haalt het eruit); zichtbaarheid volgt de themakeuze
- Ankerthema's komen automatisch in de vaste map "" (id-koppeling met de
  ankerwidget blijft onaangeroerd)
- Nieuwe i18n-teksten themeFolder/themeFolderPh (nl/en)
2026-07-14 16:35:22 +02:00
Ramon
18775ae0ec v0.3.20-beta: hernoem mappen en verplaats borden tussen mappen
- Bordenpaneel: dubbelklik op een mapnaam hernoemt de map (zelfde
  inline-input-patroon als bord hernoemen)
- Nieuw 📁-knopje per bord toont een inline select met de overige mappen;
  bij keuze verhuist het bord, het actieve bord volgt mee (BS.f/BS.b
  worden gecorrigeerd) en een leeggeraakte map krijgt een vers bord
- renameTip vermeldt nu ook mappen; nieuwe i18n-tekst moveBoardTip (nl/en)
2026-07-14 16:29:25 +02:00
Ramon
2ce82ab998 v0.3.19-beta: verstuur bij het opslaan alleen gewijzigde secties
- Nieuwe route PUT /me/data/:section (boards/themes/generalExtra): vervangt
  alleen die sub-key via jsonb_set, met dezelfde rev/409-controle en
  snapshot-hook als de volledige PUT (die blijft bestaan als terugval)
- Per-sectie size-caps (boards 20MB, themes/generalExtra 2MB)
- core.js: DIRTY-set houdt bij wat er gewijzigd is; woordwijzigingen sturen
  alleen themes+generalExtra, bordwijzigingen alleen boards (sequentieel,
  rev per respons bijgewerkt); zonder gerichte wijziging volledige save
- Twee nieuwe servertests (jsonb_set op de juiste sub-key, onbekende sectie
  is 404)
2026-07-14 16:26:16 +02:00
Ramon
6980d72041 v0.3.18-beta: bewaar en herstel eerdere versies van borddata
- Elke data-write bewaart eerst de oude data in user_data_versions (hooguit
  één snapshot per 10 minuten, maximaal 10 versies per gebruiker)
- Nieuwe routes: GET /me/data/versions (lijst) en POST /me/data/restore
  (zet een versie terug; bewaart de huidige data eerst zodat herstel zelf
  ook omkeerbaar is); beide niet voor leerlingen
- Nieuw blok "Reservekopieën" in Instellingen → Account met datum/tijd per
  versie en een herstelknop met bevestigingsstap (arm-then-confirm)
- Vier nieuwe servertests (snapshot vóór write, opruimen op 10, pupil-403,
  restore bewaart huidige data eerst)
2026-07-14 16:23:10 +02:00
Ramon
b28d25296d v0.3.17-beta: detecteer save-conflicten tussen tabbladen
- Nieuwe migratie db/009: users.data_rev + data_updated_at en de
  user_data_versions-tabel (voor de komende versiegeschiedenis)
- GET /me/data geeft nu {data, rev}; PUT /me/data controleert een optionele
  x-data-rev-header en weigert een verouderde schrijver met 409 (zonder
  header blijft het oude laatste-schrijver-wint-gedrag voor oude clients)
- core.js: rev wordt bijgehouden en meegestuurd; bij 409 toont de opslaan-
  knop "Elders bewerkt" en haalt een klik eerst de nieuwste serverversie op
  in plaats van te overschrijven
- beforeunload-waarschuwing bij een openstaande, lopende of mislukte save
- Nieuwe test test/save-system.test.js (rev mee, 409, legacy zonder header)
2026-07-14 16:19:25 +02:00
Ramon
d0ab0b2483 v0.3.16-beta: deel één widget via de Toewijzingen-tab
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 34s
- assignmentRow: na bordkeuze verschijnt een widget-select ("heel bord" of
  één widget van dat bord, client-side uit BS-borddata); bij een widgetkeuze
  een modus-select (kijken/werken); PUT-body krijgt widgetId + mode mee
- Widgets zonder wid (borden van vóór v0.3.13) worden overgeslagen tot de
  eerstvolgende save van dat bord
- Infotekst toont nu ook widget en modus van de huidige toewijzing
- Nieuwe i18n-teksten amWholeBoard/amModeWatch/amModeWork (nl/en)
2026-07-14 15:53:31 +02:00
Ramon
873f8e0bee v0.3.15-beta: kijken/werken-modus in de leerling-omgeving
- pupil.js: verwerkt de modus uit /my/assignment; "kijken" toont een
  meekijk-badge, blokkeert alle interactie en logt geen voortgang; "werken"
  (default) is het bestaande gedrag met voortgang-logging
- Poll-interval dynamisch: 5s in kijken-modus (wijzigingen van de leerkracht
  komen vlot door), 20s in werken-modus; moduswissel her-rendert direct
- teach.css: generieke kijken-overlay (pointer-events:none op de widget-body),
  werkt voor elk widgettype zonder eigen readonly-ondersteuning
- Nieuwe i18n-tekst pupilWatching (nl/en)
2026-07-14 15:51:20 +02:00
Ramon
b13fe65da5 v0.3.14-beta: sta toewijzing van één widget toe met kijken/werken-modus (API)
- Nieuwe migratie db/008_widget_share.sql: assignments krijgt widget_id
  (NULL = heel bord, bestaand gedrag) en mode ('kijken'/'werken',
  default 'werken')
- PUT /assignments/class/:id en /assignments/pupil/:id accepteren optioneel
  widgetId + mode; gedeelde validatie (parseShareBody) controleert dat de
  widget echt op het opgegeven eigen bord staat
- describeAssignment geeft widgetId/widgetType/mode terug voor de UI
- GET /my/assignment filtert bij een widget-toewijzing tot die ene widget en
  stuurt de modus mee
2026-07-14 15:48:14 +02:00
Ramon
d27419b9f6 v0.3.13-beta: geef widgets een stabiel instantie-id (wid)
- board.js: genWidgetId() naar het voorbeeld van genBoardId(); toegekend in
  makeWidget (bestaand wid uit opgeslagen data wint), bewaard in
  serializeBoard; dupliceren geeft een nieuw wid; oude borden zonder wid
  krijgen er vanzelf een bij de eerstvolgende save
- /my/assignment stuurt wid mee per widget
- pupil.js: voortgang-widgetId gebruikt nu het wid (terugval op positie voor
  borden van vóór deze versie)

Voorbereiding op het delen van één losse widget (roadmap item 8).
2026-07-14 15:46:15 +02:00
Ramon
be89a7b498 v0.3.12-beta: herstel sessie na refresh (regressie beveiligingsaudit)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 27s
De beveiligingsaudit (v0.3.03-beta) verving de client-side Bearer-token
(localStorage) door een HttpOnly session-cookie, maar de sessie-herstel-IIFE
in app.js las nog steeds de verwijderde TOKEN-variabele uit - een
ReferenceError die de hele boot-restore liet crashen. Resultaat: elke
paginaverversing verloor de ingelogde staat, ook al bleef de cookie zelf
geldig. Fix: geen client-side tokencheck meer nodig (de HttpOnly-cookie is
sowieso niet leesbaar door JS en gaat vanzelf mee); /auth/me wordt nu altijd
geprobeerd en valt bij een 401 terug op gastmodus.
2026-07-14 15:31:17 +02:00
Ramon
aac7fd1c68 v0.3.11-beta: toon leerlingvoortgang in nieuw admin-tabblad
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 17s
- Nieuwe "Voortgang"-tab naast Toewijzingen: leerkracht kiest een leerling
  (zelfde per-klas gegroepeerde select) en ziet de volledige tijdlijn van
  GET /progress/pupil/:id (widgettype, score, tijdstip)
- fillPupilSelect(): gedeelde helper voor de per-klas leerlingselectie,
  onttrokken uit Toewijzingen zodat Voortgang hem ook gebruikt
- Nieuwe i18n-teksten amProgress/amProgressEmpty (nl/en)
2026-07-14 15:05:16 +02:00
Ramon
04e9bf3847 v0.3.10-beta: rapporteer widgetvoortgang vanuit leerling-speelmodus
- board.js: fix bug waarbij de opts-parameter (readonly e.d.) nooit bij
  mountMath aankwam, doordat de registry-wrapper hem liet vallen
- math.js/letters.js/ball.js: nieuwe opts.onProgress-callback, aangeroepen
  bij resp. einde rekenronde, voltooid woord en geknapte ballon
- pupil.js: geeft onProgress mee bij het mounten en post het naar
  /my/progress; alleen actief in leerling-speelmodus, niet bij bewerken
2026-07-14 15:00:31 +02:00
Ramon
e3369e34a2 v0.3.09-beta: voeg voortgang-schema en -API toe
- Nieuwe migratie db/007_progress.sql: progress_events-tabel (per leerling
  per widget-moment: pogingen, goed, sterren)
- POST /my/progress: leerling logt een afgerond moment; teacher_id/board_id
  worden server-side afgeleid uit de bestaande toewijzing, nooit van de client
- GET /progress/pupil/:id en GET /progress/class/🆔 leerkracht-weergave,
  gated met nieuwe progress.view-permissie en dezelfde scoping als assignments
- Permissie progress.view toegevoegd in beide permissions.js-bestanden
2026-07-14 14:51:50 +02:00
Ramon
a20779e602 v0.3.08-beta: breid widgetbibliotheek uit
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 37s
- voeg acht educatieve en klaswidgets toe\n- verbeter galerij met zoeken, favorieten en lessjablonen\n- voeg dupliceren, vergrendelen en voorbeeldweergave toe\n- voeg geschiedenis en begrensde bordexport/import toe\n- verbeter responsiviteit, toegankelijkheid en vertalingen
2026-07-14 14:16:49 +02:00
Ramon
6e41ea1b2e v0.3.07-beta: voeg educatieve widgets toe
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 29s
2026-07-14 13:39:57 +02:00
Ramon
6097d7c9f1 v0.3.06-beta: herstel bereikbaarheid via Pangolin
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 17s
2026-07-14 13:26:15 +02:00
Ramon
50fafc789a v0.3.05-beta: rol nginx-config atomisch uit
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 17s
2026-07-14 13:23:15 +02:00
Ramon
e727d6a07c v0.3.04-beta: draai securitytests in Docker
Some checks failed
dev - build & deploy naar test / build-and-deploy (push) Failing after 27s
2026-07-14 13:09:09 +02:00
Ramon
f9b2be8187 v0.3.03-beta: versterk publieke beveiliging
Some checks failed
dev - build & deploy naar test / build-and-deploy (push) Failing after 4s
2026-07-14 12:42:16 +02:00
Ramon
d864299ea6 v0.3.02-beta: maak tekenwerkbalk compact
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 9s
2026-07-14 10:57:56 +02:00
Ramon
09a5d84bba v0.3.01-beta: verbeter automatisch opslaan van borden 2026-07-14 10:40:58 +02:00
Ramon
4b54ea4a12 v0.3.00-beta: nieuw ontwerp \"teachus.today\" - minimalistisch, nieuw logo, licht+donker
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 8s
- Nieuw logo: low-poly uil als SVG (transparant, vlakke merk-kleuren) + woordmerk
  \"teachus.today\" in de menubalk; op kleine schermen alleen de uil. Ook favicon
  en inlogscherm gebruiken het nieuwe logo.
- Nieuwe huisstijl afgeleid van het logo: teal als primaire actiekleur, navy inkt,
  Quicksand-font (zelf gehost, ~28 KB), dunne lijnen, vlakke minimale chrome-laag;
  het glas-effect blijft alleen op de bord-laag (widgets/HUD).
- Token-systeem herschreven: semantische kleuren (--surface/--line/--accent/...),
  radius-/schaduwschaal en één control-hoogte (--control-h) zodat alle vakken
  (inputs, selects, knoppen) in elke rij even hoog zijn; op aanraakschermen
  groeit alles mee naar 44px. Galerij-tegels hebben nu gelijke hoogtes.
- Modern tabsysteem: underline-tabs die overlopen in hun paneel (geen gele
  file-folder-tabs en omrande panelen meer); kleine keuzegroepen (taal, niveaus,
  timer, chips) delen één segmented-control-stijl.
- Donker thema: schakelbaar (licht/donker/auto volgt het OS), alle panelen,
  bordpatronen en widgets doen mee; hoog contrast wint altijd van donker.
- Nieuw tabblad Instellingen -> Weergave: thema, hoog contrast (verhuisd uit de
  menubalk), taal NL/EN (verhuisd uit de menubalk), menubalk-positie
  (boven/links/rechts), animaties aan/uit en glas-effect aan/uit - allemaal
  apparaat-gebonden en ook als gast bereikbaar via het inlogscherm.
- Menubalk: rustiger (transparante knoppen, hairline i.p.v. schaduw) en
  verplaatsbaar naar links of rechts als verticale kolom; bord, leerling-
  weergave en zwevende knoppen schuiven mee.
- Taalkeuze wordt nu onthouden (localStorage).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DuxHJtk5aHe2pA3xwCLEAk
2026-07-14 09:59:13 +02:00
Ramon
0411375a3c v0.2.22-beta: leerling-omgeving (aparte pagina zonder whiteboard)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 9s
- Nieuwe tabel `assignments`: een leerkracht koppelt één van haar eigen
  borden aan een klas (standaard) of een individuele leerling (uitzondering,
  voor wie op een ander niveau werkt).
- Geen momentopname: /my/assignment zoekt het bord live op bij de
  leerkracht, dus nieuwe woorden die zij toevoegt komen vanzelf door zodra
  de leerling-pagina opnieuw pollt (elke 20s).
- Leerlingen loggen in op een vereenvoudigde pagina zonder whiteboard/
  tekengereedschap: enkel de toegewezen taal-/rekenwidgets, als vaste
  (niet-sleepbare) kaarten in speelmodus.
- Speelmodus verbergt bewerkfuncties in Ankerwoorden (plaatje kiezen,
  woord typen, kleur wijzigen) en Letterblokken (thema/woordbeheer) -
  overige widgets waren al zuiver speelgericht.
- Elk bord krijgt een stabiel id (board.js) zodat een toewijzing een bord
  blijft vinden ook na hernoemen of herordenen.
- Nieuw tabblad "Toewijzingen" in het beheerpaneel: per klas of leerling
  een eigen bord kiezen, met een expliciete toewijs-stap.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DuxHJtk5aHe2pA3xwCLEAk
2026-07-13 23:14:26 +02:00
Ramon
2528e5b8f6 v0.2.21-beta: meerdere functies per gebruiker (multi-rol voor staf) + zoekveld
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 7s
- Nieuwe user_roles-koppeltabel (db/004_user_roles.sql): staf kan voortaan naast de hoofdrol extra functies krijgen (bv. groepsleiding + schoolbeheerder tegelijk); leerling blijft altijd exclusief
- can()/PERMISSIONS accepteren nu een array van rollen i.p.v. alleen een losse string (backward compatible), CREATABLE_ROLES-opzoeking wordt een unie over alle rollen van een gebruiker
- Rechten-checks in src/api.js gebruiken voortaan req.user.allRoles (hoofd- + extra rollen); identiteits-/scoping-logica (leerling-filters, aanmaken, groepsleiding-klas-scope) blijft bewust op de hoofdrol staan
- PATCH /admin/users/:id accepteert een nieuw veld extraRoles (super-only, alleen voor staf)
- Beheerpaneel: toggle-knoppen per stafgebruiker om extra rollen aan/uit te zetten; Instellingen toont voortaan alle rollen samengevoegd ("Schoolbeheerder + Groepsleiding")
- Zoekveld boven de gebruikerslijst (live filter op naam, client-side, behoudt focus tijdens typen) omdat die lijst in een grote school lang kan worden

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-13 22:41:40 +02:00
Ramon
e24e810313 v0.2.20-beta: Scholen-tab wordt Overkoepelend, bugfix leerlingen-lijst, VERSION bijgewerkt
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 9s
- "Scholen"-tabblad hernoemd naar "Overkoepelend" en het aanmaken van een overkoepelend beheerder verplaatst hierheen vanuit Gebruikers - die rol hoort niet bij één school, dus dat schoolgebonden tabblad was de verkeerde plek
- Klassen-tabblad toonde een lege, onverklaarde pagina als een super nog geen school had gekozen; laat nu een duidelijke hint zien
- Bugfix: leerlingen met een klas-koppeling verdwenen onterecht helemaal uit de Gebruikers-lijst wanneer een super naar "alle scholen" keek (CLASSES was dan leeg, dus geen enkele klas-groep kon ze tonen) - valt nu terug op een platte lijst zoals bij groepsleiding
- VERSION-bestand dit keer wél meteen bijgewerkt

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-13 22:24:16 +02:00
Ramon
2ceeec2de2 v0.2.19-beta: leerlingen per klas in het beheerpaneel + groepsleiding-scope + extra stap bij toevoegen
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 8s
- GET /admin/users: groepsleiding (teacher) ziet voortaan alleen leerlingen uit de eigen klas(sen) (via class_teachers), i.p.v. de hele school - staf blijft zichtbaar zoals voorheen
- Gebruikers-tab: leerlingen worden voor schoolbeheerder/super gegroepeerd per klas getoond (met een "geen klas"-groep), i.p.v. één platte lijst los van de Klassen-tab; groepsleiding houdt een platte lijst (nu vanzelf al beperkt tot eigen klas door de backend-scope)
- Alle "gebruiker toevoegen"-formulieren (staf + leerling, incl. de nieuwe per-klas toevoegrij) starten ingeklapt als alleen een "+ …"-knop; pas na een klik verschijnen de invoervelden
- Verwijderen van een gebruiker had al een bevestigingsvraag - ongewijzigd, bevestigd dat dit blijft werken
- Koppelcode-functie bewust ongewijzigd gelaten (privacy-optie naast direct-wachtwoord-aanmaken)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-13 22:04:20 +02:00
Ramon
f5140d42c9 v0.2.18-beta: VERSION-bestand was sinds v0.2.10-beta niet meer bijgewerkt
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 8s
- Het versietagje toonde daardoor al zeven commits lang nog steeds "v0.2.10-beta", ook al draaide de echte, nieuwere code allang (Instellingen-herontwerp, beheerpaneel-tabs, ankerwoorden-plaatjes, enz.)
- VERSION teruggezet naar de daadwerkelijke huidige versie
- Robuustere weergave: op dev-builds staat de git-hash er nu altijd bij in de zichtbare tekst zelf (niet meer alleen als hover-tooltip), zodat een nieuwe deploy altijd zichtbaar anders is, ook als het VERSION-bestand een keer vergeten wordt

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-13 21:26:42 +02:00
Ramon
1b6960b7ba v0.2.17-beta: beheerpaneel opgesplitst in tabs (Scholen/Klassen/Gebruikers)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 10s
- render() bouwde tot nu toe alles in één lange, doorlopende lijst; nu drie tabbladen die hetzelfde ed-tabs-patroon hergebruiken als de login- en Instellingen-tabs
- "Scholen" alleen zichtbaar voor super, "Gebruikers" is het standaard-tabblad
- Actief tabblad blijft behouden na acties (nieuwe klas/gebruiker toevoegen springt niet meer terug naar het eerste tabblad)
- Zuiver een frontend-herstructurering: geen gedragswijziging aan de onderliggende functionaliteit (reload/msg/classSel/userRow/addForm/resetPanel ongewijzigd)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-13 21:03:13 +02:00
Ramon
270739da09 v0.2.16-beta: ankerwoorden - lengtegrens-bug, geen nep-ankersymbool, koppeling met woordkaart
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 12s
- Lengte-check voor ankerwoorden was strenger dan het invoerveld zelf toestond ({2,12} vs maxLength 24): woorden als "kledingwinkel" werden nooit opgezocht terwijl ARASAAC er prima plaatjes voor heeft
- Geen ankersymbool meer als terugval wanneer ARASAAC geen match heeft (bv. "contant"); de cel blijft leeg en is klikbaar als snelkoppeling naar een nieuwe, herbruikbare plaatjeskiezer (nieuw: public/js/picker.js, hergebruikt dezelfde emoji-lijst/ARASAAC-zoekfunctie/CSS als de bestaande woordkaart-editor)
- Elk ankerraster synchroniseert zijn woorden-met-plaatje voortaan naar een eigen thema in THEMES, zodat ankerwoorden ook beheerbaar zijn via de bestaande woordkaart-editor (Letterblokken-widget) - geen wijziging aan letters.js nodig, het bestaande thema-systeem pakt dit vanzelf op
- Oudere borden met het letterlijke ankersymbool als opgeslagen "plaatje" migreren automatisch naar de nieuwe lege staat

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-13 19:28:05 +02:00
Ramon
6cb0965a9c v0.2.15-beta: ankerwoorden tonen nu ook zelf hun plaatje
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 8s
- De automatische ARASAAC-plaatjes (sinds v0.2.06-beta) werden alleen doorgegeven aan andere widgets (Hak/Flits/Bal/Woordkaart) als woordbron, maar nooit getoond in het Ankerwoorden-raster zelf - vandaar dat het leek te ontbreken, voor zowel bestaande als nieuwe woorden
- render() tekent nu een klein plaatje naast elk woord in de cel, met een render()-aanroep zodra een opgehaald plaatje binnenkomt
- Getest tegen de echte ARASAAC-API: bestaande woorden (uit een opgeslagen bord) tonen hun plaatje meteen bij het laden, nieuwe woorden tonen eerst het ankersymbool en daarna het echte plaatje zodra dat binnenkomt

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-13 17:32:42 +02:00
Ramon
baf2a4cb13 v0.2.14-beta: beheerpaneel volledig geïntegreerd in Instellingen (één overzicht)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 18s
- Het beheerpaneel opende nog als los venster (adminWrap) boven op Instellingen; nu is het een tabblad ("Account"/"Beheer") binnen hetzelfde Instellingen-scherm - één modal, geen twee
- adminWrap/adminModal-als-los-venster verwijderd; admin.js rendert nu in een contentblok binnen settingsModal, zonder eigen dubbele titel/sluitknop (die van Instellingen zelf dekt dat al)
- Instellingen is breder geworden om ruimte te bieden aan de beheerinhoud (klassen, gebruikers, aanmaakformulieren); het accountgedeelte blijft smal en overzichtelijk via een eigen max-breedte

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-13 16:23:07 +02:00
Ramon
43c7892eb7 v0.2.13-beta: één instellingenmenu - beheer, versie en copyright samengevoegd
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 9s
- Werkbalk teruggebracht tot één ⚙️-knop (was 👤 + los 👥-beheerknop + los versienummer bij het logo)
- Beheerpaneel-knop verplaatst in Instellingen (nieuwe "Beheer"-sectie, alleen zichtbaar met rechten); opent nog steeds hetzelfde beheerpaneel, sluit nu ook Instellingen zodat er geen twee schermen over elkaar staan
- Versienummer verplaatst van de werkbalk naar de voettekst van Instellingen
- Copyright-regel toegevoegd in de voettekst ("© <jaar> Ramon Besselink")
- Taal/contrast/geluid bewust NIET verplaatst: die blijven op de werkbalk omdat ze ook zonder inloggen (gastgebruik) bruikbaar moeten blijven, terwijl Instellingen alleen open gaat na inloggen

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-13 16:13:01 +02:00
Ramon
14115b79ad v0.2.12-beta: Instellingen herzien tot een overzichtelijk, volwassen menu
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 9s
- Losse ⚙️-knop uit de vorige commit weer verwijderd; Instellingen blijft bereikbaar via de bestaande 👤-knop, geen extra knoppen in de werkbalk
- Instellingen ingedeeld in duidelijke secties (Account, Wachtwoord, Sessie) met kaarten en sectielabels, hergebruikt van het beheerpaneel (.am-h3/.am-reset/.am-name/.am-role) i.p.v. losse velden onder elkaar
- Casual "Hoi ... 👋"-begroeting vervangen door een rustige naam/rol-weergave, consistent met hoe andere gebruikers in het beheerpaneel getoond worden
- Expliciete ✕-sluitknop toegevoegd, zelfde patroon als het beheerpaneel

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-13 15:55:20 +02:00
Ramon
8a3bf1e8fc v0.2.11-beta: aparte ⚙️-knop voor Instellingen in de werkbalk
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 11s
- Instellingen opende voorheen alleen via de bestaande 👤-knop, zonder enig visueel signaal in de werkbalk dat daar iets veranderd was
- Nieuwe ⚙️-knop (zichtbaar zodra je bent ingelogd) opent Instellingen rechtstreeks; de 👤-knop blijft dit ook doen zodra je bent ingelogd

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-13 15:46:06 +02:00
Ramon
7b6621ff9c v0.2.10-beta: echte semantische versienummering (v0.0.00-beta) i.p.v. git-sha in de UI
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 8s
- Nieuw bestand VERSION (repo-root) is nu de enige bron voor het versienummer; CI leest dit uit en geeft het door als APP_VERSION i.p.v. het opake dev-<sha> van de vorige build
- dev-deploys tonen voortaan "v0.2.10-beta" i.p.v. "dev-<sha> · beta"; productie blijft het releaselabel tonen
- Git-sha blijft beschikbaar via /api/version (nieuw veld "sha") en als hover-title op het versietagje, voor support/debug
- Dockerfile/CI-workflows (dev + release) geven de git-sha nu als apart APP_ARG mee

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-13 15:30:37 +02:00
Ramon
ca825ce6f8 v0.2.09-beta: versienummer in de UI klopte niet meer met de echte build
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 13s
- #verTag toonde altijd een hardgecodeerde, verouderde versie (0.2.01); nu wordt de echte versie uit /api/version getoond zodra die bekend is (dev-<sha> · beta op dev, of het releaselabel op productie)
- versienummer weer zichtbaar op mobiel (was volledig verborgen op schermen ≤600px)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-13 15:23:09 +02:00
Ramon
b52c45329c v0.2.08-beta: instellingen-pagina, vernieuwd inlogscherm, centrale permissiematrix + rolwijziging
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 18s
- Inlogscherm herzien: aparte tabs voor "Inloggen" en "Koppelcode activeren" i.p.v. één doorlopende vorm
- Nieuwe Instellingen-pagina: account-info, wachtwoord wijzigen en uitloggen zijn verplaatst uit het inlogscherm naar een eigen scherm (👤-knop opent nu Instellingen i.p.v. het inlogscherm zodra je bent ingelogd)
- Laadstatus op de inlog-, koppelcode- en wachtwoordknoppen tijdens het versturen; consistente foutmeldingen i.p.v. een losse alert() bij het wijzigen van je eigen wachtwoord
- Centrale, benoemde permissiematrix (nieuw: src/permissions.js + public/js/permissions.js) vervangt de verspreide rol-arrays in src/api.js en de losse rol-checks in admin.js/core.js
- Nieuw: een overkoepelend beheerder (super) kan nu de rol van een stafaccount (groepsleiding/schoolbeheerder/overkoepelend) rechtstreeks in het beheerpaneel wijzigen; leerlingaccounts blijven altijd leerling

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-13 10:39:50 +02:00
Ramon
b80da89ab6 v0.2.07-beta: ankerwoorden automatisch opslaan
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 12s
- Ankerwoorden-widget: elk toegevoegd, gewijzigd of verwijderd woord wordt nu automatisch (na korte debounce) opgeslagen naar de server, net als bij de woordkaart-editor
- persistWords(): ververst eerst de bordstatus (stashCurrent) voordat er opgeslagen wordt, zodat ook de bestaande woordkaart-autosave geen verouderde bordstatus meer verstuurt
- Zonder deze fix gingen getypte ankerwoorden verloren bij herladen/opnieuw inloggen zonder expliciet op "Bord opslaan" te klikken, en verschenen ze daardoor ook niet in andere widgets na een reload

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-13 09:31:52 +02:00
Ramon
d05b12bb86 v0.2.06-beta: automatische plaatjes per woord in Ankerwoorden
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 8s
- Ankerwoorden-widget: elk woord krijgt nu automatisch een passend plaatje via de ARASAAC-pictogrammendienst, in plaats van steeds hetzelfde ankersymbool
- Plaatjes worden per woord gecachet en bewaard in de bordstatus, zodat ze niet steeds opnieuw opgehaald worden
- Bij geen resultaat of een netwerkfout valt de widget terug op het ankersymbool
- ARASAAC-opzoekfunctie hergebruikt vanuit de bestaande woordkaart-editor (geen dubbele code meer)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-13 08:55:43 +02:00
Ramon
5cd1c80073 v0.2.05-beta: bronwaarde widgets als string bewaren + projectafspraken toegevoegd
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 10s
- ball.js/flits.js/hak.js: S.card bewaart de geselecteerde bronwaarde nu altijd als string i.p.v. te casten naar number, zodat de bronselectie correct blijft werken
- AGENTS.md en CLAUDE.md toegevoegd met projectafspraken

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-13 08:04:50 +02:00
Ramon
05d4fc7c8e v0.2.04-beta: mobiel- en tablet-vriendelijk maken van bord, widgets en beheer
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 14s
- Responsive breakpoints toegevoegd (tablet ≤1024px, telefoon ≤600px) en
  grotere tikzones op aanraakschermen (pointer:coarse) - er waren nog
  geen @media-regels in de hele stylesheet
- Bugfix: #boardsPanel had een vaste 300px-breedte en overflowde op een
  telefoon; nu net zo responsive als #boardStrip
- Widgets (letters, rekenen, schrijfblok, mindmap, ...) krijgen niet
  langer harde desktop-pixelmaten die van het scherm afvallen - grootte
  en positie worden nu geclampt aan de zichtbare bordgrootte
- Eigen, groter aanraakbare resize-greep voor widgets i.p.v. de
  piepkleine native browser-grip (resize:both)
- Beheerpaneel: dichte rijen (wachtwoordveld + knoppen) stapelen nu
  netjes op smalle schermen i.p.v. verdrukt te wrappen

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-13 07:53:52 +02:00
Ramon
64acb84f50 v0.2.03-beta: kopieerknop voor wachtwoorden + multireset klas/school
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 12s
- Kopieerknop (📋) bij elk getoond wachtwoord/koppelcode, zodat het niet
  meer verdwijnt voordat het overgetypt kan worden
- Bugfix: getoond wachtwoord werd bijna direct overschreven doordat de
  lijst opnieuw werd opgebouwd vlak nadat het bericht getoond werd (race
  condition tussen msg() en reload())
- Nieuw: alle leerlingwachtwoorden van een klas of hele school in één
  keer resetten, alleen voor schoolbeheerder en overkoepelend beheerder
- Resultatenpaneel na een multireset met "kopieer alles"-knop (blijft
  zichtbaar tot de beheerder het zelf sluit)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-12 22:53:08 +02:00
Ramon
bd7c7e07e7 v0.2.02: uitgebreid wachtwoordbeheer voor gebruikers
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 17s
- Beheerders kunnen bij groepsleiding/schoolbeheer/super meteen zelf een
  wachtwoord instellen of genereren, als alternatief voor de koppelcode.
- Nieuwe directe wachtwoord-reset voor deze rollen, los van koppelcode-reset.
- Leerling-wachtwoord is na de eerste keer inloggen niet langer inzichtelijk
  voor groepsleiding/beheer; alleen opnieuw genereren kan dan nog.
- Wachtwoordeisen aangescherpt en overal consistent gecontroleerd (leerling
  min. 4 tekens, groepsleiding/beheer min. 8 met letter en cijfer).
- Bevestigingsveld en toon/verberg-knop bij accountactivatie en eigen
  wachtwoord wijzigen, om typefouten te voorkomen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-12 22:32:35 +02:00
bes-r
99fadaaedc v0.2.01: schoolsysteem + automatische migraties; deploy: APP_VERSION uit image
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 7s
2026-07-09 23:04:24 +02:00
bes-r
08fd9e11e3 v0.2.01: automatische migraties bij opstarten (transactie per bestand, geen dataverlies)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 17s
2026-07-09 22:34:36 +02:00
bes-r
352e22a64b v0.2.00: schoolsysteem met rollen (super/admin/groepsleiding/leerling), koppelcodes, server-API en beheerpaneel
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 13s
2026-07-09 22:26:01 +02:00
bes-r
d1d3265c6c v0.1.02: opsplitsing in css/, js/core|data|board|app en js/widgets/* (geen functionele wijziging)
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 8s
2026-07-09 21:56:49 +02:00
bes-r
334b0f8e14 Versienummering en Widget Ankerwoorden toegevoegd
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 12s
2026-07-08 22:47:23 +02:00
bes-r
3a77442abc Nginx reverse proxy op poort 8081
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 21s
2026-07-08 22:17:28 +02:00
bes-r
01e7f77264 ssh deploy werkend + trigger
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 10s
2026-07-08 22:11:32 +02:00
bes-r
92a7e6e237 ssh deploy: fail-fast (BatchMode + ConnectTimeout)
Some checks failed
dev - build & deploy naar test / build-and-deploy (push) Failing after 6s
2026-07-08 22:01:23 +02:00
bes-r
2b567fe624 Deploy: alleen app-image pullen, niet Docker Hub
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 9s
2026-07-08 21:52:25 +02:00
bes-r
f2cb88f5a6 Schone pipelinerun
Some checks failed
dev - build & deploy naar test / build-and-deploy (push) Has been cancelled
2026-07-08 21:48:01 +02:00
bes-r
910f7953ad Nieuwe testrun 2026-07-08 20:49:02 +02:00
bes-r
b7979dbbcf Deploy via gewone ssh i.p.v. externe action
Some checks failed
dev - build & deploy naar test / build-and-deploy (push) Has been cancelled
2026-07-08 00:14:48 +02:00
bes-r
1db182f440 runs-on: self-hosted runner
Some checks failed
dev - build & deploy naar test / build-and-deploy (push) Failing after 2s
2026-07-07 23:45:25 +02:00
bes-r
ab16f160df Test pipeline dev->test 2026-07-07 23:35:43 +02:00