Parent PRD
#41
What to build
The foundational tracer bullet for gamification. End-to-end: when a student marks a lesson complete, a 10 XP event is recorded, and the student's current Level + total XP become visible in the sidebar.
- New
xp_events table (userId, amount, sourceType, sourceId, timestamp) — serves as the audit log and the dedup mechanism (a given sourceType+sourceId is awarded at most once). See PRD "Database Changes".
- Shared leveling utility in
app/lib/ (importable by both server and client) implementing the curve round(80 * N^1.3): derive level from total XP, XP required for a level, and progress toward next level. See PRD "Leveling System" and "Further Notes".
- Extend
progressService.markLessonComplete to record a 10 XP lesson_completion event as a side effect, idempotently (re-completing the same lesson awards nothing extra). See PRD "XP Awards".
- A gamification service to read a user's total XP (summed from
xp_events) and derived level.
- Sidebar (
app/components/sidebar.tsx) shows an always-visible "Level N" + total XP for the current student.
XP is global across all courses. Level is derived from total XP (not stored). XP data is loaded only for the current user (private).
Acceptance criteria
Blocked by
None - can start immediately.
User stories addressed
- User story 1
- User story 3
- User story 4
- User story 6
- User story 17
Parent PRD
#41
What to build
The foundational tracer bullet for gamification. End-to-end: when a student marks a lesson complete, a 10 XP event is recorded, and the student's current Level + total XP become visible in the sidebar.
xp_eventstable (userId, amount, sourceType, sourceId, timestamp) — serves as the audit log and the dedup mechanism (a givensourceType+sourceIdis awarded at most once). See PRD "Database Changes".app/lib/(importable by both server and client) implementing the curveround(80 * N^1.3): derive level from total XP, XP required for a level, and progress toward next level. See PRD "Leveling System" and "Further Notes".progressService.markLessonCompleteto record a 10 XPlesson_completionevent as a side effect, idempotently (re-completing the same lesson awards nothing extra). See PRD "XP Awards".xp_events) and derived level.app/components/sidebar.tsx) shows an always-visible "Level N" + total XP for the current student.XP is global across all courses. Level is derived from total XP (not stored). XP data is loaded only for the current user (private).
Acceptance criteria
xp_eventstable added with a migration generated viapnpm db:generateand applied viapnpm db:migrateapp/lib/, usable on server and client, with unit tests covering the documented breakpoints (1→2 = 80, 2→3 ≈ 197, 3→4 ≈ 345, 5→6 ≈ 720, 10→11 ≈ 1596)xp_eventspnpm testand typecheck passBlocked by
None - can start immediately.
User stories addressed