- 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)
- 🗂-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
- 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
- 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)
- 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)
- 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)
- 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)
- 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)
- 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)
- 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)
- 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
- 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).
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.
- 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)
- 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
- 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
- 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
- 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
- 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
- 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>
- "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>
- 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>
- 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>
- 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>
- 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>
- 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>
- 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>
- #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>
- 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>
- 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>
- 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>
- 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>