Commit graph

41 commits

Author SHA1 Message Date
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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