|
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
|
||
|---|---|---|
| .forgejo/workflows | ||
| db | ||
| deploy | ||
| public | ||
| src | ||
| test | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| AGENTS.md | ||
| CLAUDE.md | ||
| compose.yaml | ||
| Dockerfile | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| VERSION | ||
Teach
Digibord-webapp (Fastify + static frontend) met PostgreSQL, gecontaineriseerd en
via Forgejo Actions automatisch uitgerold: dev → test-VM, release → productie-VM.
Structuur
teach/
├─ public/index.html # de digibord-app (voorheen teach.html)
├─ src/server.js # Fastify: serveert de app + /api + DB-pool
├─ db/001_init.sql # initieel Postgres-schema
├─ Dockerfile # productie-image (non-root, healthcheck)
├─ compose.yaml # lokaal draaien (app + postgres)
├─ deploy/compose.deploy.yaml # test/prod: pullt image uit de registry
├─ .forgejo/workflows/
│ ├─ dev.yaml # push naar dev → build + deploy test
│ └─ release.yaml # release → build + deploy prod
└─ .env.example
Lokaal draaien
cp .env.example .env # pas POSTGRES_PASSWORD en DATABASE_URL aan
docker compose up --build
App op http://localhost:3000, healthcheck op /healthz, DB-check op /readyz.
Architectuurkeuzes
- Container i.p.v. losse static site: omdat er een database bijkomt, is een
backend nodig (browser praat niet rechtstreeks met Postgres). De Fastify-app
serveert de HTML én biedt de
/api, en praat met de DB. - Forgejo container registry: CI bouwt de image één keer en pusht die; beide VM's pullen exact dezelfde geteste image. Geen build op de productie-VM.
- Pangolin/Traefik verzorgt de publieke HTTPS-ingang. De meegeleverde nginx
vormt de interne proxylaag en luistert standaard op poort
8081, zodat de Pangolin/Traefik-route deze via het VM-/containernetwerk kan bereiken. De Fastify-app vertrouwt precies twee proxy-hops.
Eenmalige setup
1. Repo aanmaken in Forgejo
Maak een leeg repo (bv. ramon/teach) en push (zie onderaan).
2. Registry / Actions variabelen en secrets
Onder Settings → Actions → Variables van het repo (of org):
| Variable | Waarde | Uitleg |
|---|---|---|
REGISTRY |
10.0.20.22:3000 |
Host van je Forgejo = registry |
De image heet dan 10.0.20.22:3000/bes-r/teach.
Onder Settings → Actions → Secrets:
| Secret | Uitleg |
|---|---|
REGISTRY_USER |
Forgejo-gebruiker met package-write rechten |
REGISTRY_TOKEN |
Token/wachtwoord voor die gebruiker (scope: packages) |
TEST_HOST |
IP/hostname van de test-VM |
TEST_USER |
SSH-gebruiker op de test-VM |
TEST_SSH_KEY |
Private SSH-key (deploy key) voor de test-VM |
TEST_DEPLOY_PATH |
Pad op de test-VM met compose.deploy.yaml + .env + db/ |
PROD_HOST |
IP/hostname van de productie-VM |
PROD_USER |
SSH-gebruiker op de productie-VM |
PROD_SSH_KEY |
Private SSH-key voor de productie-VM |
PROD_DEPLOY_PATH |
Pad op de productie-VM met de deploy-bestanden |
De runner moet de
docker-CLI kunnen gebruiken (host-socket of docker-in-docker) enactions/checkout+appleboy/ssh-actionkunnen ophalen. Pasruns-onin de workflows aan naar het label van jouw runner als dat nietubuntu-latestis.
2b. HTTP-registry toestaan (insecure-registries)
Je Forgejo draait op http://10.0.20.22:3000 (platte HTTP). Docker weigert
HTTP-registries tenzij je ze expliciet toestaat. Doe dit op drie plekken: de
runner-host (die pusht) en beide VM's (die pullen). Op elke Docker-host:
# /etc/docker/daemon.json
{
"insecure-registries": ["10.0.20.22:3000"]
}
sudo systemctl restart docker
Zet je Forgejo later achter HTTPS met een echt domein, dan kan deze stap weg en gebruik je dat domein als
REGISTRY.
3. Deploy-map op elke VM
Op zowel de test- als de productie-VM, in het pad dat je bij *_DEPLOY_PATH
opgeeft:
mkdir -p teach && cd teach
# kopieer deze twee uit de repo:
# deploy/compose.deploy.yaml -> compose.deploy.yaml
# db/ -> db/
# maak een .env aan:
cat > .env <<'EOF'
IMAGE=10.0.20.22:3000/bes-r/teach:dev # prod: laat CI dit op :vX.Y.Z zetten
POSTGRES_DB=teach
POSTGRES_USER=teach
POSTGRES_PASSWORD=<sterk-wachtwoord>
DATABASE_URL=postgres://teach:<sterk-wachtwoord>@db:5432/teach
APP_PORT=3000
WEB_BIND_IP=0.0.0.0
WEB_PORT=8081
TRUST_PROXY_HOPS=2
SUPER_USER=beheerder
SUPER_PASS=<uniek-sterk-eerste-wachtwoord>
EOF
CI werkt bij elke deploy de IMAGE=-regel bij, pullt en herstart.
4. Pangolin/Traefik publiceren
Publiceer http://<interne-vm-ip>:8081 via Pangolin/Traefik en laat daar TLS
beëindigen. De interne nginx behoudt X-Forwarded-Proto: https, waarna de app
Secure/HttpOnly/SameSite-cookies, HSTS en overige securityheaders gebruikt.
- Beperk poort 8081 met de hostfirewall tot het Pangolin/Traefik- of tunnelnetwerk.
- Pas
TRUST_PROXY_HOPSalleen aan wanneer de proxyketen werkelijk verandert. - Bij een aparte Traefik-container kan een gedeeld intern Docker-netwerk nodig
zijn; zet
WEB_BIND_IPniet ruimer dan noodzakelijk. SUPER_PASSis alleen nodig bij een lege database, wordt nooit gelogd en moet via de beveiligde deploy-omgeving worden aangeleverd.- De overgang naar v0.3.03-beta trekt bestaande browsersessies bewust in.
Workflow / branching
- Werk op feature-branches, merge naar
dev→ automatisch naar test. - Tevreden? Maak een release (tag
vX.Y.Z) → automatisch naar productie.
Push naar Forgejo (eerste keer)
git remote add origin http://10.0.20.22:3000/bes-r/teach.git
git push -u origin main
git push -u origin dev
Volgende stap: data uit localStorage naar de database
De frontend bewaart borden/gebruikers nu nog in localStorage. Om echt een
gedeelde database te gebruiken, bouwen we /api-endpoints (boards, folders,
users) in src/server.js en laten we de frontend die aanroepen i.p.v.
localStorage. Het schema in db/001_init.sql is daarvoor het startpunt.