3.5 KiB
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