# План развития «Мои материалы» > Составлен Opus 2026-06-04. Базис уже есть: `student_materials(kind board|note|link|image, > title, body, url, source_session_id, source_title, created_at)`, API `/api/materials` > (GET/POST/DELETE) + `LS.listMaterials/saveMaterial/deleteMaterial`, страница `/my-materials`, > модуль `/js/board-clip.js` (сохранение страницы/фрагмента доски), сохранение из `my-lessons.html` > и живого урока `classroom.html`. См. [[reference_student_materials]]. Следующая миграция: **061**. Готчи: новый `:id`-роут → пометить `// @public-by-design` (route-auth lint); большие HTML-файлы — только Edit; без эмодзи; коммит поимённо + push; перезапуск сервера при правке backend. --- ## Фаза 1 — Переименование, правка, создание заметки (S, фундамент) Базовые операции над материалом + личный блокнот. - **Backend:** `PATCH /api/materials/:id` (поля: title, body, collection_id, tags) с проверкой владельца; пометить `@public-by-design`. Хелпер `LS.updateMaterial(id, data)`. - **Frontend `/my-materials`:** инлайн-правка заголовка; модалка правки текста заметки; кнопка **«+ Заметка»** (создать заметку с нуля → POST kind='note'). Карточкам — меню (правка/удалить). - Зависимостей нет. Делается первым. ## Фаза 2 — Коллекции (папки) + поиск/фильтры (M, организация) Решение: **коллекции (папки)** как основной примитив + свободный поиск + фильтр по типу. Теги — опциональный стретч (поле `tags TEXT`, чипы), если понадобится. - **Миграция 061:** `material_collections(id, user_id, name, color, sort_order, created_at)` + `ALTER student_materials ADD COLUMN collection_id INTEGER REFERENCES material_collections(id) ON DELETE SET NULL` (+ опц. `ADD COLUMN tags TEXT`). - **Backend:** CRUD коллекций `GET/POST/PATCH/DELETE /api/materials/collections`; перенос материала — через `PATCH /api/materials/:id {collection_id}`; список `GET /api/materials?collection=ID`. - **Frontend:** слева/сверху список коллекций (создать/переименовать/цвет/удалить), «Переместить в…» на карточке, фильтр по коллекции + поиск по тексту + фильтр по типу (клиент, данных немного). - Делается после Ф1 (нужна перед «универсальным буфером», иначе всё свалится в одну кучу). ## Фаза 3 — Универсальный буфер «Сохранить к себе» ⭐ (M–L, стратегически) Кнопка «В мои материалы» по всей платформе. Общий клиентский модуль + поэтапная разводка по источникам. - **Модуль `/js/material-save.js`:** `MaterialSave.note({title,body,...})`, `.link({title,url})`, `.image({title,blobOrUrl})`, и `MaterialSave.button(opts)` (готовая кнопка). Поверх `LS.saveMaterial`. Везде проставлять `source_title` (откуда сохранено). - **Источники (по убыванию ценности, разводить инкрементально):** 1. Учебник (`/textbook/...`): «В мои материалы» на § → kind='link' (`/textbook/slug#sec-pN`), на рисунок/ выделенный фрагмент → kind='image'/'note'. 2. Экзамен (exam-prep): сохранить задачу+решение → kind='note' (html в body) или 'link' на задачу. 3. Лаборатория/симуляция, флешкарты, вложения чата урока → link/image. - **Kinds:** переиспользуем существующие (note/link/image), чтобы не трогать CHECK. Новый kind — только при явной нужде (тогда миграция-пересборка CHECK). - Делать: модуль + 2–3 топ-источника (учебник, экзамен, ссылка) в первой итерации; остальное — добивать. ## Фаза 4 — Редактирование и аннотации (M, синергия с SVG-рисовалкой) Рисовать поверх сохранённого изображения и создавать рисунки. - **`/js/svg-draw.js`:** добавить `opts.bgImage` (рисунок-подложка) + при экспорте компоновать подложку + вектор в один PNG (offscreen canvas). - **Frontend `/my-materials`:** на image-карточке «Аннотировать» → модалка SvgDraw(bgImage=url) → сохранить как НОВЫЙ материал (kind='image'). Кнопка «Создать рисунок» (пустой холст → image). - Подпись/комментарий к материалу — уже покрывается правкой title/body из Ф1. - Зависит от Ф1 (правка) и существующих svg-draw.js/svg-sanitize.js. ## Фаза 5 — Учебная интеграция (M) Превратить материал в инструмент повторения. - **«В флешкарты»:** из заметки создать карточку (front=title, back=body) в выбранной/личной колоде — через существующий API флешкард (decks/cards). Из image — карточка с картинкой. - **«Учить из материалов»:** лёгкий режим перелистывания заметок/карточек. - (Полноценный SRS — отдельная инициатива из экзамена; здесь не блокер.) - Зависит от API флешкард (проверить контракт). ## Фаза 6 — Учитель: своя коллекция + «раздатка» (S + M–L) - **6a (S): своя коллекция учителю.** Подключить `board-clip.js` в `lesson-history.html` (страница учителя) → кнопки «Область»/«К себе» учителю. Раздел «Мои материалы» уже user-agnostic (показать пункт сайдбара и учителю). Быстрый вин, можно сделать рано. - **6b (M–L): «Раздатка» — отправить материал ученику/классу.** - Модель: **копия при отправке** (проще и согласуется с «у каждого своя копия»): `POST /api/materials/:id/share {classId|userId}` → вставляет копию в `student_materials` получателям (source_title='Раздатка: <учитель>'). Без новой таблицы шеринга. (Альтернатива — таблица `material_shares` со ссылкой; копия проще.) - Уведомление получателям через существующую систему (`emit`/notifications). - Frontend: на материале учителя «Раздать» → выбор класса/ученика. --- ## Рекомендованный порядок **1 → 2 → 3 → 6a (быстрый вин) → 4 → 5 → 6b.** Ф1 (правка/заметки) и Ф2 (коллекции+поиск) — фундамент; Ф3 (универсальный буфер) — главный стратегический шаг, но после Ф2 (иначе захламит); 6a дешёвый — можно вклинить рано; 4/5 — обогащение; 6b (раздатка) — крупное, в конце. ## Сквозные риски / заметки - **Хранилище:** изображения идут в `/api/files`; универсальный буфер + раздатка-копии множат файлы — заложить (позже) учёт/лимиты/чистку. - **Route-auth lint:** новые `:id`-роуты (PATCH, share) пометить `@public-by-design` + проверка владельца. - **CHECK kind:** держимся в note/link/image, чтобы не пересобирать таблицу. - **Тесты:** добавить `materials.test.js` (CRUD + collections + share-копия + проверка владельца). - **Разрешения:** create-note/правка — любой авторизованный (свои); раздатка — teacher/admin.