# Roosterwijs Modulair, flexibel roostersysteem voor het speciaal onderwijs (uil-logo: een uil staat voor wijsheid → *Roosterwijs*). Zie `PLAN.md` voor de visie en de fasering, en `DEPLOY.md` voor draaien op een test-/productieserver. Status: **Fase 0–4** klaar. Fase 0 (plugin-framework), Fase 1 (personen, groepen, subgroepen, functies), Fase 2 (schooljaarkalender + roosterblokken), Fase 3 (afwezigheid, uitzonderingen, effectief weekrooster) en Fase 4 (**conflictdetectie**: dubbele inzet van begeleider/leerling en locatiebotsingen). Het Rooster-scherm is een **weekweergave met drag-and-drop** (muis én touch) en een **touch-vriendelijk** ontwerp; vrije dagen, afwezigheid en uitzonderingen worden automatisch verwerkt. De Roostermaker heeft tabs **Week / Genereren / Instellingen**: onder Instellingen beheer je schooljaar + kalender, tijdvakken, vakken, lokalen, locaties en vormgeving; onder Genereren zitten de Vak-wizard en het Auto-rooster. Conflicten verschijnen als melding boven het weekrooster, niet als aparte tab. De zijbalk groepeert items onder inklapbare submenu's (Personen, Groepen) en heeft onderaan een subtiel **Instellingen**-blok met Gebruikers en Modulebeheer. Er zijn twee rooster-schermen: **Rooster** (alleen-lezen weergave, om te bekijken en af te drukken) en **Roostermaker** (de aanpasser met drag-and-drop, tabs en conflictdetectie). In de Roostermaker open je een blok met een **klik** om het te bewerken (vak, locatie, doelgroep, begeleiders, opmerking) of te **kopiëren** naar andere tijden/dagen. Het aparte scherm **Groepsindeling** (zijbalk → Organisatie) verdeelt een hoofdgroep of leerplein kolomsgewijs in subgroepen, met per subgroep de vakken en de verantwoordelijke(n), en je kunt er direct subgroepen toevoegen. Beide roosterschermen hebben een **scope-filter** (alles / per klas / per leerplein / per leerling / per personeel); de module **Printen/Exporteren** voegt — als die aanstaat — een subtiele **Afdrukken**-knop toe die het (gefilterde) weekrooster printvriendelijk afdrukt of als PDF bewaart. Optionele module **Multi-user & toegang**: een **Gebruikers**-scherm (onder Instellingen, alleen voor beheerders) om inloggers te beheren — gebruikersnaam, wachtwoord, rol (beheerder/medewerker/ouder/leerling), koppeling aan een persoon, en actief/beheerder-status. Optionele module **Leerplein**: koppelt subgroepen aan groepen en bundelt groepen, subgroepen én losse leerlingen onder een overkoepelend leerplein. Optionele module **Stage**: interne en externe stages van leerlingen — beide met een begeleider, een interne stage ook met een ruimte. Beide modules zijn aan/uit te zetten via Modulebeheer. **Fase 5 (recent)**: vaste tijden zijn per groep aan te passen (een tijdslot zonder groep = algemene tijd, met groep = afwijkende tijd). Personeel en leerlingen hebben gescheiden invoerschermen. Bij personeel koppel je direct functie(s), stamgroep/plein en de vakken die ze kunnen geven; een leerkracht krijgt de theorievakken automatisch. Bij een leerling leg je groep en geboortedatum vast. ## Wat er nu staat - **Backend** (`backend/`) — Django + Django REST Framework. - `plugins/` — het plugin-framework: een moduleregister, opslag van de aan/uit-status per module en een beheer-API. - `core/` — de kern (altijd actief): personen, groepen, subgroepen, functies, schooljaar + kalender, tijdvakken, activiteiten, locaties, lokalen, roosterblokken en conflictdetectie, elk met een CRUD-API. - `modules/` — twaalf modules die zich bij opstarten aanmelden bij het register: `printing`, `accounts`, `leerplein`, `stage`, `uren`, `blokwizard`, `personenwizard`, `autorooster`, `huisstijl`, `importexport`, `vervanging` en `portal`. De volledige lijst staat in `MODULE_APPS` in `backend/config/settings.py`. - **Frontend** (`frontend/`) — React (Vite). Zijbalk met Roosterwijs-logo die alleen menu's toont van ingeschakelde modules, beheerschermen voor **Personen**, **Groepen** en **Subgroepen**, en een scherm **Modulebeheer**. ## Hoe modulariteit werkt (het verkoopargument) 1. Een module is een gewone Django-app met een `apps.py` die in `ready()` een `ModuleSpec` registreert (naam, beschrijving, versie, afhankelijkheden en menu-items). 2. Het register weet wélke modules bestaan; de database onthoudt of ze **aan** staan. Een beheerder schakelt ze per school in/uit via Modulebeheer. 3. Uitgeschakelde modules leveren geen menu's of schermen — de kern blijft overal gelijk, modules zijn los bij te schakelen. Een nieuwe module toevoegen = nieuwe app maken, één regel in `MODULE_APPS` (in `backend/config/settings.py`), klaar. ## Installeren op een server Eén commando, zeven stappen, drie vragen. Alles komt standaard in `/srv/server-up`: ```bash git clone /roosterwijs.git /tmp/roosterwijs-install /tmp/roosterwijs-install/scripts/install.sh ``` Het script controleert Docker, haalt de code op, laat je kiezen of de gegevens in **Docker-volumes** of in **gewone mappen** (`/srv/server-up/data/`) komen, genereert `.env` met willekeurige geheimen, bouwt de containers en maakt een beheerder aan. Bijwerken doe je daarna met `./scripts/deploy.sh`. Details, de opslagkeuze en het draaien achter TLS staan in `DEPLOY.md`. ## Starten (lokaal ontwikkelen) > Voor een test- of productieserver gelden **andere** stappen: zie `DEPLOY.md`. > Daar draait alles in Docker en komt de configuratie uit `.env`. ### Backend (Django, poort 8000) ```bash cd backend python3 -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate pip install -r requirements.txt # Zonder DJANGO_DEBUG=1 weigert Django te starten: buiten debug is # DJANGO_SECRET_KEY verplicht. Met debug aan valt hij terug op een dev-sleutel. export DJANGO_DEBUG=1 # Windows: $env:DJANGO_DEBUG="1" python manage.py migrate python manage.py createsuperuser # VERPLICHT, zie hieronder python manage.py runserver ``` **`createsuperuser` is geen optionele stap.** De hele API staat op `IsAuthenticated` en de frontend toont eerst een inlogscherm; zonder account kom je nergens binnen — ook niet in de app zelf, niet alleen in `/admin/`. Zonder `POSTGRES_DB` in de omgeving gebruikt de backend automatisch SQLite in `backend/db.sqlite3`. `DEPLOY.md` zet PostgreSQL in via `.env`. API-eindpunten: - `GET /api/modules/` — alle modules met status. - `POST /api/modules//state/` — body `{"enabled": true|false}`. - `GET /api/info/` — korte systeem-/gezondheidsinfo. - CRUD-endpoints (telkens met `PATCH`/`DELETE` op `//`): `/api/personen/` (filter `?rol=leerling`), `/api/groepen/`, `/api/subgroepen/`, `/api/functies/`, `/api/schooljaren/`, `/api/kalenderdagen/` (filter `?schooljaar=`), `/api/tijdsloten/`, `/api/activiteiten/`, `/api/locaties/`, `/api/roosterblokken/` (filters `?schooljaar=`, `?groep=`, `?subgroep=`, `?leerling=`), `/api/afwezigheden/` (filters `?persoon=`, `?van=`, `?tot=`), `/api/blok-uitzonderingen/` (filters `?roosterblok=`, `?schooljaar=`, `?van=`, `?tot=`). - `GET /api/conflicten/?schooljaar=` — roosterconflicten (dubbele inzet, locatiebotsing, onderbezetting). - Module Leerplein: `/api/leerpleinen/`, `/api/subgroep-groep-koppelingen/`. - Module Stage: `/api/stages/` (filters `?type=intern|extern`, `?leerling=`). - Tijdsloten kennen een optionele `groep` (per-groep tijden); personen hebben `stamgroep`, `vakken` en `geboortedatum`; activiteiten een `theorievak`-vlag. - `/admin/` — Django-admin (personen, groepen, subgroepen en modulestatus). > Draait SQLite niet op je projectmap (bv. op een netwerkschijf)? Zet dan > `ROOSTER_DB_PATH` naar een lokaal pad, of pas `DATABASES` aan. ### Frontend (React, poort 5173) Vereist **Node 20.19+ of 22.12+** — Vite 8 weigert oudere versies. Controleer met `node -v`. ```bash cd frontend npm install npm run dev ``` De dev-server stuurt `/api` automatisch door naar de backend op poort 8000. Open daarna http://localhost:5173 en ga naar **Modulebeheer** om modules aan/uit te zetten. ## Volgende stap (Fase 5 & 6) De losse modules verder uitbouwen: **Printen/Exporteren** (roosters als PDF) en **Multi-user & toegang** verfijnen (leerling-/ouder-/collega-rollen). Eventueel de conflictdetectie datum-specifiek maken (rekening houdend met afwezigheid per dag).