Files
Learn_System/plans/my-materials/PLAN_V2.md
T
Maxim Dolgolyov abe84b9f90 feat(materials): «Мои материалы» v2 — харднинг безопасности и доводка UX
Безопасность/целостность: allowlist схемы URL (safeUrl) против stored-XSS через javascript:-ссылку; ссылочно-подсчётная чистка файлов при delete/смене url (releaseFileForUrl, учёт share-алиасов); квота на пользователя — число материалов + байты (колонка bytes, миграция 073).

Производительность: список отдаёт превью body (1000 симв.) + body_trunc; полный текст — ленивый GET /api/materials/:id (getOne, owner-only).

Фичи/UX (my-materials.html): теги-UI (ввод + чипы-фильтр + пилюля), ссылка на исходный урок, сортировка, множественный выбор + массовые действия, цвет/порядок папок, live-KaTeX в редакторе заметки.

Тесты: backend/tests/materials.test.js (16 тестов) — ранее их не было.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-13 14:21:30 +03:00

5.6 KiB
Raw Blame History

«Мои материалы» — v2: харднинг и доводка

Составлен Opus 2026-06-13. Базовый план (PLAN.md, Фазы 16) полностью реализован. Его раздел «Сквозные риски» отложил ровно то, что закрывает этот план: учёт/лимиты/чистку хранилища и materials.test.js. Источник истины по текущему состоянию — код (studentMaterialsController.js, materials.js, my-materials.html, board-clip.js, material-save.js) и reference_student_materials.

Готчи проекта: новый :id-роут → // @public-by-design + проверка владельца; большие HTML — только Edit; без эмодзи (inline SVG .ic); коммит поимённо + push; перезапуск сервера при правке backend; ветка feature/sim-builder в рабочем дереве — НЕ коммитить чужие правки, только свои файлы.


Фаза 1 — Целостность и безопасность (backend, фундамент) цель этого захода

  1. Ссылочно-подсчётная чистка файлов. DELETE /:id и смена url (аннотация) сейчас оставляют файл в uploads/materials/ сиротой. share копирует url дословно → несколько строк ссылаются на ОДИН файл, поэтому unlink только когда на url не ссылается ни одна строка. Хелпер releaseFileForUrl(url) вызывается ПОСЛЕ delete/update.
  2. Allowlist схемы URL. create/update принимали любой urllink со схемой javascript: рендерится как рабочий <a href> (раздача делает это вектором учитель→ученики). Хелпер safeUrl: только http(s):// или app-relative /… (не //host); иначе 400.
  3. Квота на пользователя. Колонка bytes (мигр. 073), счёт SUM(bytes)/COUNT(*). Лимит по числу материалов — в create(); лимит по байтам — в uploadPersonalFile (до приёма файла). Конфигурируемо через MATERIALS_MAX_ITEMS / MATERIALS_MAX_BYTES (для тестов — низкий потолок).
  4. backend/tests/materials.test.js — CRUD, владелец (403/404), коллекции, share-копия + роль/owner, валидация URL, лимит числа, ссылочная чистка (прямой вызов хелпера на временном файле).

Фаза 2 — Производительность (частично)

  • GET /api/materials отдаёт обрезанный body (первые 1000 симв.) + флаг body_trunc; полный текст — ленивый GET /api/materials/:id (getOne, owner-only). Клиент ensureFullBody() подгружает перед просмотром/правкой/флешкартой (иначе правка сохранила бы усечённый текст).
  • Пагинация/keyset — отложено (клиент пока фильтрует в памяти; включить при росте объёмов).
  • Серверные миниатюры board/image — отложено (нужна обработка картинок; пока loading=lazy).

Фаза 3 — Доводка заложенных фич

  • UI тегов: ввод в модалках создания/правки + чипы на карточке (клик → фильтр) + пилюля активного фильтра.
  • Ссылка «открыть исходный урок» на карточке (/my-lessons?session=<id>, есть source_session_id).
  • Цвет папки (палитра 8 пресетов, тинт иконки в рейле) + сортировка папок «Выше/Ниже» в модалке правки (нормализует sort_order к индексам). safeColor гейтит inline-style инъекцию (только hex).

Фаза 4 — UX

  • Варианты сортировки (новые/старые/имя/тип) — селект в тулбаре.
  • Множественный выбор (чекбокс на карточке) + панель массовых действий (переместить/удалить, reuse per-item API).
  • Живое превью KaTeX в редакторе заметки (oninput → mmPreviewmathHtml).

Статус

Сделано и проверено: Ф1 целиком (16 backend-тестов), Ф2/Ф3/Ф4 (headless-смоук my-materials.html: синтаксис + рендер карточек с deep-link/тегами/чекбоксом + фильтр по тегу + bulk-bar + тинт папки). Осталось (инфра, отложено): пагинация/keyset списка, серверные миниатюры board/image.


Порядок

Ф1 (этот заход) → Ф2 → Ф3 → Ф4. Ф1 — серверный фундамент (риск-возврат, без него фронт-фичи множат мусор). Дальше преимущественно фронтенд my-materials.html + точечные ручки API.