feat(learning): add persistent achievement records

New achievements table: stage_completed/curriculum_completed/assessment_completed/
capstone_completed, idempotent (WHERE NOT EXISTS guard, not a unique-index dance — simple and
correct at this write volume). Not a certificate — a durable internal record Phase 4/5 can
render one from later. recordAssessmentAchievement only fires on an actual pass, defensively,
even though today's only completion_rule already guarantees that.
This commit is contained in:
2026-08-18 14:35:11 -05:00
parent b908ade8e0
commit 0beb0e8f5e
2 changed files with 79 additions and 0 deletions
@@ -0,0 +1,19 @@
-- Persistent completion records — stage/curriculum/assessment/capstone. Not a certificate
-- (Phase 4/5 territory, see docs/PHASE3B_LEARNING_AND_ASSESSMENT.md): just the durable fact
-- that something was achieved, with enough context to render a certificate from later without
-- re-deriving it from raw attempt history.
CREATE TABLE IF NOT EXISTS achievements (
achievement_id BIGSERIAL PRIMARY KEY,
student_id TEXT NOT NULL REFERENCES students(student_id),
achievement_type TEXT NOT NULL CHECK (achievement_type IN
('stage_completed', 'curriculum_completed', 'assessment_completed', 'capstone_completed')),
curriculum_path_id TEXT,
curriculum_version INTEGER,
stage_id TEXT,
assessment_session_id UUID REFERENCES assessment_sessions(assessment_session_id),
achieved_at TIMESTAMPTZ NOT NULL DEFAULT now(),
metadata JSONB
);
CREATE INDEX IF NOT EXISTS idx_achievements_student ON achievements(student_id, achievement_type);