chore(memory): снимок файлов памяти Claude в репозиторий для переноса
Копия пользовательской автопамяти (29 фактов + индекс MEMORY.md) в .claude/memory/, чтобы переносить между машинами через git. README.md — как восстановить в пользовательскую папку на другой машине. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
---
|
||||
name: project_content_access
|
||||
description: "Система доступа к учебникам/экзаменам по классам и ученикам из админ-панели (allowlist, ученик > класс)"
|
||||
metadata:
|
||||
node_type: memory
|
||||
type: project
|
||||
originSessionId: d08c4099-7d49-4f89-b842-d9d7af56af47
|
||||
---
|
||||
|
||||
Доступ к учебникам и экзамен-модулям («экзамен 9 класс» = exam_key `math9`) управляется из админ-панели (вкладка «Доступ к учебникам», группа **«Пользователи»**, рядом с «Права доступа»). Реализовано 2026-05-30.
|
||||
|
||||
**Модель:** ALLOWLIST — по умолчанию закрыто, нужно явно открыть. Правило ученика важнее правила класса (точечные исключения). Управляют админ (все классы/ученики) и учителя (только свои классы и ученики своих классов / привязанные через teacher_students).
|
||||
|
||||
**Why:** так выбрал пользователь (безопаснее). Миграция 040 при внедрении выдала всем существующим классам доступ к текущему контенту, чтобы переход не отнял доступ задним числом; новый контент по умолчанию закрыт.
|
||||
|
||||
**How to apply:**
|
||||
- Таблица `content_access` (миграция 040): content_type ('textbook'|'exam'), content_ref (top-level slug учебника / exam_key), scope ('class'|'student'), target_id, allow (1 открыть / 0 закрыть-исключение). Главы (parent_slug != NULL) наследуют доступ хаба.
|
||||
- Резолвинг — `backend/src/services/contentAccess.js` (canAccessTextbook/canAccessExam/filterTextbooks/allowedRefs). Админ/учитель проходят всегда.
|
||||
- Гейты: `textbooks.js` фильтр каталога + `router.param('slug')`; `exam-prep.js` фильтр /tracks + `router.param('examKey')`. HTML-страницы не гейтятся на сервере (JWT в localStorage) — клиентский редирект на /403 в `textbook-tracker.js` (loadServerProgress) и `exam-prep/common.js` (boot).
|
||||
- API `/api/access` (`routes/access.js`, admin+teacher): GET catalog, GET targets, GET summary, GET class/:id, GET rules, POST rules.
|
||||
- Фронт: `LS.accessCatalog/accessTargets/accessSummary/accessClassOpen/accessRules/accessSetRule`; секция `frontend/js/admin/sections/access.js` — два режима «По контенту» / «По классу», массовые «Открыть всем/Закрыть у всех», бейджи N/M открытых классов.
|
||||
- При удалении класса/ученика правила чистятся вручную (нет FK): `classController.deleteClass` и `adminController._deleteUserTx`.
|
||||
|
||||
При добавлении нового учебника/экзамена он закрыт по умолчанию — открыть классам через админку.
|
||||
|
||||
**РЕВЬЮ + ПЕРЕРАБОТКА (2026-06-03):** проведено ревью всей системы прав (есть 2,5 системы: content_access
|
||||
для учебников/экзаменов по классам; role/user_permissions через [registry.js] глобально по ролям — туда
|
||||
входят `simulations.access`, испытания, магазин, manage-права; курсы — отдельно по is_published+класс).
|
||||
План: `plans/access-redesign/PLAN.md` (4 фазы). Пользователь сказал «включай всё» + «делаем как лучше».
|
||||
- **Фаза 0 ГОТОВА (commit 1bbddc0):** `contentAccess.purgeAccessFor(scope,id)` — единая чистка правил (нет FK);
|
||||
deleteClass и adminController._deleteUserTx переведены на неё; confirm() на массовое «Закрыть» в админ-UI;
|
||||
тест `backend/tests/content-access.test.js` (резолвер allowlist, ученик>класс, наследование главой,
|
||||
admin/teacher bypass, purge). Решение по kickMember: персональные правила привязаны к УЧЕНИКУ, не к
|
||||
членству → при исключении НЕ чистим (намеренный override).
|
||||
- **Фаза 2a ГОТОВА (commit 67a70c6):** режим **«Матрица»** в админ-секции access.js (3-й таб) — таблица
|
||||
контент×классы с чекбоксами + поиск (обновляет только tbody, фокус сохраняется). Backend
|
||||
`GET /api/access/matrix` (классы+карта открытого, скоуп учителя); клиент `LS.accessMatrix`. `/api/access`
|
||||
смонтирован в тест-харнесс setup.js. Тест 11/11.
|
||||
- **Фаза 2b ГОТОВА (commit 596e8d8):** поиск + подзаголовки по предмету в левой колонке (режим «По контенту»,
|
||||
обновляет только список — фокус ввода сохраняется) + бейдж **«эффективный доступ»** у ученика в раскрытом
|
||||
классе («видит/не видит · лично|по классу|по умолч.», считается клиентски из `_rules`).
|
||||
- **Фаза 1 (модель ДОБАВОЧНАЯ) — СИМУЛЯЦИИ ГОТОВЫ (commits 9a145e5 + 4549b4e):** content_ref для sim =
|
||||
`lab_sims.id` (TEXT, напр. 'graph'). Миграция **051** пересобрала `content_access` с CHECK
|
||||
`('textbook','exam','course','sim')` + мост «открыть все включённые симуляции всем существующим классам».
|
||||
`GET /api/lab/sims` (lab.js) фильтрует список для НЕпривилегированных по `allowedRefs(uid,'sim')`; admin/
|
||||
teacher — все. Ролевой `simulations.access` остался «модуль вкл.» (добавочно, AND). Админ-секция «Доступ»
|
||||
обобщена на тип 'sim' (catalog/summary/matrix/class в access.js route + UI helpers BUCKET/KEYNAME/
|
||||
CONTENT_TYPES). Тесты: lab-access 4/4, content-access 12, lab-sims переведён на admin. **ВАЖНО:** новый
|
||||
класс получает симуляции только после явного открытия в админке (allowlist) — мост покрыл лишь классы,
|
||||
существовавшие на момент миграции 051.
|
||||
- **Фаза 1c — КУРСЫ ГОТОВЫ (commit 9b7585a):** content_ref = `courses.id` (как TEXT). Миграция **052** —
|
||||
мост «открыть все опубликованные курсы всем существующим классам». `courseController.list`+`search`
|
||||
фильтруют для НЕпривилегированных через `courseVisible(user)`; admin/teacher — все. catalog отдаёт курсы;
|
||||
`CONTENT_TYPES` в admin access.js = textbook,exam,sim,**course** (все 4 типа в UI). Тест course-access 4/4.
|
||||
`class_courses` оставлен для назначений с дедлайном (сверх видимости).
|
||||
- **ФАЗА 1 ЗАВЕРШЕНА (симуляции + курсы).** Backend 213 pass (3 baseline-Auth; «intro» chemistry8-page
|
||||
флакует под нагрузкой — НЕ про доступ, в изоляции зелёный). Харнесс setup.js монтирует /api/access,
|
||||
/api/lab, /api/courses. **ВАЖНО (allowlist):** новый класс/новый опубликованный курс/новая симуляция по
|
||||
умолчанию закрыты — открыть в админке; loose-ученики (без класса) не видят sim/курсы без личного правила.
|
||||
- **Фаза 2c ГОТОВА (commits d1f2473, 6a874a3, b702b04, 3a59f56):** массовые операции матрицы (клик по
|
||||
контенту/классу), «Открыть весь предмет классу» (режим «По классу»), **история правил** (GET
|
||||
/api/access/log, admin-only, из admin_audit_log; кнопка «История изменений» в режиме «По контенту»;
|
||||
клиент LS.accessLog), **пресет «Скопировать доступ из класса»** (режим «По классу»), **объединение
|
||||
вкладок по смыслу** («Доступ · контент» + «Доступ · роли» рядом в admin.html). content-access тест 13/13.
|
||||
Полное слияние двух вкладок в одну с под-вкладками НЕ делалось (структурно крупнее, оставлено на потом).
|
||||
- **Фаза 3 — ОТЛОЖЕНА ОСОЗНАННО (низкий ROI, решение пользователя 2026-06-03).** Серверный гейт HTML
|
||||
`/textbook/:slug`, `/exam-prep/:examKey` (сейчас отдаются всем; блок только клиентским редиректом на /403,
|
||||
ДАННЫЕ через API уже гейтятся). Чтобы гейтить сам HTML на сервере, нужен переход с JWT-в-localStorage на
|
||||
**httpOnly-cookie сессию** — переделка ВСЕЙ аутентификации (логин/каждый запрос/logout/token_version/CSRF/
|
||||
мобилка), большой риск ради крошечной выгоды (видно лишь пустой каркас страницы, не контент). Это школьная
|
||||
платформа, не ПДн/финансы. ДЕЛАТЬ ТОЛЬКО при конкретном требовании приватности контента или комплаенсе.
|
||||
План: `plans/access-redesign/PLAN.md` Фаза 3. Отдельная ветка `feature/html-access-gate`.
|
||||
|
||||
**Возможные улучшения (старое, до ревью — теперь решено ДЕЛАТЬ, см. план):**
|
||||
1. *Единая per-class модель для всего контента.* Сейчас неоднородность: учебники/экзамены гейтятся по классам (`content_access`), а теория/курсы (`theory.access`) и симуляции (`simulations.access`) — глобально через role-permissions (см. registry.js). Можно расширить `content_access` типами `course`/`sim`, чтобы их тоже можно было открывать/закрывать по классам. Решили пока НЕ делать (меняет поведение двух работающих типов контента).
|
||||
2. *Серверный гейт HTML-страниц.* `/textbook/:slug` и `/exam-prep/*` отдают статический HTML без проверки токена (JWT в localStorage, не cookie) — защита только на API + клиентский редирект на /403. Неподделываемая блокировка самих страниц требует cookie-аутентификации (крупная отдельная задача).
|
||||
Reference in New Issue
Block a user