feat(lab-content-engine): phase 4 - каталог симуляций в БД + API + админка

- Миграция 042_lab_sims.sql: таблица lab_sims (id, cat, title, subject, grade,
  sort_order, enabled, featured, tags JSON), сид 40 симуляций в порядке каталога
- backend/src/routes/lab.js: GET /api/lab/sims (мёрж БД + legacy-флаги, auth),
  PATCH /api/lab/sims/:id (admin), POST /api/lab/sims/reorder (admin).
  enabled зеркалится в legacy sim_disabled_ids -> lab.html без правок фронта
- server.js: монтирование /api/lab
- tests/lab-sims.test.js: 11 тестов (auth/роли/вкл-выкл+зеркало/featured/tags/
  валидация/reorder/404), все проходят; +0 к baseline (3 pre-existing)
- admin/sections/sims.js: убран захардкоженный ADMIN_SIMS, каталог из /api/lab/sims,
  тумблеры вкл-выкл и «рекомендуемая»; XSS-эскейп, иконки .ic
- plans/: Фаза 4 done + handoff

Независимое ревью: PASS, блокеров нет. route-auth lint: PATCH-роут защищён inline
requireRole('admin'). Миграция применена к живой БД.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Maxim Dolgolyov
2026-05-30 15:49:05 +03:00
parent 8ce4cec798
commit c1c5bafaff
8 changed files with 397 additions and 76 deletions
+10 -1
View File
@@ -42,7 +42,16 @@ manifest: `{ id, cat, title, desc, preview(string|fn), theory?, bodyId?, mount?(
- `loadTheory(id)` — если `get(base).theory` есть → рендерим из него; иначе `THEORY[base]`.
- `closeSim()`/`_pauseAllSims()` — дополнительно `LabRegistry.stopActive()` / `destroyActive()`.
## RESUME STATE — Phase 3 done + FIXED (2026-05-30, latest)
## RESUME STATE — Phase 4 done (2026-05-30, latest)
- Ф4: каталог симуляций в БД. Миграция `042_lab_sims.sql` (таблица lab_sims, сид 40), `backend/src/routes/lab.js` (GET /api/lab/sims auth; PATCH /:id + POST /reorder admin), mount в server.js, 11 тестов, переписан admin/sections/sims.js (убран хардкод ADMIN_SIMS).
- enabled зеркалится в legacy app_settings.sim_disabled_ids → lab.html без правок. preview-SVG остаются в коде.
- Ревью PASS (без блокеров). route-auth lint чистый. Миграция применена к живой БД. Запушено, remote синхронен.
- ВАЖНО: `npm test` = 3 PRE-EXISTING baseline-фейла (НЕ мои; документированы с lab-split). pre-commit хук: BASELINE_FAILS=3, блокирует только при >3. Мои 11 проходят, +0.
- ⚠️ Параллельная сессия коммитит в ветку — был 2 behind, rebase прошёл чисто (без пересечений по файлам). Всегда fetch+rebase перед push.
- НЕ ПРОВЕРЕНО В БРАУЗЕРЕ: админка «Симуляции» (грузит /api/lab/sims, тумблеры, звезда featured) + исчезновение выключенной симуляции на /lab.
- ОСТАЛОСЬ: Фаза 5 (курикулум: lab_sim_links + кнопки «Открыть в лаборатории» в учебнике/теории + связанная теория/задачи на странице sim). subject/grade/featured/tags уже в схеме lab_sims.
## RESUME STATE — Phase 3 done + FIXED (2026-05-30, ранее)
- HEAD=9069d80 (Ф3 + критический фикс). ЗАПУШЕНО, remote синхронен (0 0).
- ВАЖНЫЙ УРОК: коммит fc1139f был СЛОМАН — 2 edit'а (_register-all open-обёртка + lab-init Promise-обработка) не применились (упали по отступу old_string), а я запушил, не заметив. Ревью-агент поймал: lab.html убрал eager-скрипты, но open остался синхронным → ReferenceError на клике. Фикс в 9069d80. ПРАВИЛО: после каждого edit проверять `grep -c` маркера; не пушить пакет без поштучной верификации.
- ТЕПЕРЬ КОРРЕКТНО: open → LabLoader.ensure(id).then(rawOpen); openSim обрабатывает Promise. E2E vm-harness (click→ensure→load→rawOpen, pendulum/stereo:cube/molphys/alias magnetic) ALL PASS.
+2 -2
View File
@@ -27,7 +27,7 @@ if-цепочками. Далее — ленивая загрузка кода,
- [x] Phase 1: Миграция всех симуляций на манифесты [domain: frontend] → [subplan](./phase-1-migrate-all.md)
- [x] Phase 2: Тела симуляций вынесены в labs-bodies.html (sync-инъекция) [domain: frontend] → [subplan](./phase-2-lazy-mount.md)
- [x] Phase 3: Ленивая загрузка кода симуляций [domain: frontend] → [subplan](./phase-3-lazy-load.md)
- [ ] Phase 4: Реестр в БД + API + админка [domain: fullstack] → [subplan](./phase-4-db-admin.md)
- [x] Phase 4: Реестр в БД + API + админка [domain: fullstack] → [subplan](./phase-4-db-admin.md)
- [ ] Phase 5: Курикулумная привязка [domain: fullstack] → [subplan](./phase-5-curriculum.md)
## Phase Progress Log
@@ -38,7 +38,7 @@ if-цепочками. Далее — ленивая загрузка кода,
| Phase 1: Миграция всех | frontend | ✅ Done (ebb2a9b) | ✅ PASS | ✅ n/a | ✅ pushed |
| Phase 2: Вынос тел | frontend | ✅ Done | ✅ браузер-проверка пройдена | ✅ n/a | ✅ pushed |
| Phase 3: Ленивая загрузка | frontend | ✅ Done (201e94e +fix) | ✅ E2E harness ALL PASS | ✅ n/a | ⚠️ нужна браузер-проверка |
| Phase 4: БД + админка | fullstack | ⬜ Not Started | ⬜ | ⬜ | ⬜ |
| Phase 4: БД + админка | fullstack | ✅ Done | ✅ PASS (review) | ✅ 11/11 +0 baseline | ✅ pushed |
| Phase 5: Курикулум | fullstack | ⬜ Not Started | ⬜ | ⬜ | ⬜ |
## Final Review
+8 -2
View File
@@ -1,6 +1,6 @@
# Phase 4: Реестр в БД + API + админка
**Status:** ⬜ Not Started
**Status:** ✅ Done — review PASS, 11 тестов, миграция применена, запушено
**Parent plan:** [PLAN.md](./PLAN.md)
**Domain:** fullstack
@@ -39,4 +39,10 @@
- [ ] Тесты проходят
## Handoff to Next Phase
<!-- заполнить после фазы -->
- РЕАЛИЗОВАНО: таблица `lab_sims` (миграция 042), `backend/src/routes/lab.js` (GET /api/lab/sims + PATCH /:id + POST /reorder), монтирование в server.js (require:58, mount:181), 11 тестов `lab-sims.test.js`, переписан `frontend/js/admin/sections/sims.js` (убран ADMIN_SIMS).
- ИСТОЧНИК ИСТИНЫ каталога теперь БД (lab_sims). preview-SVG остаются в коде. Поля subject/grade/featured/tags ГОТОВЫ в схеме и API — Фаза 5 их наполнит (курикулум) и фронт /lab может начать их потреблять.
- СОВМЕСТИМОСТЬ: enabled зеркалится в app_settings.sim_disabled_ids, поэтому lab.html (читает /api/settings/sims) скрывает выключенные без правок фронта. Каталог /lab пока НЕ читает /api/lab/sims (рендерится из кода-реестра+SIMS) — это опционально для Фазы 5: можно подтянуть порядок/featured/теги из БД.
- ТЕСТЫ: `npm test` имеет 3 PRE-EXISTING baseline-фейла (документированы с lab-split, не связаны с этой работой). pre-commit хук толерантен (BASELINE_FAILS=3). Мои 11 тестов проходят, +0 к фейлам.
- БРАУЗЕР-ПРОВЕРКА (желательно для Ф4): зайти в админку → раздел «Симуляции»: список грузится из API, тумблеры вкл/выкл и звёзда «рекомендуемая» работают; на /lab выключенная симуляция исчезает из каталога.
- ⚠️ ПАРАЛЛЕЛЬНАЯ СЕССИЯ активно коммитит в эту ветку (chemistry-8 и др.) — fetch+rebase перед push (в этой фазе было 2 behind, rebase прошёл чисто, без пересечений по файлам).
- Для Фазы 5: связи sim ↔ §учебника/тема/kmap можно класть в новую таблицу `lab_sim_links`; subject/grade уже есть в lab_sims для грубой привязки.