feat(permissions): A1 — зависимости между правами (requires) + план переработки
registry: поле requires (questions.delete→manage, templates.public→manage, courses.interactive→manage, simulations.quiz→access), проброшено в byRole. auth.requirePermission: вынесен isEnabled(); право = own AND все requires (дочернее не работает без родителя). /me и /users/🆔 effective с учётом requires + requires в ответе. UI permissions.js: каскад — дочернее с невыполненной зависимостью неактивно (тумблер заблокирован + «Требует: …»). Тест зависимости. План: plans/permissions-rework/PLAN.md. Backend 216 pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
# PLAN — Переработка ролевых прав (Role Permissions Rework)
|
||||
|
||||
> Составлен 2026-06-03 (Opus) по итогам разбора. Цель — сделать модель ролевых прав корректной
|
||||
> (зависимости), прозрачной (история, линт), гибкой (группы, пресеты, кастомные роли) и убрать
|
||||
> болезненный сайд-эффект (массовый разлогин при смене права).
|
||||
>
|
||||
> Факты по текущему коду (проверено):
|
||||
> - `backend/src/permissions/registry.js` — 23 ключа, роли teacher/student (+free_student зеркалит student);
|
||||
> поля `role/roles/default/label/desc/requireConfirmOff`.
|
||||
> - Резолв: `requirePermission` (`middleware/auth.js:46`) читает **живьём из БД**: user_permissions →
|
||||
> role_permissions → дефолт реестра. `authMiddleware` каждый запрос перечитывает роль из БД.
|
||||
> - Таблицы `role_permissions(role,permission,enabled)`, `user_permissions(user_id,permission,enabled)`.
|
||||
> - `permissionsController.js`: GET /api/permissions, POST (role-level), GET /me, GET/POST /users/:id, DELETE reset.
|
||||
> На каждое изменение — `token_version++` (role-level → у ВСЕХ юзеров роли; user-level → у одного).
|
||||
> - UI: `frontend/js/admin/sections/permissions.js` (тумблеры по ролям) + `user-detail.js` (оверрайды).
|
||||
|
||||
---
|
||||
|
||||
## Phase A — Быстрые победы (низкий риск)
|
||||
- [ ] **A1. Зависимости между правами (`requires`).** Поле `requires:[...]` в реестре
|
||||
(`questions.delete`→`questions.manage`; `templates.public`→`templates.manage`;
|
||||
`courses.interactive`→`courses.manage`; `simulations.quiz`→`simulations.access`).
|
||||
Enforce в `requirePermission` (effective = own AND все requires). Учесть в `/me` и `/users/:id`
|
||||
(effective с учётом requires). UI: каскад (родитель off → дочерние серые/выключены). Тест.
|
||||
- [ ] **A2. Гигиена реестра + ясные метки.** Тест-линт: каждый ключ из `requirePermission/perm(...)` в коде
|
||||
есть в реестре; предупреждать о неиспользуемых ключах. Метки `theory.access`/`simulations.access`
|
||||
переформулировать как «… доступен роли» (видимость конкретного — по классам в content_access).
|
||||
- [ ] **A3. История изменений прав в UI.** Аудит уже пишется (`permission.set`/`permission.user_set`/
|
||||
`permission.user_reset`). Эндпоинт `GET /api/permissions/log` (+ опц. фильтр по роли/пользователю),
|
||||
кнопка «История» на вкладке «Доступ · роли» и в карточке пользователя. Переиспользовать паттерн
|
||||
`/api/access/log`.
|
||||
- [ ] **A4. Смягчить `token_version++`.** Сервер уже применяет права live → массовый разлогин роли при
|
||||
одном тумблере не нужен. Убрать bump на role-level (и/или user-level), вместо этого клиент
|
||||
пере-запрашивает `/permissions/me` при `focus`/навигации. Сохранить немедленный серверный эффект
|
||||
(он и так есть). Аккуратно: проверить, где клиент кэширует права (lab-glue и т. п.).
|
||||
|
||||
## Phase B — Среднее (управление при масштабе)
|
||||
- [ ] **B5. Группы прав (`group`).** Поле `group` в реестре («Контент»/«Класс»/«Геймификация»/«Профиль»/
|
||||
«Библиотека») → секции в UI + «вкл/выкл всю группу».
|
||||
- [ ] **B6. Массовое применение к классу / выбранным ученикам.** Через `class_members`: выставить право
|
||||
пачке учеников (аналог матрицы/массовых операций content_access).
|
||||
- [ ] **B7. Пресеты-профили прав.** Бандлы («Ограниченный ученик», «Ассистент учителя») — применить к
|
||||
пользователю/классу одним кликом.
|
||||
- [ ] **B8. Временные права (`expires_at`).** Колонка в `user_permissions` + авто-снятие в резолвере/кроне.
|
||||
|
||||
## Phase C — Крупное / архитектурное
|
||||
- [ ] **C9. Кастомные роли.** Таблица ролей в БД + наборы дефолтов; реестр остаётся словарём ключей.
|
||||
Кандидаты: методист/завуч, классрук/куратор, ассистент учителя, родитель (есть `parentAuth`).
|
||||
- [ ] **C10. Делегирование учителю.** Часть студенческих прав — учителю в рамках его классов.
|
||||
- [ ] **C11. Пер-классовый скоуп прав.** Право на уровне класса (свести к модели content_access). Большая работа.
|
||||
|
||||
## Порядок исполнения
|
||||
A1 → A2 → A3 → A4 → B5 → B6 → B7 → B8 → C9 → C10 → C11. Phase C — отдельными ветками/планом (архитектура).
|
||||
|
||||
## Тесты/гочи
|
||||
- Бэкенд-тесты через `backend/tests/setup.js` (харнесс монтирует /api/permissions). Прогон `node --test`.
|
||||
- pre-commit гоняет полный backend-набор (baseline 3 Auth + флака «intro» в chemistry8-page под нагрузкой).
|
||||
- ⛔ эмодзи; коммитить поимённо; fetch перед работой (активны параллельные сессии на master).
|
||||
Reference in New Issue
Block a user