Files
Learn_System/plans/sim-builder/phase-3-persistence-api.md
T

3.5 KiB

Phase 3: БД + API (custom_sims)

Status: Not Started Parent plan: PLAN.md Domain: backend

Objective

Сохранение custom-симуляций: таблица БД, CRUD API под авторизацией с проверкой владения, серверная валидация спеки. После фазы спека сохраняется/грузится/удаляется через API.

Tasks

  • Миграция backend/src/db/migrations/0NN_custom_sims.sql (следующий свободный номер): таблица custom_sims (id, owner_id FK users ON DELETE CASCADE, title, description, subject, grade, cat, spec_json TEXT, status TEXT 'draft|published' DEFAULT 'draft', version INT, created_at, updated_at) + индекс по owner_id, status.
  • Контроллер backend/src/controllers/customSimController.js: list (own + published), get, create, update, remove. Владение проверяется на mutate (owner или admin).
  • Серверная валидация спеки validateSpec(spec): размер JSON, specVersion, лимиты (число params/objects, глубина строк-выражений), типы объектов из whitelist, строки-подписи обрезаются/санитизируются. Отказ с 400 при нарушении. Никакого исполнения спеки на сервере.
  • Роуты backend/src/routes/customSims.js: GET /api/custom-sims (свои+published), GET /api/custom-sims/:id, POST / (teacher/admin), PUT /:id, DELETE /:id. Смонтировать в server.js под authMiddleware + фича-гейт при необходимости.
  • Клиент js/api.js: customSimsList/Get/Create/Update/Delete + добавить в window.LS.
  • Тесты backend/tests/custom-sims.test.js: CRUD, ownership (403 чужой), валидация (400 кривая спека). Использовать seedRow() паттерн (устойчив к дрейфу схемы).

Files to Modify/Create

  • backend/src/db/migrations/0NN_custom_sims.sql (new)
  • backend/src/controllers/customSimController.js (new)
  • backend/src/routes/customSims.js (new)
  • backend/src/server.js — монтирование роутера (modify)
  • js/api.js — клиентские методы (modify)
  • backend/tests/custom-sims.test.js (new)

Acceptance Criteria

  • POST сохраняет спеку, GET возвращает свои+published, PUT/DELETE только владельцу/админу (403 иначе).
  • Кривая/огромная спека → 400. Тесты зелёные (в пределах baseline).
  • npm run migrate применяет таблицу; роут не отдаёт SPA-fallback после рестарта.

Notes

  • node:sqlite (DatabaseSync), НЕ better-sqlite3.
  • Спека хранится как TEXT(JSON); парс/валидация — на входе.
  • Не делать blanket router.use(requireRole('admin')) — read-роуты auth-only, мутации — inline requireRole.

Review Checklist

  • Все задачи выполнены
  • Ownership и валидация спеки покрыты тестами
  • Миграция идемпотентна (IF NOT EXISTS / INSERT OR IGNORE где надо)
  • npm run lint:routes чисто; тесты в пределах baseline

Handoff to Next Phase