A self-paced onboarding track that introduces a new employee to every KB
theme in breadth (not depth), so they grasp how Respellion works day to
day and week to week. Offered as a CTA inside the Dashboard "New here?"
explainer card; always available regardless of enrollment.
Design:
- Theme is the trackable unit; the 5 "days" are a read-time presentation
grouping, so re-chunking never loses progress. Completion is stored per
theme in onboarding_completions.
- Per-theme overview generated lazily on first open (fast-tier
emit_onboarding_overview tool), cached in onboarding_overviews keyed by
theme + a topics_fingerprint that triggers regeneration when the theme's
topic set changes.
- Reachable via /onboarding-track using the existing skipEnrollmentGate
prop, decoupled from the 26-week curriculum (distinct from /onboarding,
the enrollment page).
Backend:
- pb_migrations/1781200000_created_onboarding.js: two collections with
authenticated-only rules and unique indexes; TEXT team_member_id (no
relation) per the post-#18/#27 convention. Mirrored in
scripts/setup-pb-collections.mjs.
- src/lib/onboardingService.js: pure helpers (orderThemes,
distributeThemesIntoDays, computeTopicsFingerprint,
computeOnboardingProgress, buildOnboardingPlan) + generation + I/O.
- db.js onboarding helpers use pb.filter() bindings (theme is free text).
- LLM tool + Zod schema + registry + simulation stub.
Frontend:
- src/pages/OnboardingTrack.jsx (day list, per-theme overview, completion
banner, progress ring/day bar).
- Dashboard "New here?" card CTA + X/5-days progress chip (hidden when the
KB has no themes).
Docs: data-model, generation-spec (§D), frontend-spec updated.
Verified: 22 new unit tests (npm test 134/134), eslint clean on changed
files, npm run build OK, PocketBase v0.30.4 boot applies the migration
(collections + unique indexes + authed rules confirmed), and a backend
contract check (upsert idempotency, unique-index guard, special-char
theme filtering).
Closes#30
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Admin Topic Quizzes (was Quizzes): topics are now grouped under
collapsible theme headers with per-theme counts. Topics without a
theme fall into a "No theme" bucket rendered last.
- /topic-test picker: eligible topics grouped by theme so learners can
scan a curriculum theme and drill its topics on demand.
- Fix admin Theme Content panel (was Learning Content): it was empty
because content moved to the theme_sessions collection in an earlier
refactor while the panel still queried the legacy per-topic content
table. Rewrites ContentManager to read db.getAllThemeSessions and
render the emit_theme_session schema (title, intro, topic sections,
connections, key takeaways). Adds db.getAllThemeSessions and
db.deleteThemeSession.
- Disambiguate theme vs topic across the app: the weekly curriculum
test is now "Theme Test" (nav, page heading, Dashboard card, button,
explainer); the on-demand bank test stays "Topic Test". Admin nav
also clarified to "Theme Content" / "Topic Quizzes".
No schema changes. 85/85 tests still pass, build green.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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>
Adds a BuildStamp component pinned to the bottom-right of every page
(desktop only, dim monospace text) so it's obvious at a glance which
build is currently running.
The git short SHA and an ISO build timestamp are injected at build time
via Vite's `define`, falling back to 'unknown' if git is not available.
ESLint config declares the two compile-time constants as readonly
globals so no per-file disable comments are needed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Implements phase 1 of AI_PIPELINE_HARDENING_PLAN.md. Every Anthropic call
now goes through one module that owns retry, timeout, abort, structured-
output parsing, schema validation, and best-effort call telemetry.
* src/lib/llm.js — single callLLM entry point. Resolves model per tier
(fast / standard / reasoning) with admin:model legacy fallback for the
standard tier; 60s default timeout via AbortController; balanced-brace
JSON extraction; LLMHttpError, LLMTruncatedError, LLMOutputError, and
LLMValidationError surface clearly distinct failure modes.
* src/lib/llmRetry.js — exponential backoff with full jitter, retries
only on transient HTTP statuses, honours Retry-After up to 60s, never
retries on AbortError.
* src/lib/llmSchemas.js — Zod schemas for every structured task plus
normalizeHandbookResult (collapses legacy "executes" relations into
the canonical "executed_by" vocabulary).
* src/lib/api.js — thin shim over callLLM so existing callers (extraction
pipeline, learning, quiz, R42, knowledge graph) keep working unchanged.
* src/lib/__tests__/ — 32 Vitest cases covering parse paths, error
surfaces, simulation mode, model resolution, and schema validation.
* src/pages/Admin/index.jsx — three model inputs (fast / standard /
reasoning) replacing the single legacy field; legacy value falls back
for the standard tier so existing overrides survive.
Adds Zod and Vitest, plus an "npm run test" script.
Also cleans up the pre-existing repo-wide ESLint failures so phase 1's
"npm run lint passes" acceptance criterion can be checked: drops unused
React imports across the JSX tree (React 19 JSX runtime auto-imports),
attaches cause to rethrown errors in the service modules, ignores
pb_migrations in the ESLint config (PocketBase JSVM globals), and
removes one dead handleCreateCustom function in Leren.jsx. A real
behaviour bug surfaced in Testen.jsx — the quiz timer captured a stale
finishQuiz via setInterval closure; now updated via finishQuizRef so the
timer always invokes the latest callback.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>