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
24 lines
1.4 KiB
SQL
24 lines
1.4 KiB
SQL
-- Klassenmanagement: per vakgebied (taal/rekenen/world) een niveaugroep
|
|
-- (groep 1-8, gebaseerd op de leerjaren van de basisschool, waaraan de
|
|
-- leerdoelen gekoppeld zijn) en een niveau (1-3, fijnmazige verfijning
|
|
-- BINNEN die groep - niet aan 3 geklemd in het datamodel zelf, widgets
|
|
-- klemmen voorlopig zelf nog wel). Zelfde vorm als assignments: precies
|
|
-- één van class_id/pupil_id gezet (klas-standaard, of een individuele
|
|
-- afwijking - in het speciaal onderwijs vaak vanaf het begin de norm),
|
|
-- nu met vakgebied als extra dimensie, dus één rij per (klas|leerling,
|
|
-- vakgebied) i.p.v. één rij per klas|leerling.
|
|
CREATE TABLE IF NOT EXISTS pupil_levels (
|
|
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
class_id BIGINT REFERENCES classes(id) ON DELETE CASCADE,
|
|
pupil_id BIGINT REFERENCES users(id) ON DELETE CASCADE,
|
|
subject TEXT NOT NULL,
|
|
year_group INT NOT NULL,
|
|
level INT NOT NULL DEFAULT 1,
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
CHECK (num_nonnulls(class_id, pupil_id) = 1),
|
|
CHECK (subject IN ('taal','rekenen','world')),
|
|
CHECK (year_group BETWEEN 1 AND 8),
|
|
CHECK (level >= 1)
|
|
);
|
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_pupil_levels_class ON pupil_levels(class_id, subject) WHERE class_id IS NOT NULL;
|
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_pupil_levels_pupil ON pupil_levels(pupil_id, subject) WHERE pupil_id IS NOT NULL;
|