Files
learning-platform/pb_migrations/1781100000_created_question_bank.js
RaymondVerhoef 43a71e2110
All checks were successful
On Push to Main / test (push) Successful in 1m1s
On Push to Main / publish (push) Successful in 1m22s
On Push to Main / deploy-dev (push) Successful in 2m18s
feat: on-demand topic tests with shared question bank
Adds a /topic-test route where learners can take a 5-question test on any
eligible topic at any time. Questions come from a shared, admin-curated
question_bank — no LLM calls on the user path. Points feed the existing
leaderboard with a 10pt/topic/week cap (per ISO week) so the bank can't be
farmed, and repeats from a thin bank yield 0 points.

- New PB collections: question_bank, on_demand_attempts (+ migrations and
  setup-pb-collections.mjs entries).
- db.js: un-deprecates getQuizBank/setQuizBank against question_bank so the
  existing admin TestManager panel becomes functional again; adds
  saveOnDemandAttempt, getOnDemandPointsThisWeek, getUserSeenQuestionIds,
  getAllOnDemandAttempts, isoWeekKey.
- testService.js: getEligibleTopicsForOnDemand, startOnDemandTest (unseen-
  first draw), finishOnDemandTest (cap enforcement + leaderboard upsert).
- New TopicTest page, route, and nav entry; weekly test flow untouched.
- Leaderboard folds on-demand 100%s into perfect-score count and merges
  on-demand attempts into the recent activity feed.
- Spec: docs/on-demand-tests-spec.md with ADRs and extension points.
- Tests: 5 new vitest cases covering eligibility, draw fallback, scoring,
  partial cap, and exhausted cap (85/85 total).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-02 15:06:43 +02:00

69 lines
1.8 KiB
JavaScript

/// <reference path="../pb_data/types.d.ts" />
// Creates the question_bank collection used by on-demand topic tests.
// One record per topic; `questions` is a JSON array of question objects
// (id, question, options[], correctIndex, explanation, difficulty, topicLabel).
// Replaces the deprecated `quiz_banks` collection that was dropped in
// 1780800001_deleted_legacy_collections.js.
migrate((app) => {
const collection = new Collection({
"createRule": "",
"deleteRule": "",
"listRule": "",
"updateRule": "",
"viewRule": "",
"name": "question_bank",
"type": "base",
"fields": [
{
"autogeneratePattern": "",
"hidden": false,
"id": "text_topic_id",
"max": 0,
"min": 0,
"name": "topic_id",
"pattern": "",
"presentable": false,
"primaryKey": false,
"required": true,
"system": false,
"type": "text"
},
{
"hidden": false,
"id": "json_questions",
"maxSize": 0,
"name": "questions",
"presentable": false,
"required": false,
"system": false,
"type": "json"
},
{
"hidden": false,
"id": "autodate_created",
"name": "created",
"onCreate": true,
"onUpdate": false,
"presentable": false,
"system": false,
"type": "autodate"
},
{
"hidden": false,
"id": "autodate_updated",
"name": "updated",
"onCreate": true,
"onUpdate": true,
"presentable": false,
"system": false,
"type": "autodate"
}
]
});
return app.save(collection);
}, (app) => {
const collection = app.findCollectionByNameOrId("question_bank");
return app.delete(collection);
});