126 lines
6.0 KiB
SQL
126 lines
6.0 KiB
SQL
-- ═══════════════════════════════════════════════════════════════
|
|
-- 022: Exam Preparation Module
|
|
--
|
|
-- Generic exam preparation infrastructure parameterized by exam_key.
|
|
-- Supports multiple exams (math9, phys9, chem9, math11ce, etc.) sharing
|
|
-- the same task bank, attempts tracking, mock sessions, and study plans.
|
|
--
|
|
-- See docs/exam-prep-plan.md for full architecture.
|
|
-- ═══════════════════════════════════════════════════════════════
|
|
|
|
-- ── Exam tracks registry ────────────────────────────────────────
|
|
CREATE TABLE exam_tracks (
|
|
exam_key TEXT PRIMARY KEY,
|
|
title TEXT NOT NULL,
|
|
subject_slug TEXT NOT NULL,
|
|
grade INTEGER NOT NULL,
|
|
duration_min INTEGER NOT NULL,
|
|
tasks_per_variant INTEGER NOT NULL,
|
|
variants_count INTEGER NOT NULL,
|
|
scoring_json TEXT,
|
|
intro_html TEXT,
|
|
enabled INTEGER NOT NULL DEFAULT 1,
|
|
sort_order INTEGER NOT NULL DEFAULT 0
|
|
);
|
|
|
|
-- ── Task bank (one row per task across all variants) ────────────
|
|
CREATE TABLE exam_tasks (
|
|
id INTEGER PRIMARY KEY,
|
|
exam_key TEXT NOT NULL REFERENCES exam_tracks(exam_key) ON DELETE CASCADE,
|
|
variant INTEGER NOT NULL,
|
|
task_idx INTEGER NOT NULL,
|
|
task_type TEXT NOT NULL CHECK (task_type IN ('mc','open','long')),
|
|
text_html TEXT NOT NULL,
|
|
figure_html TEXT,
|
|
opts_json TEXT,
|
|
answer TEXT,
|
|
solution_html TEXT NOT NULL,
|
|
topic TEXT,
|
|
subtopic TEXT,
|
|
difficulty INTEGER,
|
|
UNIQUE(exam_key, variant, task_idx)
|
|
);
|
|
CREATE INDEX idx_exam_tasks_topic ON exam_tasks(exam_key, topic);
|
|
CREATE INDEX idx_exam_tasks_variant ON exam_tasks(exam_key, variant);
|
|
CREATE INDEX idx_exam_tasks_type ON exam_tasks(exam_key, task_type);
|
|
|
|
-- ── User attempts ───────────────────────────────────────────────
|
|
CREATE TABLE exam_attempts (
|
|
id INTEGER PRIMARY KEY,
|
|
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
exam_task_id INTEGER NOT NULL REFERENCES exam_tasks(id) ON DELETE CASCADE,
|
|
user_answer TEXT,
|
|
is_correct INTEGER,
|
|
time_ms INTEGER,
|
|
mode TEXT NOT NULL CHECK (mode IN ('practice','variant','topic','mock')),
|
|
session_id INTEGER,
|
|
hint_used INTEGER NOT NULL DEFAULT 0,
|
|
solution_viewed INTEGER NOT NULL DEFAULT 0,
|
|
created_at INTEGER NOT NULL
|
|
);
|
|
CREATE INDEX idx_exam_attempts_user_time ON exam_attempts(user_id, created_at DESC);
|
|
CREATE INDEX idx_exam_attempts_task ON exam_attempts(exam_task_id);
|
|
CREATE INDEX idx_exam_attempts_session ON exam_attempts(session_id);
|
|
CREATE INDEX idx_exam_attempts_user_task ON exam_attempts(user_id, exam_task_id, created_at DESC);
|
|
|
|
-- ── Mock exam sessions ──────────────────────────────────────────
|
|
CREATE TABLE exam_mock_sessions (
|
|
id INTEGER PRIMARY KEY,
|
|
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
exam_key TEXT NOT NULL,
|
|
variant INTEGER,
|
|
source TEXT NOT NULL CHECK (source IN ('variant','random','weak-topics')),
|
|
task_ids_json TEXT NOT NULL,
|
|
started_at INTEGER NOT NULL,
|
|
finished_at INTEGER,
|
|
duration_planned_min INTEGER NOT NULL,
|
|
score INTEGER,
|
|
total_correct INTEGER,
|
|
total_tasks INTEGER,
|
|
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active','finished','abandoned'))
|
|
);
|
|
CREATE INDEX idx_mock_user ON exam_mock_sessions(user_id, started_at DESC);
|
|
|
|
-- ── User preparation plan ───────────────────────────────────────
|
|
CREATE TABLE exam_user_plan (
|
|
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
exam_key TEXT NOT NULL,
|
|
exam_date TEXT NOT NULL,
|
|
daily_target INTEGER NOT NULL DEFAULT 10,
|
|
weak_focus INTEGER NOT NULL DEFAULT 1,
|
|
created_at INTEGER NOT NULL,
|
|
updated_at INTEGER NOT NULL,
|
|
PRIMARY KEY (user_id, exam_key)
|
|
);
|
|
|
|
-- ── Topic dictionary (populated in F6) ──────────────────────────
|
|
CREATE TABLE exam_topics (
|
|
slug TEXT PRIMARY KEY,
|
|
exam_key TEXT NOT NULL,
|
|
parent_slug TEXT,
|
|
title TEXT NOT NULL,
|
|
description TEXT,
|
|
sort_order INTEGER NOT NULL DEFAULT 0
|
|
);
|
|
CREATE INDEX idx_topics_exam ON exam_topics(exam_key, parent_slug);
|
|
|
|
-- ── Seed: math9 track ───────────────────────────────────────────
|
|
-- Placeholder scoring grid (simple proportional). Replace with the actual
|
|
-- Belarus 9th-grade math exam grid once published per academic year.
|
|
INSERT INTO exam_tracks (
|
|
exam_key, title, subject_slug, grade, duration_min,
|
|
tasks_per_variant, variants_count, scoring_json, intro_html, enabled, sort_order
|
|
) VALUES (
|
|
'math9',
|
|
'Экзамен 9 класс — Математика',
|
|
'math',
|
|
9,
|
|
180,
|
|
10,
|
|
80,
|
|
'[{"correct":30,"score":10},{"correct":27,"score":9},{"correct":24,"score":8},{"correct":21,"score":7},{"correct":18,"score":6},{"correct":15,"score":5},{"correct":12,"score":4},{"correct":9,"score":3},{"correct":6,"score":2},{"correct":3,"score":1},{"correct":0,"score":0}]',
|
|
'<p>Полная подготовка к выпускному экзамену по математике за 9 класс. 80 реальных вариантов, разбор каждого задания, тренажёр по темам, пробные экзамены с таймером.</p>',
|
|
1,
|
|
10
|
|
);
|