ADR-002 — Node.js + TypeScript + Fastify backend¶
Status¶
Accepted (2026-07-03, inherited from heig-classroom). Amended 2026-10-03: the
language/framework choice remains; the version pins, the library shortlist and
"explicit authorization middleware on every route" are withdrawn — access is
loaded through modules/guards.ts (invariant 6).
The inherited record preserves the original library shortlist.
Context¶
One maintainer needs readable control flow and shared types across the API, SPA and tools, including GitHub and OIDC integrations.
Decision¶
- Strict TypeScript and Node.js, with Zod contracts in
packages/contracts. Runtime and compiler versions belong topackage.json, workspace manifests,pnpm-lock.yamland the Dockerfiles, not a second dependency list in this ADR. - Fastify, explicit plugin/service wiring, no DI framework or decorators.
Routes validate with shared contracts;
modules/guards.tsloads authorized entities. Access rules are the invariants inCLAUDE.md. - Quiz uses Octokit,
openid-clientand Fastify's structured logging. The installed dependencies are inapps/api/package.json; webhook HMAC, request validation and rate limits are implemented where they are needed (webhook HMAC inmodules/github, rate limits in the kiosk, live and runner paths), not guaranteed by the libraries once proposed here.
Consequences¶
Client and server share schemas, while module discipline stays explicit. Development can use Keycloak for real OIDC independently of institutional configuration. The inherited Swagger/type-provider/Luxon dependency proposals are not evidence that those packages or generated clients exist in Quiz.
Rejected alternatives¶
NestJS would add framework indirection; another backend language would lose shared contracts. No second route-contract framework is needed merely to duplicate Zod. See the inherited rationale before reconsidering those choices.