exam-utils/: useful utility functions working on exam data typesjs-api/: wasm bindings forexam-utils, published to npm as@freecodecamp/exam-servicesmoderation-service/: tasks to manage exam attemptsprisma/: prisma schema Rust exportscript/: assortment of past, once-off scripts interacting with the database
This project is deployed on the Digital Ocean App Platform as a Job on a schedule. The image is built using GitHub Actions, pushed to the Digital Ocean Container Registry, then the App Platform auto-deploys the new image.
To deploy:
- manually bump the version(s) of the changed package(s)
- run the
deploy.yamlto build and push to DOCR
docker build . --file ./moderation-service/DockerfileSeed database with exam and attempt
cd freeCodeCamp/freeCodeCampm
pnpm run seed:exam-env --attemptA specific version of rustc is used, because the test tooling requires nightly features.
cargo +nightly-2025-04-03 testget_moderation_score is high-risk. Every algorithm version is registered in
moderation_versions.rs and run over a
committed, PII-free scenario catalog (testdata/moderation/scenarios/).
Runs in CI (test-exam-utils.yml); no nightly, no DB.
# Gate + report (report.html written to testdata/moderation/, git-ignored).
cargo test -p exam-utils- Gate:
moderation_scores_goldenasserts scores matchscores.golden. A change to a live version (or edit to a frozen one) fails it. - Report: open
exam-utils/testdata/moderation/report.html— per-version scores, deltas, threshold crossings. Includes real attempts if a localfixtures/dump exists.
Change the algorithm → review the drift → regenerate the golden:
UPDATE_GOLDEN=1 cargo test -p exam-utils moderation_scores_golden
git diff exam-utils/testdata/moderation/scores.goldenAdd a case: drop a JSON file in scenarios/, then UPDATE_GOLDEN=1.
Add a version (when changing the algorithm): freeze the old body as vN_<sha> in moderation_versions.rs, append to VERSIONS, then UPDATE_GOLDEN=1 — see that file's header.
WASM bindings for exam-utils, consumable from Node.js and browsers. See js-api/README.md for the API reference and consumption docs.
rustup target add wasm32-unknown-unknown
npm install -g wasm-pack
node js-api/build.mjs # builds the npm package into js-api/pkg/
node js-api/smoke-test.mjs # runs the package against fixtures/ (when present)- bump
versioninjs-api/Cargo.tomland updatejs-api/CHANGELOG.md - commit, then tag and push:
git tag js-api-v<version> && git push origin js-api-v<version>
The publish-js-api.yml workflow (also runnable via workflow_dispatch) builds, smoke-tests, and publishes to npm with provenance. Requires the NPM_TOKEN repository secret.
cd script/
cargo run