fix(biochem 3D): корректная глубина + объёмные связи-цилиндры
Два дефекта, из-за которых 3D читался как плоская диаграмма: - painter-сортировка была по возрастанию z (ближние первыми) — дальние атомы рисовались поверх ближних. Теперь единый список примитивов (атомы + половинки связей) сортируется по убыванию z (дальние первыми). - связи были тонкими плоскими линиями. Теперь — затенённые «цилиндры»: толстый штрих с поперечным градиентом (центр светлее, края темнее), двухцветные (каждая половина под цвет своего атома) — фирменный вид ball-and-stick. Ширина зависит от перспективы (ближе — толще). - усилена перспектива (fov 900→700), добавлен тёмный ободок сфер для объёма. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
# Feature Context: Контент-движок лаборатории
|
||||
|
||||
## Current State
|
||||
- Лаборатория работает на захардкоженной регистрации (см. PLAN.md Summary).
|
||||
- Ветка `feature/lab-content-engine` создана от `master`.
|
||||
|
||||
## Architecture map (как было ДО рефактора)
|
||||
- `frontend/lab.html` — sim-тела `<div id="sim-xxx">` (inline HTML, ~3000 строк) + 58 `<script>` тегов (4800-4861) + three.js.
|
||||
- `frontend/js/labs/lab-glue.js`:
|
||||
- `_catFilter`, `_disabledSimIds`, `_simModuleDisabled` (вкл/выкл из админки)
|
||||
- `filterSims()`, `renderSims()` (карточки каталога)
|
||||
- preview-хелперы `_grid/_axes/_svg` + ~60 констант `P_*`
|
||||
- массив `SIMS` (821-866), `window.SIMS`/`window.LAB_SIMS`
|
||||
- `frontend/js/labs/lab-init.js`:
|
||||
- объявления переменных симуляций (gSim, pSim, …)
|
||||
- `ALL_SIM_BODIES` / `ALL_CTRL_BARS` (33-48)
|
||||
- `_pauseAllSims()` (54-91), `openSim(id)` if-цепочка (93-160), `closeSim()` (212-258)
|
||||
- `_simShow()`, `_addTouchSupport()` (touch-bridge + ResizeObserver)
|
||||
- объект `THEORY` + `loadTheory()` + `_theoryToggle()`
|
||||
- функции `_openXxx()` (603-756) — единый шаблон: `_simShow('sim-xxx')` + ленивое `new XxxSim(...)` + показ `ctrl-xxx`
|
||||
- `frontend/js/admin/sections/sims.js` — админ-секция (пока только вкл/выкл, `_disabledSimIds`).
|
||||
|
||||
## Загрузочный порядок (КРИТИЧНО)
|
||||
В lab.html: движки `_fx_*`, `_phys_visuals`, `_graph_panel`, `_chem_visuals` грузятся ПЕРЕД симуляциями.
|
||||
`lab-init.js` (4826) грузится ПЕРЕД `lab-glue.js` (4827). `renderSims()` вызывается в конце lab-glue.
|
||||
Некоторые sim-файлы (graph.js) грузятся РАНЬШЕ lab-glue.js → preview `P_*` ещё не определены на момент исполнения их тел.
|
||||
=> В манифестах `preview` поддерживает функцию (ленивое вычисление в renderSims), не только строку.
|
||||
|
||||
## Контракт LabRegistry (Фаза 0)
|
||||
```
|
||||
LabRegistry.register(manifest) // manifest.id уникален; повторная регистрация перезаписывает
|
||||
LabRegistry.get(id) // по base-id (без ':arg')
|
||||
LabRegistry.has(id)
|
||||
LabRegistry.all() // в порядке регистрации
|
||||
LabRegistry.setActive(sim) / stopActive() / destroyActive() // менеджер жизненного цикла
|
||||
```
|
||||
manifest: `{ id, cat, title, desc, preview(string|fn), theory?, bodyId?, mount?(host), open(ctx), stop?(), destroy?(), subject?, grade?, topics? }`
|
||||
|
||||
## Адаптер (Фаза 0): реестр в приоритете, иначе legacy
|
||||
- `renderSims()` — порядок берём из исходного `SIMS`; для id, который есть в реестре, используем манифест (resolve preview), иначе legacy-запись; в конце добавляем registry-only записи, которых нет в SIMS.
|
||||
- `openSim(id)` — `base = id.split(':')[0]`; если `LabRegistry.has(base)` → `stopActive()`; `get(base).open({arg})`; `setActive`; иначе старый if-путь.
|
||||
- `loadTheory(id)` — если `get(base).theory` есть → рендерим из него; иначе `THEORY[base]`.
|
||||
- `closeSim()`/`_pauseAllSims()` — дополнительно `LabRegistry.stopActive()` / `destroyActive()`.
|
||||
|
||||
## Temporary Workarounds
|
||||
- (пока нет)
|
||||
|
||||
## Cross-Phase Dependencies
|
||||
- Фаза 1 опирается на ядро реестра из Фазы 0.
|
||||
- Фаза 3 (ленивая загрузка) опирается на манифесты с зависимостями движков (Фаза 1/2).
|
||||
- Фаза 4 (БД) мёржит код-манифесты Фазы 1 с оверрайдами.
|
||||
- Фаза 5 использует поля subject/grade/topics из манифестов.
|
||||
|
||||
## Deep-links (сохранить!)
|
||||
`openSim('stereo:figure')`, `?stereofig=`, обратная совместимость `magnetic/coulomb→emfield`, `thinlens/mirrors/refraction→opticsbench`.
|
||||
|
||||
## Проектные правила (НЕ нарушать)
|
||||
- Иконки: только inline SVG `.ic`, НЕ эмоджи.
|
||||
- Поиск по коду: ast-index, НЕ Grep tool.
|
||||
- БД: встроенный `node:sqlite` DatabaseSync, НЕ better-sqlite3.
|
||||
- Git: коммитить только изменённые файлы.
|
||||
@@ -0,0 +1,53 @@
|
||||
# Feature: Контент-движок лаборатории (симуляции как данные)
|
||||
|
||||
**Branch:** `feature/lab-content-engine`
|
||||
**Base branch:** `master`
|
||||
**Created:** 2026-05-30
|
||||
**Status:** 🟡 In Progress
|
||||
**Strategy:** Big Bang
|
||||
**Mode:** Automated
|
||||
**Execution:** Direct
|
||||
|
||||
## Summary
|
||||
|
||||
Превратить захардкоженную в 6 местах регистрацию ~49 симуляций лаборатории в единый
|
||||
декларативный манифест + реестр (`LabRegistry`). Каждая симуляция сама себя регистрирует
|
||||
объектом `{id, cat, title, desc, preview, theory, bodyId/mount, open, stop, destroy, subject, grade, topics}`.
|
||||
Ядро (renderSims/openSim/closeSim/loadTheory) работает с реестром, а не с массивами и
|
||||
if-цепочками. Далее — ленивая загрузка кода, БД-бэкенд с админкой и курикулумная привязка.
|
||||
|
||||
## Build & Test Commands
|
||||
- **Build:** — (фронт без сборки, статика через Express)
|
||||
- **Test:** `cd backend && npm test` (актуально для Фаз 4-5; Фазы 0-3 — статическая проверка + ревью по диффу)
|
||||
- **Lint:** `cd backend && npm run lint:routes` (актуально для Фаз 4-5)
|
||||
|
||||
## Phases
|
||||
|
||||
- [ ] Phase 0: Ядро реестра + адаптер + 3 пилота [domain: frontend] → [subplan](./phase-0-registry-core.md)
|
||||
- [ ] Phase 1: Миграция всех симуляций на манифесты [domain: frontend] → [subplan](./phase-1-migrate-all.md)
|
||||
- [ ] Phase 2: Тела симуляций как шаблоны + ленивый mount [domain: frontend] → [subplan](./phase-2-lazy-mount.md)
|
||||
- [ ] Phase 3: Ленивая загрузка кода симуляций [domain: frontend] → [subplan](./phase-3-lazy-load.md)
|
||||
- [ ] Phase 4: Реестр в БД + API + админка [domain: fullstack] → [subplan](./phase-4-db-admin.md)
|
||||
- [ ] Phase 5: Курикулумная привязка [domain: fullstack] → [subplan](./phase-5-curriculum.md)
|
||||
|
||||
## Phase Progress Log
|
||||
|
||||
| Phase | Domain | Status | Review | Build | Committed |
|
||||
|-------|--------|--------|--------|-------|-----------|
|
||||
| Phase 0: Ядро реестра | frontend | ⬜ Not Started | ⬜ | ⬜ | ⬜ |
|
||||
| Phase 1: Миграция всех | frontend | ⬜ Not Started | ⬜ | ⬜ | ⬜ |
|
||||
| Phase 2: Ленивый mount | frontend | ⬜ Not Started | ⬜ | ⬜ | ⬜ |
|
||||
| Phase 3: Ленивая загрузка | frontend | ⬜ Not Started | ⬜ | ⬜ | ⬜ |
|
||||
| Phase 4: БД + админка | fullstack | ⬜ Not Started | ⬜ | ⬜ | ⬜ |
|
||||
| Phase 5: Курикулум | fullstack | ⬜ Not Started | ⬜ | ⬜ | ⬜ |
|
||||
|
||||
## Final Review
|
||||
- [ ] Comprehensive code review
|
||||
- [ ] Full build passes
|
||||
- [ ] Full test suite passes
|
||||
- [ ] Merged to `master`
|
||||
|
||||
## Notes (Big Bang temporary breakage map)
|
||||
- Фаза 1 может временно ломать каталог/открытие симуляций пока миграция не завершена — устраняется внутри Фазы 1.
|
||||
- Фаза 2 временно меняет структуру lab.html (вынос тел) — устраняется внутри Фазы 2.
|
||||
- Полная работоспособность лаборатории гарантируется после ФИНАЛЬНОЙ фазы.
|
||||
@@ -0,0 +1,46 @@
|
||||
# Phase 0: Ядро реестра + адаптер + 3 пилота
|
||||
|
||||
**Status:** ⬜ Not Started
|
||||
**Parent plan:** [PLAN.md](./PLAN.md)
|
||||
**Domain:** frontend
|
||||
|
||||
## Objective
|
||||
Создать `LabRegistry` (реестр + менеджер активной симуляции). Подключить адаптер: ядро
|
||||
лаборатории сначала смотрит в реестр, иначе — старый путь. Мигрировать 3 пилота
|
||||
(graph, quadratic, pendulum) и доказать паритет. Полностью обратимо.
|
||||
|
||||
## Tasks
|
||||
- [ ] Создать `frontend/js/labs/_registry.js` — `window.LabRegistry` (register/get/has/all + setActive/stopActive/destroyActive). Без эмоджи.
|
||||
- [ ] Подключить `_registry.js` в lab.html ПЕРВЫМ среди labs-скриптов (до graph.js).
|
||||
- [ ] Адаптер `renderSims()` (lab-glue.js): порядок из SIMS, registry-override + resolve preview (string|fn), append registry-only.
|
||||
- [ ] Адаптер `openSim()` (lab-init.js): base-id, registry-first → stopActive/open/setActive; deep-link `:arg` сохранить.
|
||||
- [ ] Адаптер `loadTheory()` (lab-init.js): registry.theory в приоритете, иначе THEORY[base].
|
||||
- [ ] Адаптер `closeSim()`/`_pauseAllSims()`: добавить `LabRegistry.stopActive()`/`destroyActive()`.
|
||||
- [ ] Зарегистрировать 3 пилота в конце lab-init.js (после _openXxx): graph, quadratic, pendulum — с preview-fn, theory-объектом, open=_openXxx, stop/destroy.
|
||||
- [ ] Удалить graph/quadratic/pendulum из legacy `THEORY` и `SIMS` (проверка, что адаптер их подхватывает из реестра).
|
||||
|
||||
## Files to Modify/Create
|
||||
- `frontend/js/labs/_registry.js` — новый: ядро реестра.
|
||||
- `frontend/lab.html` — добавить `<script src="/js/labs/_registry.js">` первым (в обоих местах, если дублируется список).
|
||||
- `frontend/js/labs/lab-glue.js` — renderSims адаптер; убрать 3 пилота из SIMS.
|
||||
- `frontend/js/labs/lab-init.js` — openSim/loadTheory/closeSim/_pauseAllSims адаптеры; регистрация 3 пилотов; убрать 3 пилота из THEORY.
|
||||
|
||||
## Acceptance Criteria
|
||||
- Каталог отображает все симуляции в прежнем порядке; 3 пилота открываются и работают идентично.
|
||||
- Остальные 46 симуляций открываются по-старому (legacy путь не сломан).
|
||||
- Deep-links и обратная совместимость id работают.
|
||||
- Нет дублей карточек (пилот не показан дважды).
|
||||
- Нет эмоджи; иконки `.ic`.
|
||||
|
||||
## Notes
|
||||
- Порядок загрузки: см. CONTEXT.md. preview как функция спасает от undefined P_*.
|
||||
- `_disabledSimIds` фильтрация должна продолжать работать для registry-записей.
|
||||
|
||||
## Review Checklist
|
||||
- [ ] Адаптер не ломает legacy симуляции
|
||||
- [ ] Паритет 3 пилотов (open/stop/close/theory/preview)
|
||||
- [ ] Соблюдены конвенции проекта (no emoji, .ic)
|
||||
- [ ] Нет дублирования карточек
|
||||
|
||||
## Handoff to Next Phase
|
||||
<!-- заполнить после фазы -->
|
||||
@@ -0,0 +1,40 @@
|
||||
# Phase 1: Миграция всех симуляций на манифесты
|
||||
|
||||
**Status:** ⬜ Not Started
|
||||
**Parent plan:** [PLAN.md](./PLAN.md)
|
||||
**Domain:** frontend
|
||||
|
||||
## Objective
|
||||
Перевести все ~49 симуляций на сам/регистрацию через `LabRegistry`. Перенести данные
|
||||
(catalogue meta, preview, theory) и поведение (open/stop/destroy) в манифесты. Удалить
|
||||
legacy-структуры. Сохранить глобальные имена через shim.
|
||||
|
||||
## Tasks
|
||||
- [ ] Для каждой симуляции зарегистрировать манифест (метаданные из SIMS, preview из P_*, theory из THEORY, open/stop/destroy из _openXxx + _pauseAllSims/closeSim веток).
|
||||
- [ ] Удалить массив `SIMS` (lab-glue.js) и объект `THEORY` (lab-init.js).
|
||||
- [ ] Удалить if-цепочку `openSim`, `_pauseAllSims`, switch в `closeSim`, `ALL_SIM_BODIES`/`ALL_CTRL_BARS`.
|
||||
- [ ] lab-init.js усохнуть до generic-логики (openSim/closeSim через реестр).
|
||||
- [ ] Shim глобальных имён (gSim, pSim, …) — их дёргают deep-link/поиск/инлайн-обработчики.
|
||||
- [ ] Сохранить обратную совместимость id (magnetic/coulomb→emfield, thinlens/mirrors/refraction→opticsbench, stereo:fig, hydrostatics:arg, molphys:arg, chemistry:arg, dynamics:arg, emfield:mode, opticsbench:mode).
|
||||
|
||||
## Files to Modify/Create
|
||||
- Все `frontend/js/labs/*.js` симуляции — добавить `LabRegistry.register(...)`.
|
||||
- `frontend/js/labs/lab-glue.js`, `frontend/js/labs/lab-init.js` — удалить legacy.
|
||||
|
||||
## Acceptance Criteria
|
||||
- Все симуляции открываются/работают как раньше (паритет).
|
||||
- Удалены все 6 точек дублирования из CONTEXT.md.
|
||||
- Deep-links и алиасы работают.
|
||||
|
||||
## Notes
|
||||
- Мигрировать пачками (по категориям) с проверкой паритета после каждой пачки (Big Bang допускает временную поломку между пачками).
|
||||
- Превью с зависимостями (random в P_ELECTROLYSIS) перенести как есть.
|
||||
|
||||
## Review Checklist
|
||||
- [ ] Ни одна симуляция не потеряна
|
||||
- [ ] Глобальные shim'ы на месте
|
||||
- [ ] Алиасы/deep-links работают
|
||||
- [ ] Legacy полностью удалён
|
||||
|
||||
## Handoff to Next Phase
|
||||
<!-- заполнить после фазы -->
|
||||
@@ -0,0 +1,37 @@
|
||||
# Phase 2: Тела симуляций как шаблоны + ленивый mount
|
||||
|
||||
**Status:** ⬜ Not Started
|
||||
**Parent plan:** [PLAN.md](./PLAN.md)
|
||||
**Domain:** frontend
|
||||
|
||||
## Objective
|
||||
Вынести inline-HTML тел симуляций (`<div id="sim-xxx">`, ~3000 строк) из lab.html в
|
||||
манифесты: `mount(host)` создаёт DOM лениво при первом открытии. lab.html худеет.
|
||||
|
||||
## Tasks
|
||||
- [ ] Добавить в манифест поле `mount(host)` (или `bodyHtml`) — строит/возвращает тело симуляции.
|
||||
- [ ] Ядро: при первом open — если тело не смонтировано, вызвать mount() в контейнер `#lab-sim`.
|
||||
- [ ] Перенести разметку каждого `sim-xxx` тела + его `ctrl-xxx` бара из lab.html в соответствующий модуль.
|
||||
- [ ] Удалить вынесенные блоки из lab.html.
|
||||
- [ ] Сохранить id элементов (canvas ids, ctrl ids) — на них завязаны Sim-классы.
|
||||
|
||||
## Files to Modify/Create
|
||||
- Все `frontend/js/labs/*.js` — добавить mount/bodyHtml.
|
||||
- `frontend/lab.html` — удалить inline тела.
|
||||
|
||||
## Acceptance Criteria
|
||||
- Все симуляции монтируются и работают.
|
||||
- lab.html значительно меньше (~3000 строк вынесено).
|
||||
- Повторное открытие не дублирует DOM.
|
||||
|
||||
## Notes
|
||||
- Theory-panel и общий sim-topbar остаются в lab.html.
|
||||
- KaTeX/lucide ре-инициализация после mount при необходимости.
|
||||
|
||||
## Review Checklist
|
||||
- [ ] Нет дублей DOM при повторном open
|
||||
- [ ] id элементов сохранены
|
||||
- [ ] Все тела перенесены
|
||||
|
||||
## Handoff to Next Phase
|
||||
<!-- заполнить после фазы -->
|
||||
@@ -0,0 +1,39 @@
|
||||
# Phase 3: Ленивая загрузка кода симуляций
|
||||
|
||||
**Status:** ⬜ Not Started
|
||||
**Parent plan:** [PLAN.md](./PLAN.md)
|
||||
**Domain:** frontend
|
||||
|
||||
## Objective
|
||||
Грузить тяжёлый код симуляции и движков по клику, а не 58 скриптов + three.js сразу.
|
||||
Лёгкий манифест каталога загружается сразу.
|
||||
|
||||
## Tasks
|
||||
- [ ] Вынести лёгкие метаданные каталога (id/cat/title/desc/preview) в отдельный `sims.manifest.js`, грузимый сразу.
|
||||
- [ ] Тяжёлый код симуляции (Sim-класс + open/mount) грузить динамически при openSim (инъекция script или import()).
|
||||
- [ ] Объявить зависимости движков в манифесте (`deps: ['_fx_core','_phys_visuals',...]`); загрузчик резолвит и грузит до кода симуляции, кешируя загруженное.
|
||||
- [ ] three.js грузить только для 3D-симуляций (stereo).
|
||||
- [ ] Лоадер с дедупликацией (один и тот же файл не грузится дважды).
|
||||
|
||||
## Files to Modify/Create
|
||||
- `frontend/js/labs/_loader.js` — новый: динамический загрузчик + резолв зависимостей.
|
||||
- `frontend/js/labs/sims.manifest.js` — новый: лёгкий каталог.
|
||||
- `frontend/lab.html` — убрать массовые `<script>`, оставить ядро (api, registry, loader, manifest).
|
||||
|
||||
## Acceptance Criteria
|
||||
- Первый рендер каталога без загрузки кода симуляций.
|
||||
- Открытие симуляции догружает её код+движки и работает.
|
||||
- three.js грузится только для 3D.
|
||||
- Заметное падение объёма стартовой загрузки lab.html.
|
||||
|
||||
## Notes
|
||||
- Учесть defer-скрипты (solutions/organic/periodic/qualanalysis).
|
||||
- Кеш загруженных модулей в Map.
|
||||
|
||||
## Review Checklist
|
||||
- [ ] Нет двойной загрузки
|
||||
- [ ] Зависимости движков соблюдены
|
||||
- [ ] Старт лаборатории легче
|
||||
|
||||
## Handoff to Next Phase
|
||||
<!-- заполнить после фазы -->
|
||||
@@ -0,0 +1,42 @@
|
||||
# Phase 4: Реестр в БД + API + админка
|
||||
|
||||
**Status:** ⬜ Not Started
|
||||
**Parent plan:** [PLAN.md](./PLAN.md)
|
||||
**Domain:** fullstack
|
||||
|
||||
## Objective
|
||||
Хранить оверрайды каталога в БД, мёржить с код-манифестами, управлять каталогом из
|
||||
админки (вкл/выкл, порядок, теги, рекомендуемые).
|
||||
|
||||
## Tasks
|
||||
- [ ] Миграция БД: таблица `lab_sims` (id PK, title, cat, subject, grade, desc, enabled, sort, topic_id, textbook_ref, flags JSON, updated_at). Через `node:sqlite` DatabaseSync.
|
||||
- [ ] Backend route `GET /api/lab/sims` — отдаёт мёрж: код-манифест (база) + БД-оверрайды.
|
||||
- [ ] Backend admin routes: upsert/enable/disable/reorder/tag (под RBAC admin).
|
||||
- [ ] Frontend: каталог берёт enabled/order/теги из `/api/lab/sims` (с фолбэком на код-манифест офлайн).
|
||||
- [ ] Расширить `frontend/js/admin/sections/sims.js`: список, вкл/выкл, drag-reorder, теги, «рекомендуемые».
|
||||
- [ ] Сохранить совместимость с `_disabledSimIds`.
|
||||
|
||||
## Files to Modify/Create
|
||||
- `backend/src/db/migrations/0XX_lab_sims.sql` — новая миграция.
|
||||
- `backend/src/routes/lab.js` (или расширить существующий) — API.
|
||||
- `backend/src/server.js` — подключить роут (если новый файл).
|
||||
- `frontend/js/admin/sections/sims.js` — расширить админку.
|
||||
- `frontend/js/labs/_loader.js`/manifest — учитывать БД-данные.
|
||||
|
||||
## Acceptance Criteria
|
||||
- `npm test` зелёный; `npm run lint:routes` без ошибок (auth на роутах).
|
||||
- Админ может вкл/выкл/переупорядочить/тегировать симуляцию, изменения видны в каталоге.
|
||||
- Офлайн/без БД — фолбэк на код-манифест.
|
||||
|
||||
## Notes
|
||||
- RBAC: мутации только admin. Чтение каталога — для роли с доступом к лаборатории.
|
||||
- Не дублировать данные: код-манифест = источник базовых полей; БД = оверрайды/доп.
|
||||
|
||||
## Review Checklist
|
||||
- [ ] Миграция идемпотентна
|
||||
- [ ] Роуты под auth (lint:routes)
|
||||
- [ ] Мёрж корректен, фолбэк работает
|
||||
- [ ] Тесты проходят
|
||||
|
||||
## Handoff to Next Phase
|
||||
<!-- заполнить после фазы -->
|
||||
@@ -0,0 +1,43 @@
|
||||
# Phase 5: Курикулумная привязка
|
||||
|
||||
**Status:** ⬜ Not Started
|
||||
**Parent plan:** [PLAN.md](./PLAN.md)
|
||||
**Domain:** fullstack
|
||||
|
||||
## Objective
|
||||
Связать симуляции с учебной программой: § учебника, узел knowledge-map, тема банка
|
||||
вопросов. Двусторонняя навигация.
|
||||
|
||||
## Tasks
|
||||
- [ ] Схема связей: использовать поля манифеста (subject/grade/topics) + таблицу связей `lab_sim_links` (sim_id, kind[textbook|topic|kmap|question], ref_id).
|
||||
- [ ] API: `GET /api/lab/sims/:id/related` — связанные § / темы / задачи.
|
||||
- [ ] Frontend учебник/теория: кнопка «Открыть в лаборатории» в § (deep-link openSim).
|
||||
- [ ] Frontend knowledge-map: узел темы → ссылка на симуляцию.
|
||||
- [ ] Страница симуляции: блок «Связанная теория и задачи».
|
||||
- [ ] Админка: редактирование связей симуляции.
|
||||
|
||||
## Files to Modify/Create
|
||||
- `backend/src/db/migrations/0XX_lab_sim_links.sql`
|
||||
- `backend/src/routes/lab.js` — related endpoint.
|
||||
- `frontend/textbooks.html` / theory / учебник-рендер — кнопки в §.
|
||||
- `frontend/knowledge-map.html` — ссылки с узлов.
|
||||
- `frontend/lab.html` — блок связей на странице sim.
|
||||
- `frontend/js/admin/sections/sims.js` — редактор связей.
|
||||
|
||||
## Acceptance Criteria
|
||||
- Из § учебника можно открыть нужную симуляцию.
|
||||
- На странице симуляции видны связанные теория/задачи.
|
||||
- Узлы knowledge-map ведут на симуляции.
|
||||
- `npm test` зелёный, роуты под auth.
|
||||
|
||||
## Notes
|
||||
- Привязки опциональны: отсутствие связей не ломает страницы.
|
||||
- Переиспользовать существующие topic_id банка вопросов и структуру учебников.
|
||||
|
||||
## Review Checklist
|
||||
- [ ] Навигация в обе стороны работает
|
||||
- [ ] Пустые связи не ломают UI
|
||||
- [ ] Роуты под auth, тесты проходят
|
||||
|
||||
## Handoff to Next Phase
|
||||
<!-- финальная фаза -->
|
||||
Reference in New Issue
Block a user