Безопасность/целостность: 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>
5.6 KiB
«Мои материалы» — v2: харднинг и доводка
Составлен Opus 2026-06-13. Базовый план (PLAN.md, Фазы 1–6) полностью реализован. Его раздел «Сквозные риски» отложил ровно то, что закрывает этот план: учёт/лимиты/чистку хранилища и
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, фундамент) ✅ цель этого захода
- Ссылочно-подсчётная чистка файлов.
DELETE /:idи сменаurl(аннотация) сейчас оставляют файл вuploads/materials/сиротой.shareкопируетurlдословно → несколько строк ссылаются на ОДИН файл, поэтомуunlinkтолько когда наurlне ссылается ни одна строка. ХелперreleaseFileForUrl(url)вызывается ПОСЛЕ delete/update. - Allowlist схемы URL.
create/updateпринимали любойurl→linkсо схемойjavascript:рендерится как рабочий<a href>(раздача делает это вектором учитель→ученики). ХелперsafeUrl: толькоhttp(s)://или app-relative/…(не//host); иначе 400. - Квота на пользователя. Колонка
bytes(мигр. 073), счётSUM(bytes)/COUNT(*). Лимит по числу материалов — вcreate(); лимит по байтам — вuploadPersonalFile(до приёма файла). Конфигурируемо черезMATERIALS_MAX_ITEMS/MATERIALS_MAX_BYTES(для тестов — низкий потолок). 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 →
mmPreview→mathHtml).
Статус
Сделано и проверено: Ф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.