diff --git a/.claude/memory/MEMORY.md b/.claude/memory/MEMORY.md new file mode 100644 index 0000000..187c33b --- /dev/null +++ b/.claude/memory/MEMORY.md @@ -0,0 +1,78 @@ +# LearnSpace Project Memory + +- [project_status.md](project_status.md) — Полный список реализованных фич: все страницы, API, таблицы БД, инструменты доски, стек, деплой (апрель 2026) +- [project_classroom_module.md](project_classroom_module.md) — Оригинальный план classroom-модуля (4 фазы, все реализованы) +- [project_whiteboard_roadmap.md](project_whiteboard_roadmap.md) — Roadmap улучшений доски (7 фаз, утверждён 2026-04-11) +- [project_pet_assistant.md](project_pet_assistant.md) — «Квантик-ассистент» РЕАЛИЗОВАН (commit 3f8009c): Ф0/Ф1/«Спроси-FAQ», правиловый движок, reuse 'pet', assistant_seen, на учебнике тоже. НЕ сделано: Ф2 тур, реальная LLM, activeLesson +- [feedback_no_emoji.md](feedback_no_emoji.md) — Запрет эмоджи в коде, только inline SVG `.ic` +- [feedback_sims_admin_sync.md](feedback_sims_admin_sync.md) — При добавлении симуляции в lab.html → сразу обновить ADMIN_SIMS в admin.html +- [project_ct_seeded.md](project_ct_seeded.md) — Список перенесённых сборников ЦТ/ЦЭ (физика 2024 + матем 2024); правило: 1 вариант из сборника, нет повторов +- [project_hardening_2026.md](project_hardening_2026.md) — 8-task security/architecture hardening plan (started 2026-05-06), executed by Sonnet sessions one task at a time +- [reference_textbook_sources.md](reference_textbook_sources.md) — Расположение PDF учебников Беларуси (физика/алгебра/геометрия 7-11) в `G:\Dev\Тесты\Методички\тест_6 класс\Книги\` + структура §-канвы Исаченковой +- [project_stereo3d_improvements.md](project_stereo3d_improvements.md) — Стереометрия 3D: апгрейд 5 фаз (май 2026) + deep-link фигур `openSim('stereo:
')` / `?stereofig=` +- [reference_sqlite_node.md](reference_sqlite_node.md) — БД на встроенном node:sqlite (НЕ better-sqlite3); живая БД backend/data/learnspace.db; Bash ломает кириллический путь +- [reference_textbook_latex_escaping.md](reference_textbook_latex_escaping.md) — Баг формул = ЛИШНИЕ слэши (over-escape), правило чётности, фикс fix_overescaped_latex.js; БД чиста +- [project_content_access.md](project_content_access.md) — Доступ к учебникам/экзаменам/симуляциям/курсам по классам и ученикам (allowlist, ученик > класс), миграции 040/051/052, /api/access; ревью+переработка done, Фаза 3 (HTML-гейт) отложена +- [project_permissions_rework.md](project_permissions_rework.md) — Ролевые права (registry/role_permissions/user_permissions): Phase A+B+C ВСЕ в master (2026-06-03): зависимости, история, группы, массово по классу, пресеты, временные права, произвольные кастомные роли (конструктор). План plans/permissions-rework/ +- [project_optics_constructor.md](project_optics_constructor.md) — Конструктор оптических систем (BenchSim) в режиме «Конструктор» оптической скамьи: общий 2D-трассировщик, элементы/призма/дисперсия +- [project_lab_content_engine.md](project_lab_content_engine.md) — Рефактор лаборатории «симуляции как данные» (LabRegistry); фазы 0-3 done, ветка feature/lab-content-engine +- [project_chemistry7_textbook.md](project_chemistry7_textbook.md) — Новый учебник «Химия 7» (4 гл, 26§): план + статус (Phase 0 done), переиспользует движок Химии 8 +- [project_concurrent_sessions_branch.md](project_concurrent_sessions_branch.md) — Несколько сессий коммитят в одну ветку → fetch перед работой, не force-push вслепую, add поимённо +- [feedback_verify_edits_applied.md](feedback_verify_edits_applied.md) — После каждого Edit проверять grep -c маркера; не пушить пакет без поштучной верификации (дважды коммитил сломанное) +- [project_dashboard_rebuild.md](project_dashboard_rebuild.md) — План пересборки dashboard.html по скрину (hero: чтение+лаба+питомец, синхрон питомца); редизайн утерян (был некоммичен) +- [project_phys7_status.md](project_phys7_status.md) — Физика 7: контент ВСЕХ 5 глав готов (рендер из phys7_chN_widgets.js); Шпаргалки наполнены (47 шт, commit c6835cf); учебник функционально полный +- [reference_vex_search.md](reference_vex_search.md) — vex установлен+проиндексирован (semantic); когда vex (semantic/pattern/similar/duplicates), когда ast-index (символы/usages); гочи модели/HEAD +- [project_math6_textbook.md](project_math6_textbook.md) — Учебник «Математика 6» (Герасимов 2022): движок math6_engine.js + Math6 svg (numberLine/plane/pie/venn). ВСЕ 6 глав + курсовой финал ГОТОВЫ на master (тесты 17/17, +полировка 20/20). Осталось только: выдать доступ ученикам (/api/access) +- [project_math5_textbook.md](project_math5_textbook.md) — Учебник «Математика 5» (Герасимов 2020) переиспользует движок math6. НАПОЛНЕН ЦЕЛИКОМ: 3 главы, 44 § (Гл.1 Opus-эталон, Гл.2–3 Sonnet), хаб+курсовой финал, тест 12/12, всё на master (последний 5a2a1be). Осталось только: выдать доступ ученикам (/api/access). План: plans/textbooks-5/ +- [reference_exam_textbook_links.md](reference_exam_textbook_links.md) — Привязка задач экзамена math9 к § учебников: per-task колонки в exam_tasks + классификатор tag-exam-textbook.js (таксономия gen-exam-textbook-sections.js) + починенный deep-link (textbook-deeplink.js). 98% размечено. Готчи: geometry-8 поглавная нумерация, math5/6 движковые +- [reference_svg_drawer.md](reference_svg_drawer.md) — Векторная SVG-рисовалка: виджет js/svg-draw.js (SvgDraw.mount) + санитайзер js/svg-sanitize.js (UMD, клиент+сервер) + блок урока svg-draw (редактор/превью/lesson.html). Переиспользуемо для флешкарт/фигур генератора +- [reference_quick_lesson.md](reference_quick_lesson.md) — «Быстрый урок»: одиночный урок без курса через скрытый личный курс-контейнер (courses.is_personal, POST /api/lessons/quick, кнопка в theory.html). Каталог скрывает контейнеры от всех кроме владельца +- [reference_student_materials.md](reference_student_materials.md) — «Мои материалы»: ученик сохраняет к себе доску(PNG)/заметку из онлайн-урока (миграция 060 student_materials, /api/materials, Whiteboard.exportBlob, страница /my-materials, кнопки в my-lessons.html). Копия переживает удаление сессии + +## Stack +- Node.js/Express backend, SQLite (встроенный **node:sqlite** `DatabaseSync`, НЕ better-sqlite3 — см. [[reference_sqlite_node]]) +- Frontend: vanilla JS, `window.LS.*` namespace via /js/api.js +- No bundler — plain HTML/CSS/JS served by Express static +- Репо: https://git.dolgolyov-family.by/maxim.dolgolyov/Learn_System (master) + +## Key Paths +- Backend: `backend/src/` +- Frontend pages: `frontend/*.html` +- Shared CSS: `frontend/css/ls.css` (design system) +- JS API: `js/api.js` → `window.LS.*` +- Whiteboard engine: `frontend/js/whiteboard.js` (~3200 строк) +- Server entry: `backend/src/server.js` + +## UI Architecture +- Sidebar nav: `.app-layout > .sidebar + .sb-content` +- login.html: split layout `.login-layout > .login-left + .login-right` +- Page transitions: CSS `@view-transition { navigation: auto }` +- Mobile: `.mob-bar` (56px fixed top), sidebar drawer на ≤768px, `/js/mobile.js` +- Notifications dropdown: `left` ставится через `r.right + 8` динамически + +## Whiteboard (classroom.html) +- Chalkboard theme: зелёный фон (#2d5a2d), деревянная рамка, chalk-grain +- Tools: pencil (Catmull-Rom), highlighter, laser, eraser, 11 shapes, connector, sticky, text, image, formula (KaTeX), table, coordinate system, number line, compass +- Select tool: move/resize/rotate всех объектов, lasso multi-select, snap guides, copy/paste +- Zoom/Pan: wheel zoom, Space+drag, minimap overlay (bottom-right, при zoom>1) +- Ruler/Protractor: rotation + resize handles, floating props panel +- SSE real-time sync + HTTP polling (since_seq параметр) +- Two-layer canvas: static (_ctx) + dynamic (_dynCtx) +- Multi-page + thumbnail sidebar + +## User Roles +- admin: full access +- teacher: classes + board + library + classroom +- student: dashboard + board (только если в классе) + +## Icons — КРИТИЧНО +- **⛔ ЗАПРЕТ на эмоджи** — никогда не использовать эмоджи в коде. +- Только inline SVG с классом `.ic` (определён в ls.css). +- На некоторых страницах также Lucide CDN `lucide@0.469.0`. + +## Workflow Preferences — КРИТИЧНО +- **⛔ АБСОЛЮТНЫЙ ЗАПРЕТ на Grep tool** — пользователь запретил КАТЕГОРИЧЕСКИ. +- Поиск по коду: `ast-index` (дефолт: символы/usages/callers/outline) + `vex` (semantic/pattern/similar/duplicates) — см. [[reference_vex_search]] / `.claude/rules/search-tools.md`. usages по JS — только ast-index. +- Чтение файлов: ТОЛЬКО `Read` с offset/limit +- Поиск файлов: `Glob` или `ast-index search` +- НЕТ ИСКЛЮЧЕНИЙ. Даже для "быстрой проверки". Даже для верификации. diff --git a/.claude/memory/README.md b/.claude/memory/README.md new file mode 100644 index 0000000..bf2c47a --- /dev/null +++ b/.claude/memory/README.md @@ -0,0 +1,55 @@ +# Файлы памяти Claude (перенос между машинами) + +Здесь собраны файлы автопамяти Claude Code для этого проекта, чтобы их можно было +переносить через git и работать на другой машине. + +`MEMORY.md` — индекс (загружается в контекст каждой сессии). Остальные `.md` — +по одному факту на файл (см. frontmatter `metadata.type`: user / feedback / project / reference). + +## Как это работает + +Claude Code хранит память не в репозитории, а в пользовательской папке, привязанной +к пути проекта: + +``` +<домашняя папка>/.claude/projects/<хэш-пути-проекта>/memory/ +``` + +На этой машине это: +`C:\Users\Home\.claude\projects\g--Dev-------BQ-System\memory\` + +Хэш `g--Dev-------BQ-System` получается из абсолютного пути проекта +(`g:\Dev\Тесты\BQ-System`), где не-буквенно-цифровые символы заменены на дефис. + +## Восстановление на другой машине + +1. Склонируй репозиторий (память приедет в `.claude/memory/`). +2. Определи целевую папку памяти: + - **Если путь проекта тот же** (`g:\Dev\Тесты\BQ-System`) — папка та же: + `~/.claude/projects/g--Dev-------BQ-System/memory/`. + - **Если путь другой** — открой проект в Claude Code один раз (он создаст папку + `~/.claude/projects/<новый-хэш>/memory/`), либо вычисли хэш из своего пути по + правилу выше. +3. Скопируй туда все `.md` из `.claude/memory/` (включая `MEMORY.md`). + +PowerShell-пример (путь проекта тот же): + +```powershell +$dst = "$env:USERPROFILE\.claude\projects\g--Dev-------BQ-System\memory" +New-Item -ItemType Directory -Force -Path $dst | Out-Null +Copy-Item ".\.claude\memory\*.md" $dst -Force +``` + +bash-пример (Linux/macOS, путь проекта тот же): + +```bash +dst="$HOME/.claude/projects/g--Dev-------BQ-System/memory" +mkdir -p "$dst" && cp .claude/memory/*.md "$dst"/ +``` + +## Поддержание в актуальном состоянии + +Это **снимок**. Когда Claude обновляет память во время работы, меняются файлы в +пользовательской папке, а не здесь. Чтобы снова синхронизировать в репозиторий — +скопируй из пользовательской папки обратно в `.claude/memory/` и закоммить +(или попроси Claude «обнови снимок памяти в репозитории»). diff --git a/.claude/memory/feedback_no_emoji.md b/.claude/memory/feedback_no_emoji.md new file mode 100644 index 0000000..e4c09dd --- /dev/null +++ b/.claude/memory/feedback_no_emoji.md @@ -0,0 +1,14 @@ +--- +name: no_emoji_use_svg +description: Never use emoji in code — always use inline SVG icons instead +type: feedback +--- + +Никогда не использовать эмоджи в коде. Вместо эмоджи всегда использовать inline SVG иконки с классом `.ic` (определён в bq.css). + +Примеры замен: +- ✓ → `` +- ⚠ → `...` +- Любая другая иконка → соответствующий Lucide SVG path + +CSS класс `.ic` в bq.css: `display:inline-block; width:1em; height:1em; fill:none; stroke:currentColor; stroke-width:2.5; stroke-linecap:round; stroke-linejoin:round` diff --git a/.claude/memory/feedback_sims_admin_sync.md b/.claude/memory/feedback_sims_admin_sync.md new file mode 100644 index 0000000..015cbb9 --- /dev/null +++ b/.claude/memory/feedback_sims_admin_sync.md @@ -0,0 +1,11 @@ +--- +name: Симуляции — синхронизация с панелью администратора +description: При добавлении новой симуляции в lab.html нужно сразу же обновить ADMIN_SIMS в admin.html +type: feedback +originSessionId: 1959f491-c6c4-4d6b-9081-0b09298d1699 +--- +При добавлении новой симуляции (нового элемента массива `SIMS` в `frontend/lab.html`) — **сразу же** добавлять соответствующую запись в массив `ADMIN_SIMS` в `frontend/admin.html` (строки ~4463). + +**Why:** Пользователь обнаружил, что Гидростатика (`hydrostatics`) и другие симуляции (`mirrors`, `isoprocess`, `waves`) были в lab.html, но отсутствовали в панели администратора. Это приводит к тому, что администратор не может управлять этими симуляциями. + +**How to apply:** Структура записи: `{ id: '', cat: '<Категория>', title: '<Название>' }`. Категории в ADMIN_SIMS: `Математика`, `Физика`, `Химия`, `Биология`, `Игры`. Добавлять в той же последовательности, что и в SIMS lab.html. diff --git a/.claude/memory/feedback_verify_edits_applied.md b/.claude/memory/feedback_verify_edits_applied.md new file mode 100644 index 0000000..b6cce59 --- /dev/null +++ b/.claude/memory/feedback_verify_edits_applied.md @@ -0,0 +1,20 @@ +--- +name: feedback_verify_edits_applied +description: "После каждого Edit проверять, что он реально применился (grep -c маркера); не пушить пакет без поштучной верификации" +metadata: + node_type: memory + type: feedback + originSessionId: 4e9fb8e3-3745-4f02-9d88-40b13d0cb4ca +--- + +# Проверять, что Edit реально применился — особенно при пакетных правках + +В этой кодовой базе при пакетном выполнении нескольких Edit подряд легко не заметить, что часть упала с «String to replace not found» (неверный отступ/перенумерация линтером/чужая сессия). Дважды это привело к коммиту и push СЛОМАННОГО состояния (Фаза 0 и Фаза 3 контент-движка лаборатории): зависимые правки в разных файлах применились частично → рантайм-ошибки, пойманные только независимым ревью. + +**Why:** Edit-тул возвращает ошибку, но в потоке из 10+ параллельных вызовов её легко пропустить; pre-commit хук ловит синтаксис/эмодзи, но НЕ логическую неполноту. + +**How to apply:** +- После КАЖДОГО смыслового Edit подтверждать применение: `grep -c "<уникальный маркер нового кода>" <файл>` (ожидать >0). +- Файлы лаборатории (lab-init.js, lab-glue.js, lab.html, _register-all.js) часто перенумеровываются линтером/[[project_concurrent_sessions_branch]] — перечитывать прямо перед Edit, копировать точный текст с отступами. +- Не делать `git commit`+`push` пакетом, пока каждый edit не верифицирован отдельно. Для критичных изменений — исполняемый vm/node-harness (а не только node --check), он ловит «функция не вызывается / не подключена». +- Связано: [[project_lab_content_engine]] (рефактор, где это всплыло). diff --git a/.claude/memory/image-extraction.md b/.claude/memory/image-extraction.md new file mode 100644 index 0000000..897bdce --- /dev/null +++ b/.claude/memory/image-extraction.md @@ -0,0 +1,80 @@ +# Image Extraction from PDF — ЦТ/ЦЭ Questions + +## Tools available +- **pdftoppm** (poppler, via scoop): renders PDF pages to PNG +- **sharp** (npm, installed in `backend/`): crops images in Node.js +- Script: `backend/src/db/crop_images.js` + +## Workflow for extracting figures from exam PDF + +### Step 1 — Render pages at 200 DPI +```bash +pdftoppm -png -r 200 -f -l "path/to/file.pdf" "/tmp/prefix" +# Output: /tmp/prefix-06.png, /tmp/prefix-07.png ... +# Copy to: frontend/img/questions/pageN.png +``` + +### Step 2 — Calibrate coordinates using 72 DPI reference +```bash +pdftoppm -png -r 72 -f -l "path/to/file.pdf" "/tmp/pt" +# Output: /tmp/pt-06.png etc. (614×844 px for A4) +# Copy to: frontend/img/questions/ptN.png +``` + +At 72 DPI: A4 = 614×844 px. Scale to 200 DPI: **×2.777** +Measure coordinates visually on 72 DPI images, multiply by 2.777 to get 200 DPI coords. + +### Step 3 — Test crops (Node.js) +```javascript +// Run from backend/ folder +const sharp = require('sharp'); +sharp('../frontend/img/questions/pt6.png') + .extract({ left: 220, top: 80, width: 200, height: 100 }) + .toFile('../frontend/img/questions/test.png'); +``` + +### Step 4 — Run crop_images.js +```bash +cd backend && node src/db/crop_images.js +``` + +--- + +## ЦТ 2021 — Variant 1 crop coordinates (200 DPI, 1705×2344) + +| File | Question | Source page | left | top | width | height | +|------|----------|-------------|------|-----|-------|--------| +| ct2021v1_a1.png | A1 triangle | page6.png | 611 | 222 | 556 | 292 | +| ct2021v1_a7.png | A7 graph f(x) | page6.png | 278 | 1222| 750 | 403 | +| ct2021v1_a15.png | A15 parabola | page7.png | 556 | 917 | 695 | 278 | +| ct2021v1_a17.png | A17 grid A,B | page7.png | 861 | 1439| 639 | 194 | +| ct2021v1_a18.png | A18 pyramid | page7.png | 389 | 1656| 945 | 472 | +| ct2021v1_b1.png | B1 bar chart | page8.png | 28 | 83 | 1167| 556 | +| ct2021v1_b3.png | B3 3D planes | page8.png | 1015| 1717| 319 | 417 | +| ct2021v1_b4.png | B4 enclosure | page9.png | 945 | 14 | 542 | 208 | + +PDF source: `ЦТ-ЦЭ/ЦТ 2021.pdf` +- Page 6 = Variant 1, Part A (A1–A11) +- Page 7 = Variant 1, Part A (A12–A18) +- Page 8 = Variant 1, Part B (B1–B3) +- Page 9 = Variant 1, Part B (B4–B14) + +Images stored: `frontend/img/questions/ct2021v1_*.png` +Served at: `/img/questions/ct2021v1_*.png` (via express.static on frontendDir) + +--- + +## DB: updating image field after seeding +```javascript +const upd = db.prepare('UPDATE questions SET image = ? WHERE text LIKE ? AND year = ?'); +upd.run('/img/questions/ct2021v1_a1.png', '[ЦТ 2021 · A1]%', 2021); +``` + +--- + +## Notes +- PDF contains scanned raster images — no extractable vector graphics +- Each PDF page = one large bitmap scan +- `pdfimages` extracts only full-page bitmaps (not individual diagram crops) +- sharp must be required from `backend/` directory (installed there) +- Temp page renders NOT committed to git — regenerate with pdftoppm when needed diff --git a/.claude/memory/project_chemistry7_textbook.md b/.claude/memory/project_chemistry7_textbook.md new file mode 100644 index 0000000..b7be994 --- /dev/null +++ b/.claude/memory/project_chemistry7_textbook.md @@ -0,0 +1,44 @@ +--- +name: project_chemistry7_textbook +description: "Новый интерактивный учебник «Химия 7» (Беларусь, Шиманович 2023): план + статус фаз, архитектура (переиспользование движка Химии 8)" +metadata: + node_type: memory + type: project + originSessionId: f74d8a9a-17bc-40a4-b458-4a5b596a07f2 +--- + +Создаём интерактивный учебник **«Химия 7»** (Беларусь, Шиманович и др., 2023) — первый курс химии. План: `plans/textbooks-7/PLAN_CHEMISTRY_7.md`. Программа из книги (PDF `himiya_7kl_shimanovich_rus_2023 (1).pdf` в [[reference_textbook_sources]], TOC на стр. 3–4): **4 главы, 26 §, 5 лаб. опытов, 4 практ. работы**. Гл.I Первоначальные понятия §1–12, Гл.II Кислород §13–17, Гл.III Водород §18–22, Гл.IV Вода §23–26. + +**Why:** закрывает нижнюю ступень химии (линейка 7→8→9). 7 класс — качественный курс (валентность, а не степень окисления; `M_r` без моля; без ПЗ/строения атома/ТЭД — это [[project_lab_content_engine]]… нет, это Химия 8). + +**How to apply (ключевая архитектура — НЕ дублировать):** движок Химии 8 **полностью переиспользуется** для Химии 7. Страница главы лишь объявляет `window.CHEM8_CFG`/`PARAS`/`BUILDERS`/`POOLS`/`SIDEBARS`/`TIPS`/`ACH_LABELS` и подключает общие `/js/chem8_engine.js` + `/css/chem8-textbook.css` + `/js/chem8_svg.js` (`window.Chem8`) + `/js/biochem-core.js`. Свой только `/js/chem7_svg.js` (`window.Chem7` — тонкая надстройка над Chem8) и страницы. `/textbook/` → `frontend/textbooks/` (html_path из БД). Прогресс/XP/ачивки — автоматически движком; ключи localStorage `chemistry7_*`. + +**Статус (2026-05-30): ВЕСЬ КОНТЕНТ ГОТОВ — все 26 § наполнены** (Phases 0–4, последний коммит 7574d16, ветка feature/lab-content-engine). Глава 3 «Водород» (§§18–22 + ЛО3,4 + ПР3, виджеты `chem7_ch3_widgets.js`: паспорт H₂, реакции водорода, индикаторы кислот, ряд активности, опыт металл+кислота, конструктор солей, проверка чистоты H₂) и Глава 4 «Вода» (§§23–26 + ЛО5 + ПР4, `chem7_ch4_widgets.js`: разложение воды 2:1, конструктор оснований, индикаторы щёлочи, нейтрализация, экология) — ГОТОВЫ. У всех 4 глав финалы по 6 боссов; курсовой финал (8 боссов + ачивка «Химик 7 класса») в хабе. Тесты chem7: **15/15 pass**; полный прогон **161/164** (3 — baseline Auth). Учебник появляется в каталоге `/api/textbooks` автоматически (is_active=1, parent_slug=NULL). + +**Визуальный апгрейд (анимации):** план `plans/textbooks-7/PLAN_CHEMISTRY_7_VISUAL.md` (~15 флагманов, фазы V0–V5). **V0+пилот V1 ГОТОВЫ** (коммит f620562): движок `frontend/js/chem7_anim.js` (`window.Chem7Anim`: `loop` с IntersectionObserver-паузой, `molecule3d` SVG-вращение+drag, `separation` canvas-частицы, `colorMorph`, `confettiSmall`; **headless-guard** `navigator.userAgent~jsdom` — canvas getContext НЕ зовётся в тестах, молекулы на SVG → jsdom-safe; IntersectionObserver guard). Пилот: §5/§6 → вращающиеся 3D-молекулы (`molViewer`+`MOL` в chem7_ch1_widgets.js), §2/ПР1 → анимация разделения смесей при верном методе. Тест `ch1 V-пилот` зелёный (16/16). **Готово: V0 + V1 (Гл.1) + V2 §15 (горение).** Движок дополнен CSS-хелперами (jsdom-safe): `bubbleField`/`precipField`/`flameBox`/`colorBlock` (+ инжект keyframes). V1 анимировано: §2/ПР1 разделение (canvas `separation`), §5/§6 3D-молекулы (`molViewer`+`MOL`), §10/ЛО1 признаки (`demoAnim`: colorBlock/precip/flame/bubble), §11 осадок (`precipField`). V2: §15 горение — `flameBox` с цветом по веществу (C оранж, S синий, P бел., Fe/Mg искры); `chem7_anim.js` подключён в Гл.1 и Гл.2. Коммиты f620562, 41985a9, e8cb95b. +**Готово V0–V4: ВСЕ 4 главы анимированы** (коммиты …e8cb95b, 33f968b, 639f985). `chem7_anim.js` подключён во все 4 главы. V3 (Гл.3): §21 ряд активности → пузырьки H₂ (`bubbleField`)/«нет реакции» для Cu; §19 восстановление CuO → `colorBlock` чёрный→красный; §20/ЛО3 индикаторы → `colorBlock`. V4 (Гл.4): §23 электролиз → 2 потока пузырьков H₂(18)/O₂(9) = 2:1; §24/ЛО5 индикаторы щёлочи → `colorBlock`; §25/ПР4 нейтрализация → `colorBlock` малиновый→бесцветный. chem7-тест: **16/16** (3D-молекулы, разделение, признаки, осадок, горение, пузырьки, морфинг цвета, индикаторы, электролиз, титрование). +**V1-хвост ЗАКРЫТ** (коммит ac6552b): §9 — `Chem7Anim.valenceLink` (SVG «связи-крючки», draw-in); §12 — анимированный подсчёт атомов (реагенты vs продукты, точки появляются масштабом, баланс слева=справа). **ВСЕ интерактивы Химии 7 анимированы (V0–V4 + хвост).** chem7-тест 16/16. **Остаток (опционально):** звук (Web Audio: хлопок гремучего газа / пшик лучинки) — не делал; V5 reduced-motion и пауза вне экрана УЖЕ в движке. ВАЖНО при full-test: chem8 «intro» тест иногда флачит по таймингу под параллельной нагрузкой (не регрессия — проходит в изоляции). + +**КРИТИЧНО для тестов:** пакет `canvas` НЕ установлен → `getContext` в jsdom кидает «Not implemented» (ловится как jsdomError) → анимации на canvas ОБЯЗАНЫ иметь headless-guard. `jsdom` и `katex` стоят `--no-save` (любой `npm install` их пруннит — при пропаже восстановить `npm install --no-save jsdom katex`). + +**Осталось по контенту (опциональная полировка, Phase 5/6):** виджет глоссария `chem7_glossary.js` (по образцу chem8_glossary), проверка в браузере, выдача доступа ученикам ([[project_content_access]]), при желании — общий «большой финал»/карта связей. Функционально курс завершён. + +**Предыдущий статус (Phase 0+1+2):** + +**Phase 2 — Глава 2 «Кислород» (§§13–17 + ЛО2 + ПР2 + финал) ГОТОВА** (2 волны). Виджеты в `frontend/js/chem7_ch2_widgets.js`: §13 диаграмма состава воздуха, ЛО2 выбор собирания газа, §14 переключатель элемент/O₂/O₃ + модели (`molSvg`), §15 симулятор горения (C/S/P/Fe/Mg → оксид, через Chem8.chemEq), §16 конструктор оксида (валентность) + `Chem7Classify` (оксид/не оксид), §17 схема получения O₂ (катализатор), ПР2 тлеющая лучинка. 8 боссов финала курса в хабе уже работают. + +**⚠️ КРИТИЧНО — флака Cyrillic-FS (видел вживую):** под путём `G:\Dev\Тесты\…` инструмент **Edit иногда рапортует success, но запись НЕ персистится** (целый пакет из 6 Edit'ов молча не сохранился). Также `node --test ` и `node -e readFileSync(...)` периодически дают ENOENT/«Could not find» под кириллицей. ПРАВИЛО (см. [[feedback_verify_edits_applied]]): после пакета Edit'ов в файл под `Тесты\` — ОБЯЗАТЕЛЬНО проверить персист через `node -e \"h=fs.readFileSync(...); h.includes('маркер')\"` (Bash), и только потом коммитить. Тесты запускать через **`node -e \"require('./tests/chemistry7-page.test.js')\"`** (require резолвит кириллицу надёжнее, чем `--test `); при ENOENT — повторить (флака транзиентна). Read-state харнесса слетает после компакта → перед Edit может понадобиться повторный Read. + +**Phase 1 — Глава 1 «Первоначальные химические понятия» (§§1–12) наполнена ПОЛНОСТЬЮ** (4 волны): +теория (3 карточки/§), звёздные виджеты, тренажёры задач (POOLS), финал главы (6 боссов). Виджеты в `frontend/js/chem7_ch1_widgets.js` (CHEM8_WIDGETS/FLAG_MOUNTS): §1 классификатор тело/вещество, §2/ПР1 разделитель смесей, §3 каталог элементов + тренажёр символов, §4 весы атомов, §5 галерея молекул (SVG-шарики `molBalls`), §6 классификатор простое/сложное, §7 парсер формулы (Chem8.elementCounts), §8 калькулятор M_r (Chem8.molarMass), §9 конструктор формулы по валентности (НОК), §10/ЛО1 детектор признаков реакции, §11 весы сохранения массы, §12 балансировщик (Chem8.equationBalancer). Builder'ы build_pN — inline в `chemistry_7_ch1.html` (override заглушек). Тест `chemistry7-page.test.js`: 10/10 pass; полный прогон 156/159 (3 — baseline Auth). **Паттерн волны:** добавить build_pN+POOLS+SIDEBARS+TIPS+override в HTML + mount_pN в widgets-файл + тест + commit. + +**Phase 0 ГОТОВ** (коммит c33b4ab): +- миграция `046_chemistry7_hub.sql` применена (родитель `chemistry-7` 26§ + 4 ребёнка `chemistry-7-ch1..ch4`, палитра emerald/cyan/violet/blue); +- `frontend/textbooks/chemistry_7_hub.html` (emerald, 4 главы, финал курса 8 боссов, ачивка `chemistry7_course_master` «Химик 7 класса» +150 XP); +- `chemistry_7_ch1..ch4.html` — каркасы на общем движке; PARAS по реальной программе; **builder'ы пока заглушки** (para-hero + «содержание готовится» + кнопка прочтения), генерятся inline из PARAS; +- `frontend/js/chem7_svg.js` — Chem7 (стабы звёздных виджетов: valenceBuilder, mixtureSeparator, reactionSigns, massConservation, combustionSim, compoundBuilder, airComposition, waterDecomp, massFraction); +- тест `backend/tests/chemistry7-page.test.js` (6 тестов, все проходят). + +**Дальше:** Phase 1 — наполнить Гл.I §§1–12 реальным контентом (теория + интерактивы + POOLS), создать `chem7_ch1_widgets.js` (заменить inline-заглушки на build_pN + CHEM8_WIDGETS/FLAG_MOUNTS, как в `chem8_intro_widgets.js`). Затем Phase 2–4 (главы), Phase 5 финалы, Phase 6 качество/админка. + +**Тесты:** `cd backend && node --test tests/*.test.js`. ВАЖНО: Cyrillic-путь ломает запуск `node --test ` из PowerShell — запускать через Bash. Baseline: 3 pre-existing Auth-фейла (не трогать). См. [[reference_sqlite_node]], [[feedback_no_emoji]], [[project_concurrent_sessions_branch]]. diff --git a/.claude/memory/project_classroom_module.md b/.claude/memory/project_classroom_module.md new file mode 100644 index 0000000..edc6da0 --- /dev/null +++ b/.claude/memory/project_classroom_module.md @@ -0,0 +1,18 @@ +--- +name: Online Classroom Module Plan +description: План модуля онлайн-урока — доска, голосовой чат, трансляция экрана, личные сессии. 4 фазы. +type: project +originSessionId: 1959f491-c6c4-4d6b-9081-0b09298d1699 +--- +Модуль «Онлайн-урок» — план утверждён, реализация пока не начата. + +**Why:** Расширить LearnSpace до полноценной платформы онлайн-обучения с интерактивными уроками в реальном времени. + +**How to apply:** Полный план сохранён в `C:\Users\Home\.claude\plans\bubbly-booping-harp.md`. При начале реализации — использовать этот план как источник истины. + +Ключевые моменты: +- 4 фазы: (1) Сессия+Чат+Посещаемость, (2) Доска, (3) Фигуры+Многостраничность+Рука, (4) Голосовой чат+Экран (WebRTC mesh) +- Два режима сессии: с классом (emitToClass) и личная без класса (classroom_invites + emit) +- Архитектура: SSE + HTTP POST (доска, чат), WebRTC mesh (аудио, экран) +- Новые файлы: classroomController.js, classroom.js route, classroom.html, whiteboard.js, classroom-rtc.js +- 6 новых таблиц: classroom_sessions, classroom_pages, classroom_strokes, classroom_chat, classroom_attendance, classroom_invites diff --git a/.claude/memory/project_concurrent_sessions_branch.md b/.claude/memory/project_concurrent_sessions_branch.md new file mode 100644 index 0000000..d21321e --- /dev/null +++ b/.claude/memory/project_concurrent_sessions_branch.md @@ -0,0 +1,26 @@ +--- +name: project_concurrent_sessions_branch +description: "По ветке feature/lab-content-engine параллельно коммитят другие сессии — fetch перед работой, не force-push вслепую" +metadata: + node_type: memory + type: project + originSessionId: 4e9fb8e3-3745-4f02-9d88-40b13d0cb4ca +--- + +# Параллельные сессии пишут в ту же ветку + +На 2026-05-30 по ветке `feature/lab-content-engine` одновременно работали несколько сессий Claude: помимо контент-движка лаборатории ([[project_lab_content_engine]]) туда же коммитили biochem (Фазы 2/3/5/6), opticsbench-конструктор, учебники (chemistry-8). Это вызвало реальные проблемы: расхождение local/remote, откат моих правок lab.html (include-теги дважды), потребность в `--force-with-lease`. + +**Why:** Несколько агентов/сессий делят одну git-ветку и рабочее дерево — типичная причина «пропавших» правок и non-fast-forward при push. + +**How to apply:** +- Перед началом и перед push: `git fetch` + `git rev-list --left-right --count HEAD...origin/`. +- Если remote ушёл вперёд — НЕ force-push вслепую: сначала понять, что за коммиты (часто чужая сессия), и что local — content-superset. +- В рабочем дереве почти всегда лежат чужие незакоммиченные правки (api.js, *.html) — коммитить только СВОИ файлы поимённо, не `git add -A`. +- Правки в часто-редактируемых файлах (lab.html) перечитывать прямо перед Edit — линтер/чужая сессия перенумеровывают строки. +- Push на git.dolgolyov-family.by иногда даёт транзиентный «Failed to authenticate» — повторить. + +**Реальный инцидент (2026-05-30):** браузерные баги после Фаз 3-4 контент-движка. +1. `cirSim is not defined` в `_pauseAllSims()/closeSim()` (lab-init.js): Фаза 3 (ленивая загрузка) обнажила latent-баг — эти «дробовик»-функции ссылаются на глобалы экземпляров симуляций (cirSim/reacSim/newtonSim/…) по голому имени; раньше их объявляли sim-файлы (eager), теперь до открытия симуляции → ReferenceError. Фикс: предсоздать имена как window-свойства (null) в начале lab-init.js. (Изначально я ошибочно подумал, что проблема в theory-data.js/_pilots.js — их НЕ существует, THEORY остаётся inline в lab-init.js; те правки lab.html были no-op.) +2. `/api/lab/sims` 500 = `no such table: lab_sims`: миграция 042 применялась к ТЕСТОВЫМ temp-БД, но не к ЖИВОЙ (`backend/data/learnspace.db`). Сервер НЕ авто-мигрирует (только fail-fast проверка). Фикс: `node src/db/migrations-runner.js` на живой БД (применил, 40 строк) + graceful-degradation в lab.js (пустой каталог вместо 500). SQLite: таблица, созданная миграцией, видна работающему серверу без рестарта (DDL закоммичен в файл; prepare происходит на запрос). +Уроки: (а) после рефактора с ленивой загрузкой проверять, что глобал-ссылки в «дробовик»-функциях не указывают на now-lazy переменные; (б) НОВАЯ миграция требует прогона на ЖИВОЙ БД (`npm run migrate` в backend), а не только в тестах; (в) не выдумывать причину — сверять с error_log и фактическим наличием файлов. diff --git a/.claude/memory/project_content_access.md b/.claude/memory/project_content_access.md new file mode 100644 index 0000000..52e6b3c --- /dev/null +++ b/.claude/memory/project_content_access.md @@ -0,0 +1,76 @@ +--- +name: project_content_access +description: "Система доступа к учебникам/экзаменам по классам и ученикам из админ-панели (allowlist, ученик > класс)" +metadata: + node_type: memory + type: project + originSessionId: d08c4099-7d49-4f89-b842-d9d7af56af47 +--- + +Доступ к учебникам и экзамен-модулям («экзамен 9 класс» = exam_key `math9`) управляется из админ-панели (вкладка «Доступ к учебникам», группа **«Пользователи»**, рядом с «Права доступа»). Реализовано 2026-05-30. + +**Модель:** ALLOWLIST — по умолчанию закрыто, нужно явно открыть. Правило ученика важнее правила класса (точечные исключения). Управляют админ (все классы/ученики) и учителя (только свои классы и ученики своих классов / привязанные через teacher_students). + +**Why:** так выбрал пользователь (безопаснее). Миграция 040 при внедрении выдала всем существующим классам доступ к текущему контенту, чтобы переход не отнял доступ задним числом; новый контент по умолчанию закрыт. + +**How to apply:** +- Таблица `content_access` (миграция 040): content_type ('textbook'|'exam'), content_ref (top-level slug учебника / exam_key), scope ('class'|'student'), target_id, allow (1 открыть / 0 закрыть-исключение). Главы (parent_slug != NULL) наследуют доступ хаба. +- Резолвинг — `backend/src/services/contentAccess.js` (canAccessTextbook/canAccessExam/filterTextbooks/allowedRefs). Админ/учитель проходят всегда. +- Гейты: `textbooks.js` фильтр каталога + `router.param('slug')`; `exam-prep.js` фильтр /tracks + `router.param('examKey')`. HTML-страницы не гейтятся на сервере (JWT в localStorage) — клиентский редирект на /403 в `textbook-tracker.js` (loadServerProgress) и `exam-prep/common.js` (boot). +- API `/api/access` (`routes/access.js`, admin+teacher): GET catalog, GET targets, GET summary, GET class/:id, GET rules, POST rules. +- Фронт: `LS.accessCatalog/accessTargets/accessSummary/accessClassOpen/accessRules/accessSetRule`; секция `frontend/js/admin/sections/access.js` — два режима «По контенту» / «По классу», массовые «Открыть всем/Закрыть у всех», бейджи N/M открытых классов. +- При удалении класса/ученика правила чистятся вручную (нет FK): `classController.deleteClass` и `adminController._deleteUserTx`. + +При добавлении нового учебника/экзамена он закрыт по умолчанию — открыть классам через админку. + +**РЕВЬЮ + ПЕРЕРАБОТКА (2026-06-03):** проведено ревью всей системы прав (есть 2,5 системы: content_access +для учебников/экзаменов по классам; role/user_permissions через [registry.js] глобально по ролям — туда +входят `simulations.access`, испытания, магазин, manage-права; курсы — отдельно по is_published+класс). +План: `plans/access-redesign/PLAN.md` (4 фазы). Пользователь сказал «включай всё» + «делаем как лучше». +- **Фаза 0 ГОТОВА (commit 1bbddc0):** `contentAccess.purgeAccessFor(scope,id)` — единая чистка правил (нет FK); + deleteClass и adminController._deleteUserTx переведены на неё; confirm() на массовое «Закрыть» в админ-UI; + тест `backend/tests/content-access.test.js` (резолвер allowlist, ученик>класс, наследование главой, + admin/teacher bypass, purge). Решение по kickMember: персональные правила привязаны к УЧЕНИКУ, не к + членству → при исключении НЕ чистим (намеренный override). +- **Фаза 2a ГОТОВА (commit 67a70c6):** режим **«Матрица»** в админ-секции access.js (3-й таб) — таблица + контент×классы с чекбоксами + поиск (обновляет только tbody, фокус сохраняется). Backend + `GET /api/access/matrix` (классы+карта открытого, скоуп учителя); клиент `LS.accessMatrix`. `/api/access` + смонтирован в тест-харнесс setup.js. Тест 11/11. +- **Фаза 2b ГОТОВА (commit 596e8d8):** поиск + подзаголовки по предмету в левой колонке (режим «По контенту», + обновляет только список — фокус ввода сохраняется) + бейдж **«эффективный доступ»** у ученика в раскрытом + классе («видит/не видит · лично|по классу|по умолч.», считается клиентски из `_rules`). +- **Фаза 1 (модель ДОБАВОЧНАЯ) — СИМУЛЯЦИИ ГОТОВЫ (commits 9a145e5 + 4549b4e):** content_ref для sim = + `lab_sims.id` (TEXT, напр. 'graph'). Миграция **051** пересобрала `content_access` с CHECK + `('textbook','exam','course','sim')` + мост «открыть все включённые симуляции всем существующим классам». + `GET /api/lab/sims` (lab.js) фильтрует список для НЕпривилегированных по `allowedRefs(uid,'sim')`; admin/ + teacher — все. Ролевой `simulations.access` остался «модуль вкл.» (добавочно, AND). Админ-секция «Доступ» + обобщена на тип 'sim' (catalog/summary/matrix/class в access.js route + UI helpers BUCKET/KEYNAME/ + CONTENT_TYPES). Тесты: lab-access 4/4, content-access 12, lab-sims переведён на admin. **ВАЖНО:** новый + класс получает симуляции только после явного открытия в админке (allowlist) — мост покрыл лишь классы, + существовавшие на момент миграции 051. +- **Фаза 1c — КУРСЫ ГОТОВЫ (commit 9b7585a):** content_ref = `courses.id` (как TEXT). Миграция **052** — + мост «открыть все опубликованные курсы всем существующим классам». `courseController.list`+`search` + фильтруют для НЕпривилегированных через `courseVisible(user)`; admin/teacher — все. catalog отдаёт курсы; + `CONTENT_TYPES` в admin access.js = textbook,exam,sim,**course** (все 4 типа в UI). Тест course-access 4/4. + `class_courses` оставлен для назначений с дедлайном (сверх видимости). +- **ФАЗА 1 ЗАВЕРШЕНА (симуляции + курсы).** Backend 213 pass (3 baseline-Auth; «intro» chemistry8-page + флакует под нагрузкой — НЕ про доступ, в изоляции зелёный). Харнесс setup.js монтирует /api/access, + /api/lab, /api/courses. **ВАЖНО (allowlist):** новый класс/новый опубликованный курс/новая симуляция по + умолчанию закрыты — открыть в админке; loose-ученики (без класса) не видят sim/курсы без личного правила. +- **Фаза 2c ГОТОВА (commits d1f2473, 6a874a3, b702b04, 3a59f56):** массовые операции матрицы (клик по + контенту/классу), «Открыть весь предмет классу» (режим «По классу»), **история правил** (GET + /api/access/log, admin-only, из admin_audit_log; кнопка «История изменений» в режиме «По контенту»; + клиент LS.accessLog), **пресет «Скопировать доступ из класса»** (режим «По классу»), **объединение + вкладок по смыслу** («Доступ · контент» + «Доступ · роли» рядом в admin.html). content-access тест 13/13. + Полное слияние двух вкладок в одну с под-вкладками НЕ делалось (структурно крупнее, оставлено на потом). +- **Фаза 3 — ОТЛОЖЕНА ОСОЗНАННО (низкий ROI, решение пользователя 2026-06-03).** Серверный гейт HTML + `/textbook/:slug`, `/exam-prep/:examKey` (сейчас отдаются всем; блок только клиентским редиректом на /403, + ДАННЫЕ через API уже гейтятся). Чтобы гейтить сам HTML на сервере, нужен переход с JWT-в-localStorage на + **httpOnly-cookie сессию** — переделка ВСЕЙ аутентификации (логин/каждый запрос/logout/token_version/CSRF/ + мобилка), большой риск ради крошечной выгоды (видно лишь пустой каркас страницы, не контент). Это школьная + платформа, не ПДн/финансы. ДЕЛАТЬ ТОЛЬКО при конкретном требовании приватности контента или комплаенсе. + План: `plans/access-redesign/PLAN.md` Фаза 3. Отдельная ветка `feature/html-access-gate`. + +**Возможные улучшения (старое, до ревью — теперь решено ДЕЛАТЬ, см. план):** +1. *Единая per-class модель для всего контента.* Сейчас неоднородность: учебники/экзамены гейтятся по классам (`content_access`), а теория/курсы (`theory.access`) и симуляции (`simulations.access`) — глобально через role-permissions (см. registry.js). Можно расширить `content_access` типами `course`/`sim`, чтобы их тоже можно было открывать/закрывать по классам. Решили пока НЕ делать (меняет поведение двух работающих типов контента). +2. *Серверный гейт HTML-страниц.* `/textbook/:slug` и `/exam-prep/*` отдают статический HTML без проверки токена (JWT в localStorage, не cookie) — защита только на API + клиентский редирект на /403. Неподделываемая блокировка самих страниц требует cookie-аутентификации (крупная отдельная задача). diff --git a/.claude/memory/project_ct_seeded.md b/.claude/memory/project_ct_seeded.md new file mode 100644 index 0000000..4bf9202 --- /dev/null +++ b/.claude/memory/project_ct_seeded.md @@ -0,0 +1,63 @@ +--- +name: CT Seeded Collections +description: Список перенесённых сборников ЦТ/ЦЭ в базу — чтобы не дублировать +type: project +originSessionId: ae1e3355-b7e7-4fd7-a241-757f409a04bc +--- +## Уже перенесено в БД + +### Физика (subject_id=4) +- **ЦЭ,ЦТ 2024 (Сборники ЦЭ,ЦТ)** — перенесён как набор уникальных тематических вопросов из всех 10 вариантов (НЕ полный вариант). Файл: `seed_phys_ct2024.js`. 93 вопроса. + - Темы: векторы, МКТ формулы, единицы (Вб/В/Гн/Тл), дифракция, зеркало, преломление, явления, бросок, центростремительное, кран, охотник, нагрев Al, электростатика треугольник, КПД, ЭМИ, фотоэффект (K/Pt/Ca/Zn/Na), распад Po +- **Предыдущие seed файлы** (seed-phys.js, seed_phys.js): ~97 вопросов физики общего плана + +### Математика (subject_id=3) +- **ЦЭ-ЦТ 2024 МАТ** — перенесён как набор уникальных вопросов из всех 10 вариантов. Файл: `seed_math_ct2024.js`. 117 вопросов. +- **ЦТ 2021 V1** — 30 заданий A1-A18 + B1-B12. Файл: `seed_math_ct2021.js`. +- **ЦТ 2020 V1** — 32 задания A1-A20 + B1-B12 (5 PNG-изображений). Файл: `seed_math_ct2020.js`. +- **ЦТ 2019 V1** — 30 заданий A1-A18 + B1-B12. Файл: `seed_math_ct2019.js`. +- **ЦТ 2018 V1** — 30 заданий, 6 PNG. Файл: `seed_math_ct2018.js`. +- **ЦТ 2017 V1** — 30 заданий, 7 PNG. Файл: `seed_math_ct2017.js`. +- **ЦТ 2016 V1** — 30 заданий, 5 PNG. Файл: `seed_math_ct2016.js`. +- **ЦТ 2015 V1** — 30 заданий, 5 PNG. Файл: `seed_math_ct2015.js`. +- **ЦТ 2014 V1** — 29 заданий, 5 PNG. Файл: `seed_math_ct2014.js`. +- **Предыдущие seed файлы** (seed-math.js, seed_math.js): общие задачи по темам + +## Не перенесено (приоритет следующий) + +### Физика (сделано в этой сессии) +- **ЦЭ,ЦТ 2025 V1** — 30 заданий (15 PNG). Файл: `seed_phys_ct2025.js` +- **ЦТ 2021 V1** — 32 задания (18 PNG). Файл: `seed_phys_ct2021.js` +- **ЦТ 2020 V1** — 31 задание (20 PNG). Файл: `seed_phys_ct2020.js` +- **ЦТ 2018 V1** — 30 заданий (21 PNG, ключ из Сборники ЦТ/2018.pdf). Файл: `seed_phys_ct2018.js` +- **ЦТ 2017 V1** — 30 заданий (18 PNG, ключ из ответы.jpeg). Файл: `seed_phys_ct2017.js` + +### Физика (не перенесено) +- ЦТ 2019 — нет ключа в PDF +- ЦТ 2016 и ранее — нет отдельных файлов с ключами + +### Математика (сделано в этой сессии) +- **ЦТ 2011 V1** — 30 заданий (1 PNG). Файл: `seed_math_ct2011.js` +- **ЦТ 2012 V1** — 30 заданий (3 PNG). Файл: `seed_math_ct2012.js` +- **ЦТ 2013 V1** — 30 заданий (5 PNG). Файл: `seed_math_ct2013.js` + +### Математика (не перенесено) +- ЦТ 2010 — `F:\...\2010\ЦТ 2010 В1-В10.pdf` +- ЦТ 2009–2005 — `F:\...\2005-2009\` +- ЦТ 2004 — в папке "4 год" + +### Физика (не перенесено, нет ключей) +- ЦЭ,ЦТ 2019.pdf (ЦЭ,ЦТ папка — нет встроенного ключа) +- ЦТ 2016–2004 — нет отдельных файлов ответов + +## Правило переноса (согласовано с пользователем) +- **Из каждого сборника — ОДИН вариант** (V1, не все 10) +- **Для вопросов С РИСУНКОМ** — сохранять весь вопрос-строку как PNG (crop_question_row.py) +- **PNG изображения** → `frontend/img/ct/math/YYYY_v1_aNN.png`, путь в поле `image` таблицы questions +- **source_type = 'ЦТ'** для всех вопросов из ЦТ +- **Проверять на дубликаты** перед каждым запуском seed (ex Set по первым 80 символам) +- **Инструменты**: render_pdf_page.py, detect_table_rows.py, crop_question_row.py (в backend/scripts/) + +**Why:** пользователь сказал "из каждого сборника делай только один вариант", "не делай повторы", "если задание с рисунком — вырезай всю строку как PNG" + +**How to apply:** рендерить V1 страницы (обычно 1-3 PDF page), детектировать строки, кропать IMAGE задания, писать seed JS файл с q() для single и fb() для fill-blank, заливать в БД. diff --git a/.claude/memory/project_dashboard_rebuild.md b/.claude/memory/project_dashboard_rebuild.md new file mode 100644 index 0000000..7710581 --- /dev/null +++ b/.claude/memory/project_dashboard_rebuild.md @@ -0,0 +1,30 @@ +--- +name: project_dashboard_rebuild +description: План пересборки главной dashboard.html по скриншоту (hero-карточки + синхрон питомца); редизайн был утерян +metadata: + node_type: memory + type: project + originSessionId: 4eebe34f-0200-4613-bc0c-e884c7496721 +--- + +Боевой редизайн `frontend/dashboard.html` (питомец Квантик, «Начать чтение», «Лаборатория дня», колонки Задания/Тесты/Активность) был **некоммичен** и перезаписан коммитом flashcards `1dcc4cb`. В git/stash/dangling/VSCode Local History его НЕТ — восстановить нельзя, пересобираем по скриншоту пользователя (2026-05-31). + +**Базис — живой `frontend/dashboard.html`** (НЕ мокап `dashboard-redesign.html` — там чужой Linear-дизайн, филин «Архивариус», игнорировать). Дизайн-система: `/css/ls.css`, шрифты Unbounded+Manrope, тёмная тема, палитра #9B5DE5/#06D6E0/#F9C74F. + +**Правки от пользователя:** +- Убрать блок «Теория — в процессе» (`loadTheoryWidget` / `w-theory-progress`). +- Рейтинг уже перенесён в профиль — на дашборде не показывать (lb-section). +- Питомец на дашборде синхронизирован с модулем через `window.PetSprite.render(level, mood, accessories, color, streak)` + GET `/api/pet`. + +**Что уже есть в живом файле (loaders готовы):** loadAssignments (~2015), loadContinueWidget (3108, `/api/courses/continue`), loadActivityWidget (3174), loadFlashcardWidget (3937, `/api/flashcards/random`, СОХРАНИТЬ виджет #w-flashcard / «Повтори карточку»), loadGamification (1721), loadSubjects (1980, → блок «Тесты»). Markup: hero-зона = `.action-zone` (1380), 3 колонки = `.main-grid` (1465): #w-assignments / #w-tests / #w-progress-col. + +**Hero-карточки со скрина (3 шт, заменяют .action-cards):** +1. «Начать чтение» Химия 9 класс, прогресс % → `/api/courses/continue` (есть loadContinueWidget). +2. «Лаборатория дня» Газовые законы → SVG из `window.LabPreviews` (frontend/js/lab-previews.js: keys opticsbench/circuit/pendulum/waves/isoprocess/stereo). +3. «Питомец» Квантик, уровень/стрик/настроение → `/api/pet` + PetSprite. + +**Ассеты уцелели (untracked, НЕ трогать):** `frontend/js/pet-sprite.js` (window.PetSprite), `frontend/js/lab-previews.js` (window.LabPreviews). Их надо подключить `