feat(exam9): link tasks to textbook + difficulty-ordered random + topic exclusion

Practice (random) now picks tasks by ascending difficulty so the first
slot is always level 1 and the session ramps up. Adds ?exclude= to drop
specific subtopics from the random pool, with a per-section checkbox
modal in the UI.

Each task carries a topic_ref (textbook chapter + paragraph) shown as
a 'Учить тему · §N' button next to the solution, deep-linking to the
right section of /textbook/<slug>. Mapping seeded for all 15 math9
subtopics in migration 028.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Maxim Dolgolyov
2026-05-29 14:55:47 +03:00
parent 441321c598
commit 3cc52e21b0
5 changed files with 386 additions and 9 deletions
@@ -0,0 +1,43 @@
-- ═══════════════════════════════════════════════════════════════
-- 028: Link exam_topics → textbook chapter + paragraph
--
-- Adds two columns to exam_topics:
-- textbook_slug — slug of the textbook chapter (e.g. 'algebra-9-ch3')
-- textbook_paragraph — paragraph number inside that chapter (NULL → no anchor)
--
-- The frontend builds a link like
-- /textbook/<slug> (when paragraph is NULL)
-- /textbook/<slug>#sec-pN (when paragraph = N)
-- so a student who fails an exam task is sent straight to the right §.
--
-- Mapping covers math9 subtopics. Sections (parent_slug IS NULL) are
-- left without a textbook_slug — the per-task link is driven by the
-- specific subtopic, not the section.
-- ═══════════════════════════════════════════════════════════════
ALTER TABLE exam_topics ADD COLUMN textbook_slug TEXT;
ALTER TABLE exam_topics ADD COLUMN textbook_paragraph INTEGER;
-- ── math9 ───────────────────────────────────────────────────────
-- Algebra
UPDATE exam_topics SET textbook_slug = 'algebra-9-ch1', textbook_paragraph = 5 WHERE slug = 'alg-expressions';
UPDATE exam_topics SET textbook_slug = 'algebra-9-ch1', textbook_paragraph = 3 WHERE slug = 'alg-fractions';
UPDATE exam_topics SET textbook_slug = 'algebra-9-ch2', textbook_paragraph = 6 WHERE slug = 'alg-functions';
UPDATE exam_topics SET textbook_slug = 'algebra-9-ch3', textbook_paragraph = 10 WHERE slug = 'alg-equations';
UPDATE exam_topics SET textbook_slug = 'algebra-9-ch3', textbook_paragraph = 13 WHERE slug = 'alg-inequalities';
UPDATE exam_topics SET textbook_slug = 'algebra-9-ch4', textbook_paragraph = 15 WHERE slug = 'alg-progressions';
-- Topics that aren't covered by a single Grade-9 paragraph — link to hub.
UPDATE exam_topics SET textbook_slug = 'algebra-9' WHERE slug IN (
'alg-numbers', 'alg-arithmetic', 'alg-powers',
'alg-polynomials', 'alg-word-problems'
);
-- Geometry
UPDATE exam_topics SET textbook_slug = 'geometry-9-ch1', textbook_paragraph = 1 WHERE slug = 'geom-triangles';
UPDATE exam_topics SET textbook_slug = 'geometry-9-ch2', textbook_paragraph = 9 WHERE slug = 'geom-quadrilaterals';
UPDATE exam_topics SET textbook_slug = 'geometry-9-ch2', textbook_paragraph = 7 WHERE slug = 'geom-circle';
-- Coordinates / circle-equation lives in algebra-9 ch3 §12 (уравнение окружности)
UPDATE exam_topics SET textbook_slug = 'algebra-9-ch3', textbook_paragraph = 12 WHERE slug = 'geom-coordinates';
-- theory-statements has no single textbook home — leave NULL.