ролевая моделю доступа + загруженность по кафедрам и преподавателям + просморт расписания
This commit is contained in:
@@ -1,541 +1,245 @@
|
||||
# План реализации задач после созвона с научным руководителем
|
||||
# Отчёт об изменениях по задачам научного руководителя
|
||||
|
||||
Дата: 2026-05-19
|
||||
|
||||
## 1. Короткий вывод
|
||||
## Краткий итог
|
||||
|
||||
В проекте уже есть основа для большей части требований: справочники, пользователи, кафедры, дисциплины, аудитории, динамическое расписание на базе `schedule_rules`, календарный учебный график, временные сетки и экран загруженности аудиторий. Главные недостающие архитектурные слои:
|
||||
Выполнен первый цельный релиз архитектурной основы:
|
||||
|
||||
- нормальная ролевая модель и серверная авторизация;
|
||||
- темпоральность: история принадлежности, версионирование связей и запрет ретроактивного изменения прошлого расписания;
|
||||
- мягкое удаление справочников вместо физического удаления;
|
||||
- отдельные рабочие места для кафедры и учебного отдела;
|
||||
- расширенные просмотры расписания и загруженности по преподавателям, аудиториям, кафедрам, парам и периодам.
|
||||
- добавлены роли `EDUCATION_OFFICE`, `DEPARTMENT` и `SCHEDULE_VIEWER`;
|
||||
- добавлена backend-проверка bearer-токена и ролей через `AuthorizationInterceptor` и `@RequireRoles`;
|
||||
- добавлен жизненный цикл справочников: `ACTIVE` / `ARCHIVED`;
|
||||
- физическое удаление ключевых сущностей заменено архивированием там, где это влияет на историю;
|
||||
- добавлена история переводов преподавателей между кафедрами;
|
||||
- добавлены точечные изменения расписания: перенос, отмена, замена;
|
||||
- добавлен расширенный read-only поиск расписания по аудитории, преподавателю, кафедре, группе, дисциплине, типу занятия, паре и чётности;
|
||||
- добавлены отчёты загруженности по преподавателям, аудиториям, кафедрам, парам и свободным аудиториям;
|
||||
- просмотр расписаний переведён с плоского списка на недельные матричные таблицы;
|
||||
- вкладка загруженности стала общей для аудиторий, преподавателей и кафедр;
|
||||
- интерфейсы кафедры и учебного отдела переведены в общий стиль админ-панели через role-based вкладки;
|
||||
- отдельная миграция `V2` удалена, изменения схемы внесены в `V1__init.sql`;
|
||||
- обновлена документация проекта.
|
||||
|
||||
Рекомендуемый порядок: сначала ввести темпоральный слой, жизненный цикл записей и роли, затем уже строить новые кабинеты и редакторы. Если начать с экранов, старые связи будут продолжать теряться при удалениях, переносах преподавателей и правках расписания.
|
||||
## Backend
|
||||
|
||||
## 2. Расшифровка задач руководителя в терминах системы
|
||||
### Роли и авторизация
|
||||
|
||||
| Формулировка | Что реализуем |
|
||||
|-------------|---------------|
|
||||
| Загруженность по паре или преподавателю | Аналитика занятости по временным слотам, преподавателям, аудиториям, кафедрам, дисциплинам и периодам. |
|
||||
| Темпоральные базы данных | Не отдельная БД, а темпоральная модель внутри текущей PostgreSQL БД каждого тенанта: периоды действия записей, история связей, версионирование расписания. |
|
||||
| Сделать удаление аудиторий и т.д., чтобы нельзя было использовать в дальнейшем | Мягкое удаление/архивация справочников. Исторические записи остаются, новые назначения на архивные сущности запрещены. |
|
||||
| Перенос преподавателей с одной кафедры в другую без потери связи с прошлыми записями | История принадлежности преподавателя к кафедрам через интервалы действия, а не простое перезаписывание `users.department_id`. |
|
||||
| Уровни пользователей | Расширение ролей и прав: администратор, кафедра, учебный отдел, преподаватель, студент. Проверки должны быть на backend, не только в UI. |
|
||||
| Администратор: создание аудиторий, специальностей, кафедр и т.д. | Довести справочники до полного CRUD + архив/восстановление + фильтр архивных записей. |
|
||||
| Кафедра: смотреть предметы кафедры, грузить, связывать предметы, разделять, комментарии, расписания и загруженность | Новый кабинет кафедры: дисциплины кафедры, импорт, описание дисциплин, привязки преподавателей и типов занятий, комментарии, расписание и нагрузка кафедры. |
|
||||
| Учебный отдел: закреплять время и аудитории, редактировать расписание, закреплять предметы и преподавателей в аудитории в определённое время | Новый кабинет учебного отдела: редактор расписания, фиксация времени/аудиторий/преподавателей, точечные переносы и отмены, проверка конфликтов. |
|
||||
| Просмотр расписания разных аудиторий, преподавателей, кафедр | Универсальный просмотр расписания с фильтрами по аудитории, преподавателю, группе, кафедре, дисциплине и периоду. |
|
||||
Поддерживаются роли:
|
||||
|
||||
## 3. Текущее состояние проекта
|
||||
- `ADMIN`;
|
||||
- `EDUCATION_OFFICE`;
|
||||
- `DEPARTMENT`;
|
||||
- `SCHEDULE_VIEWER`;
|
||||
- `TEACHER`;
|
||||
- `STUDENT`.
|
||||
|
||||
### Уже есть
|
||||
Добавлены:
|
||||
|
||||
- Backend: Java 17, Spring Boot, JPA, Flyway, мультитенантность через отдельную БД на тенант.
|
||||
- Frontend: Vanilla JS, отдельные интерфейсы `/admin/`, `/teacher/`, `/student/`.
|
||||
- Роли сейчас ограничены `ADMIN`, `TEACHER`, `STUDENT`.
|
||||
- Авторизация возвращает UUID-токен и роль, но полноценной серверной проверки прав по эндпоинтам пока нет.
|
||||
- Динамическое расписание строится из:
|
||||
- `schedule_rules`;
|
||||
- `schedule_rule_groups`;
|
||||
- `schedule_rule_slots`;
|
||||
- `schedule_rule_slot_subgroups`;
|
||||
- `time_slots`;
|
||||
- `academic_years` / `semesters`;
|
||||
- `academic_calendars`.
|
||||
- `GET /api/schedule` сейчас принимает ровно один фильтр: `groupId` или `teacherId`.
|
||||
- Экран загруженности аудиторий уже есть и использует реальные аудитории, временные слоты и сгенерированное расписание.
|
||||
- У аудиторий есть `is_available`, но `DELETE /api/classrooms/{id}` физически удаляет запись.
|
||||
- Преподаватель сейчас имеет одно поле `users.department_id`; история переводов не хранится.
|
||||
- Дисциплины связаны с кафедрой через `subjects.department_id`; история смены кафедры дисциплины не хранится.
|
||||
- Привязка преподавателей к дисциплинам есть через `teacher_subjects`, но это простая текущая связь без периода действия, комментариев и разбиения по ответственности.
|
||||
- `AuthSessionService` — in-memory UUID-сессии;
|
||||
- `AuthContext` — текущий пользователь в `ThreadLocal`;
|
||||
- `AuthorizationInterceptor` — проверка `Authorization: Bearer ...`;
|
||||
- `@RequireRoles` — ограничение доступа на уровне контроллеров и методов;
|
||||
- `GET /api/auth/me` — текущий пользователь по токену.
|
||||
|
||||
### Основные проблемы текущей модели
|
||||
Redirect после входа:
|
||||
|
||||
- Физическое удаление справочников опасно для истории расписания и отчётов.
|
||||
- Обновление текущих связей перезаписывает контекст прошлого.
|
||||
- Динамическое расписание пересчитывается из текущих правил, поэтому изменение правила может изменить отображение прошлого периода.
|
||||
- Ролевая модель не отражает учебный отдел и кафедру как самостоятельных пользователей.
|
||||
- Просмотр расписания и загруженности завязан на частные сценарии, а не на единый фильтруемый слой.
|
||||
- `ADMIN` -> `/admin/`;
|
||||
- `EDUCATION_OFFICE` -> `/admin/#schedule-view`;
|
||||
- `DEPARTMENT` -> `/admin/#department-workspace`;
|
||||
- `SCHEDULE_VIEWER` -> `/admin/#schedule-view`;
|
||||
- `TEACHER` -> `/teacher/`;
|
||||
- `STUDENT` -> `/student/`.
|
||||
|
||||
## 4. Целевая архитектурная идея
|
||||
### Миграция БД
|
||||
|
||||
Ввести три базовых понятия:
|
||||
Отдельная миграция `V2__roles_lifecycle_temporal_schedule.sql` удалена по текущему решению проекта.
|
||||
|
||||
1. **Жизненный цикл записи**: активна, архивирована, недоступна для новых назначений.
|
||||
2. **Период действия связи**: преподаватель относится к кафедре не "навсегда", а с даты по дату.
|
||||
3. **Версия расписания**: прошлое расписание должно оставаться воспроизводимым, даже если текущие правила изменились.
|
||||
Все изменения схемы внесены в:
|
||||
|
||||
После этого все новые экраны работают с одной логикой:
|
||||
|
||||
- активные справочники доступны для выбора;
|
||||
- архивные записи видны в истории, но не выбираются для будущих назначений;
|
||||
- отчёты за прошлый период используют связи, действовавшие на дату занятия;
|
||||
- правки будущего расписания не ломают прошлые отчёты.
|
||||
|
||||
## 5. Этап 1. Роли и права доступа
|
||||
|
||||
### Новые роли
|
||||
|
||||
| Роль | Назначение |
|
||||
|------|------------|
|
||||
| `ADMIN` | Полный доступ внутри тенанта: справочники, пользователи, роли, настройки. |
|
||||
| `EDUCATION_OFFICE` | Учебный отдел: расписание, аудитории, временные слоты, закрепления, конфликты. |
|
||||
| `DEPARTMENT` | Кафедра: дисциплины своей кафедры, преподаватели, комментарии, нагрузка, просмотр расписания. |
|
||||
| `TEACHER` | Преподаватель: личное расписание и, позже, заявки на изменения. |
|
||||
| `STUDENT` | Просмотр расписания. |
|
||||
|
||||
`ADMIN` можно оставить как суперроль внутри одной БД тенанта. Управление тенантами через `/api/database` стоит разрешить только `ADMIN`.
|
||||
|
||||
### Backend
|
||||
|
||||
- Расширить `Role`.
|
||||
- Обновить `AuthController.ROLE_REDIRECTS`:
|
||||
- `ADMIN` -> `/admin/`;
|
||||
- `EDUCATION_OFFICE` -> `/edu-office/`;
|
||||
- `DEPARTMENT` -> `/department/`;
|
||||
- `TEACHER` -> `/teacher/`;
|
||||
- `STUDENT` -> `/student/`.
|
||||
- Добавить серверную авторизацию:
|
||||
- хранение активных сессий/токенов или проверяемый токен;
|
||||
- фильтр/интерцептор, который получает пользователя по `Authorization`;
|
||||
- аннотации или централизованные проверки прав в контроллерах.
|
||||
- Не полагаться на `localStorage.role` как на источник прав.
|
||||
|
||||
### Frontend
|
||||
|
||||
- Добавить оболочки `/department/` и `/edu-office/`.
|
||||
- В админке скрывать пункты меню по роли, но считать это только UX-ограничением.
|
||||
- Все ошибки доступа показывать на русском: `Недостаточно прав для выполнения операции`.
|
||||
|
||||
## 6. Этап 2. Темпоральный слой и жизненный цикл справочников
|
||||
|
||||
### Базовые поля жизненного цикла
|
||||
|
||||
Для справочников, которые могут участвовать в расписании или отчётах, добавить:
|
||||
|
||||
- `status` (`ACTIVE`, `ARCHIVED`);
|
||||
- `active_from`;
|
||||
- `active_to`;
|
||||
- `archived_at`;
|
||||
- `archived_by`;
|
||||
- `archive_reason`.
|
||||
|
||||
Минимальный набор для первого внедрения:
|
||||
|
||||
- `classrooms`;
|
||||
- `equipments`;
|
||||
- `departments`;
|
||||
- `specialties`;
|
||||
- `specialty_profiles`;
|
||||
- `education_forms`;
|
||||
- `student_groups`;
|
||||
- `subgroups`;
|
||||
- `subjects`;
|
||||
- `users`.
|
||||
|
||||
Для сущностей, где достаточно простого вывода из эксплуатации, можно начать с `status`, `archived_at`, `archive_reason`, а `active_from/active_to` добавить там, где требуется отчётность по датам.
|
||||
|
||||
### Правила использования
|
||||
|
||||
- `GET` по умолчанию возвращает только активные записи.
|
||||
- Для админских экранов добавить `includeArchived=true`.
|
||||
- `DELETE` заменить на архивирование.
|
||||
- Физическое удаление оставить только для записей, которые точно нигде не используются, либо убрать из публичных API.
|
||||
- В формах будущего расписания нельзя выбирать архивные аудитории, дисциплины, группы, подгруппы, кафедры и пользователей.
|
||||
- В историческом расписании архивные записи отображаются с пометкой, например `Аудитория 101 (архив)`.
|
||||
|
||||
### Аудитории
|
||||
|
||||
`is_available` и архивирование должны означать разные вещи:
|
||||
|
||||
- `is_available=false` — аудитория временно недоступна, но может вернуться в работу;
|
||||
- `status=ARCHIVED` — аудитория выведена из эксплуатации и не может использоваться в новых назначениях.
|
||||
|
||||
UI-кнопку `Удалить` лучше заменить на `Вывести из эксплуатации`. Для администратора можно добавить отдельное действие `Восстановить`.
|
||||
|
||||
## 7. Этап 3. История переводов преподавателей между кафедрами
|
||||
|
||||
### Модель данных
|
||||
|
||||
Добавить таблицу:
|
||||
|
||||
```sql
|
||||
teacher_department_assignments
|
||||
```text
|
||||
backend/src/main/resources/db/migration/V1__init.sql
|
||||
```
|
||||
|
||||
Поля:
|
||||
|
||||
- `id`;
|
||||
- `teacher_id`;
|
||||
- `department_id`;
|
||||
- `valid_from`;
|
||||
- `valid_to`;
|
||||
- `is_primary`;
|
||||
- `comment`;
|
||||
- `created_at`;
|
||||
- `created_by`.
|
||||
|
||||
Текущий `users.department_id` можно временно оставить как денормализованное поле "текущая кафедра", но источником правды для отчётов должна стать таблица истории.
|
||||
|
||||
### Правила
|
||||
|
||||
- У преподавателя должна быть ровно одна основная кафедра на дату.
|
||||
- При переводе преподавателя:
|
||||
- закрывается старая запись `valid_to`;
|
||||
- создаётся новая запись `valid_from`;
|
||||
- старые расписания и отчёты используют кафедру, актуальную на дату занятия.
|
||||
- Привязки `teacher_subjects` не удаляются автоматически при переводе, иначе потеряется история. Для будущих назначений можно показывать предупреждение, если дисциплина не относится к текущей кафедре преподавателя.
|
||||
|
||||
### API
|
||||
|
||||
- `GET /api/users/{id}/department-history`
|
||||
- `POST /api/users/{id}/department-transfer`
|
||||
- `GET /api/departments/{id}/teachers?date=YYYY-MM-DD`
|
||||
- `GET /api/users/teachers?departmentId=&date=`
|
||||
|
||||
## 8. Этап 4. Версионирование расписания и точечные изменения
|
||||
|
||||
Текущая модель `schedule_rules` хороша для генерации будущего расписания, но недостаточна для неизменяемого прошлого и точечных переносов.
|
||||
|
||||
### Версии правил
|
||||
|
||||
Добавить к правилам и слотам период действия:
|
||||
|
||||
- `valid_from`;
|
||||
- `valid_to`;
|
||||
- `status`;
|
||||
- `version_group_id` или `parent_rule_id`;
|
||||
- `created_by`;
|
||||
- `change_reason`.
|
||||
|
||||
При редактировании правила:
|
||||
|
||||
- если правка относится к будущему периоду, закрывать старую версию и создавать новую;
|
||||
- если правка исправляет ошибку текущего будущего правила, разрешить обновление только до даты начала действия;
|
||||
- прошлые периоды не пересчитывать по новым данным.
|
||||
|
||||
### Точечные изменения расписания
|
||||
|
||||
Добавить таблицу:
|
||||
|
||||
```sql
|
||||
schedule_overrides
|
||||
```
|
||||
|
||||
Назначение: перенос, отмена или замена конкретной сгенерированной пары.
|
||||
|
||||
Поля:
|
||||
|
||||
- `id`;
|
||||
- `base_rule_slot_id`;
|
||||
- `lesson_date`;
|
||||
- `action` (`MOVE`, `CANCEL`, `REPLACE`);
|
||||
- `new_time_slot_id`;
|
||||
- `new_classroom_id`;
|
||||
- `new_teacher_id`;
|
||||
- `new_lesson_format`;
|
||||
- `comment`;
|
||||
- `created_by`;
|
||||
- `created_at`.
|
||||
|
||||
Генератор расписания должен сначала строить базовые пары из правил, затем применять точечные изменения.
|
||||
|
||||
### Закрепление времени, аудитории, преподавателя
|
||||
|
||||
В `schedule_rule_slots` или отдельной таблице закреплений добавить признаки:
|
||||
|
||||
- `time_locked`;
|
||||
- `classroom_locked`;
|
||||
- `teacher_locked`;
|
||||
- `locked_by`;
|
||||
- `locked_at`;
|
||||
- `lock_comment`.
|
||||
|
||||
Учебный отдел сможет фиксировать назначения, а автоматические или массовые операции не должны менять закреплённые поля без явного подтверждения.
|
||||
|
||||
## 9. Этап 5. Проверка конфликтов
|
||||
|
||||
Перед сохранением правила, версии или override проверять:
|
||||
|
||||
- преподаватель не занят в другом месте в тот же день/пару;
|
||||
- аудитория не занята другой парой;
|
||||
- вместимость аудитории не меньше суммы групп/подгрупп;
|
||||
- преподаватель привязан к дисциплине и нужному типу занятия;
|
||||
- выбранная аудитория активна и доступна на дату;
|
||||
- группа/подгруппа активна на дату;
|
||||
- кафедральные ограничения не нарушены, если дисциплина принадлежит другой кафедре.
|
||||
|
||||
Конфликты делить на:
|
||||
|
||||
- `ERROR` — сохранение запрещено;
|
||||
- `WARNING` — можно сохранить с комментарием, если роль имеет право.
|
||||
|
||||
API:
|
||||
|
||||
- `POST /api/admin/schedule-rules/validate`
|
||||
- `POST /api/edu-office/schedule/validate`
|
||||
- `GET /api/schedule/conflicts?startDate=&endDate=`
|
||||
|
||||
## 10. Этап 6. Кабинет кафедры
|
||||
|
||||
### Функции
|
||||
|
||||
- Просмотр дисциплин своей кафедры.
|
||||
- Создание и редактирование описания дисциплины.
|
||||
- Импорт дисциплин из файла. Формат нужно согласовать отдельно: CSV/XLSX, обязательные колонки, правила обновления.
|
||||
- Разделение данных дисциплины:
|
||||
- карточка дисциплины: название, код, кафедра, описание, комментарии;
|
||||
- преподаватели дисциплины;
|
||||
- типы занятий, которые может вести каждый преподаватель;
|
||||
- история изменений.
|
||||
- Комментарии к дисциплине, привязке или расписанию.
|
||||
- Просмотр расписания кафедры.
|
||||
- Просмотр загруженности кафедры:
|
||||
- по преподавателям;
|
||||
- по дисциплинам;
|
||||
- по неделям;
|
||||
- по типам занятий.
|
||||
|
||||
### Backend
|
||||
|
||||
Новые или расширенные сущности:
|
||||
`V1__init.sql` теперь сразу создаёт:
|
||||
|
||||
- lifecycle-поля к справочникам и пользователям;
|
||||
- `teacher_department_assignments`;
|
||||
- `subject_comments`;
|
||||
- `subject_department_assignments` или темпоральные поля у `subjects`;
|
||||
- версионированные `teacher_subjects`;
|
||||
- `teacher_lesson_types` вывести в полноценный API, если таблица уже есть в схеме.
|
||||
- version-поля к `schedule_rules`;
|
||||
- lock-поля к `schedule_rule_slots`;
|
||||
- `schedule_overrides`;
|
||||
- стартовых пользователей `учебный_отдел`, `кафедра_иб` и `просмотр_расписаний`.
|
||||
|
||||
API:
|
||||
### Архивирование вместо удаления
|
||||
|
||||
- `GET /api/department/subjects`
|
||||
- `POST /api/department/subjects/import`
|
||||
- `GET /api/department/subjects/{id}`
|
||||
- `PUT /api/department/subjects/{id}`
|
||||
- `GET /api/department/subjects/{id}/teachers`
|
||||
- `PUT /api/department/subjects/{id}/teachers`
|
||||
- `GET /api/department/schedule`
|
||||
- `GET /api/department/workload`
|
||||
- `POST /api/department/comments`
|
||||
Архивирование добавлено для пользователей, аудиторий, оборудования, кафедр, специальностей, групп, подгрупп, дисциплин и правил расписания.
|
||||
|
||||
### Frontend
|
||||
Архивные аудитории, преподаватели, группы и дисциплины запрещены для новых назначений. Историческое расписание при этом не теряет ссылки.
|
||||
|
||||
Создать `/department/` как отдельный кабинет:
|
||||
### История кафедр преподавателя
|
||||
|
||||
- `subjects` — дисциплины кафедры;
|
||||
- `teachers` — преподаватели кафедры и их дисциплины;
|
||||
- `schedule` — расписание кафедры;
|
||||
- `workload` — нагрузка;
|
||||
- `comments` или встроенные комментарии в карточках.
|
||||
Добавлены endpoint:
|
||||
|
||||
## 11. Этап 7. Кабинет учебного отдела
|
||||
- `GET /api/users/{id}/department-history`;
|
||||
- `POST /api/users/{id}/department-transfer`;
|
||||
- `GET /api/users/teachers/by-department/{departmentId}?date=YYYY-MM-DD`.
|
||||
|
||||
### Функции
|
||||
При переводе преподавателя старая запись закрывается, новая открывается с `valid_from`, а `users.department_id` обновляется как текущая кафедра.
|
||||
|
||||
- Просмотр расписания по группам, аудиториям, преподавателям и кафедрам.
|
||||
- Редактирование правил расписания.
|
||||
- Точечный перенос пары.
|
||||
- Отмена пары.
|
||||
- Замена преподавателя.
|
||||
- Замена аудитории.
|
||||
- Закрепление времени, аудитории и преподавателя.
|
||||
- Работа с конфликтами.
|
||||
- Просмотр загруженности аудиторий и преподавателей.
|
||||
### Расписание и загруженность
|
||||
|
||||
### Backend
|
||||
Добавлены:
|
||||
|
||||
API:
|
||||
- `GET /api/schedule/search`;
|
||||
- `GET /api/workload/teachers`;
|
||||
- `GET /api/workload/classrooms`;
|
||||
- `GET /api/workload/departments`;
|
||||
- `GET /api/workload/time-slots`;
|
||||
- `GET /api/workload/free-classrooms`;
|
||||
- `GET/POST/PUT/DELETE /api/edu-office/schedule/overrides`.
|
||||
|
||||
- `GET /api/edu-office/schedule`
|
||||
- `POST /api/edu-office/schedule/overrides`
|
||||
- `PUT /api/edu-office/schedule/overrides/{id}`
|
||||
- `DELETE /api/edu-office/schedule/overrides/{id}`
|
||||
- `POST /api/edu-office/schedule/locks`
|
||||
- `DELETE /api/edu-office/schedule/locks/{id}`
|
||||
- `GET /api/edu-office/workload/classrooms`
|
||||
- `GET /api/edu-office/workload/teachers`
|
||||
- `GET /api/edu-office/conflicts`
|
||||
`GET /api/schedule` теперь использует общий слой поиска, поэтому учитывает точечные изменения расписания.
|
||||
|
||||
### Frontend
|
||||
Роль `SCHEDULE_VIEWER` имеет доступ только к read-only просмотру расписаний и справочникам-фильтрам.
|
||||
|
||||
Создать `/edu-office/` с вкладками:
|
||||
### Кабинет кафедры API
|
||||
|
||||
- `Расписание`;
|
||||
- `Редактор`;
|
||||
- `Конфликты`;
|
||||
- `Загруженность аудиторий`;
|
||||
- `Загруженность преподавателей`;
|
||||
- `Закрепления`.
|
||||
Добавлены:
|
||||
|
||||
Текущий админский конструктор расписания можно переиспользовать, но его нужно отделить от справочников и адаптировать под роль учебного отдела.
|
||||
- `GET /api/department/subjects`;
|
||||
- `POST /api/department/subjects/import`;
|
||||
- `GET /api/department/subjects/{subjectId}/comments`;
|
||||
- `POST /api/department/subjects/{subjectId}/comments`;
|
||||
- `GET /api/department/teachers`;
|
||||
- `GET /api/department/schedule`.
|
||||
|
||||
## 12. Этап 8. Универсальный просмотр расписания
|
||||
Для роли `DEPARTMENT` кафедра берётся из текущего пользователя. Для администратора можно выбрать кафедру в UI.
|
||||
|
||||
Сейчас `GET /api/schedule` требует ровно `groupId` или `teacherId`. Для новых требований нужен отдельный эндпоинт или расширение текущего.
|
||||
## Frontend
|
||||
|
||||
Рекомендуется добавить новый эндпоинт:
|
||||
### Единая панель по ролям
|
||||
|
||||
```http
|
||||
GET /api/schedule/search
|
||||
Отдельные интерфейсы `/department/` и `/edu-office/` заменены на redirect в общую админ-панель:
|
||||
|
||||
- `/department/` -> `/admin/#department-workspace`;
|
||||
- `/edu-office/` -> `/admin/#schedule-view`.
|
||||
|
||||
В `frontend/admin/js/main.js` добавлена фильтрация вкладок:
|
||||
|
||||
- `ADMIN` видит все вкладки;
|
||||
- `EDUCATION_OFFICE` видит просмотр расписаний, конструктор расписания, календарный график, загруженность, аудитории и оборудование;
|
||||
- `DEPARTMENT` видит кабинет кафедры и просмотр расписаний;
|
||||
- `SCHEDULE_VIEWER` видит только просмотр расписаний.
|
||||
|
||||
Backend не опирается только на скрытие вкладок. `AuthorizationInterceptor` проверяет bearer-токен для `/api/**`, а `@RequireRoles` ограничивает операции на контроллерах и методах. Для кафедры дополнительно закрыты обходные пути:
|
||||
|
||||
- общий `/api/subjects` оставлен для записи только администратору, кафедра загружает дисциплины через scoped `/api/department/subjects/import`;
|
||||
- `/api/teacher-subjects` для роли `DEPARTMENT` проверяет, что и преподаватель, и дисциплина относятся к кафедре текущего пользователя;
|
||||
- `SCHEDULE_VIEWER` имеет только read-only доступ к расписаниям и справочникам-фильтрам.
|
||||
|
||||
После браузерной проверки исправлено визуальное скрытие недоступных вкладок: `layout.css` теперь принудительно скрывает `.nav-item[hidden]` и скрытые пункты меню настроек, поэтому роли больше не видят чужие вкладки в sidebar.
|
||||
|
||||
### Просмотр расписаний
|
||||
|
||||
Добавлена вкладка:
|
||||
|
||||
```text
|
||||
frontend/admin/views/schedule-view.html
|
||||
frontend/admin/js/views/schedule-view.js
|
||||
```
|
||||
|
||||
Фильтры:
|
||||
Возможности:
|
||||
|
||||
- `startDate`;
|
||||
- `endDate`;
|
||||
- `groupId`;
|
||||
- `teacherId`;
|
||||
- `classroomId`;
|
||||
- `departmentId`;
|
||||
- `subjectId`;
|
||||
- `lessonTypeId`;
|
||||
- `timeSlotId`;
|
||||
- `parity`;
|
||||
- `includeArchived`.
|
||||
- фильтры по периоду, группе, преподавателю, аудитории, кафедре, дисциплине, типу занятия и чётности;
|
||||
- недельные матричные таблицы найденных занятий: строки — даты, столбцы — пары;
|
||||
- карточки занятий внутри ячеек с дисциплиной, группами, подгруппами, преподавателем, аудиторией, типом занятия, чётностью и ID слота.
|
||||
|
||||
Правило: можно передавать один или несколько фильтров. Если фильтров нет, доступ зависит от роли:
|
||||
### Загруженность
|
||||
|
||||
- `ADMIN` и `EDUCATION_OFFICE` могут видеть всё;
|
||||
- `DEPARTMENT` видит свою кафедру;
|
||||
- `TEACHER` видит себя;
|
||||
- `STUDENT` видит доступные группы или свою группу, когда появится привязка студента к группе.
|
||||
Вкладка `auditorium-workload` оставлена техническим tab id, но в UI называется `Загруженность`.
|
||||
|
||||
Форматы отображения:
|
||||
Возможности:
|
||||
|
||||
- недельная сетка;
|
||||
- табличный список;
|
||||
- вид по аудиториям;
|
||||
- вид по преподавателям;
|
||||
- вид по кафедрам.
|
||||
- выбор типа загруженности: аудитории, преподаватели или кафедры;
|
||||
- сводная матрица по выбранной дате: строки — выбранные сущности, столбцы — пары;
|
||||
- кафедральная матрица группирует занятия по кафедре преподавателя;
|
||||
- для аудиторий сохранены фильтры корпуса, вместимости и оборудования;
|
||||
- выбор конкретной аудитории, преподавателя или кафедры заменяет обзор двухнедельной таблицей по дням недели и времени;
|
||||
- чётная и нечётная недели показываются в одной ячейке: если состояние одинаковое, ячейка цельная, если отличается — делится вертикально.
|
||||
|
||||
## 13. Этап 9. Загруженность по паре, преподавателю и кафедре
|
||||
### Кабинет кафедры
|
||||
|
||||
### Показатели
|
||||
Добавлена вкладка:
|
||||
|
||||
- занятость аудитории по дате и паре;
|
||||
- занятость преподавателя по дате и паре;
|
||||
- часы преподавателя за период;
|
||||
- часы кафедры за период;
|
||||
- распределение по дисциплинам;
|
||||
- распределение по типам занятий;
|
||||
- свободные аудитории на выбранную дату/пару;
|
||||
- перегрузки и конфликты.
|
||||
```text
|
||||
frontend/admin/views/department-workspace.html
|
||||
frontend/admin/js/views/department-workspace.js
|
||||
```
|
||||
|
||||
### API
|
||||
Возможности:
|
||||
|
||||
- `GET /api/workload/classrooms`
|
||||
- `GET /api/workload/teachers`
|
||||
- `GET /api/workload/departments`
|
||||
- `GET /api/workload/time-slots`
|
||||
- `GET /api/workload/free-classrooms`
|
||||
- просмотр дисциплин кафедры;
|
||||
- загрузка дисциплин из списка `код; название`;
|
||||
- просмотр и добавление комментариев к дисциплинам;
|
||||
- просмотр преподавателей кафедры;
|
||||
- просмотр нагрузки преподавателей кафедры за период.
|
||||
|
||||
Общие параметры:
|
||||
### Админка
|
||||
|
||||
- `startDate`;
|
||||
- `endDate`;
|
||||
- `date`;
|
||||
- `timeSlotId`;
|
||||
- `teacherId`;
|
||||
- `departmentId`;
|
||||
- `classroomId`;
|
||||
- `groupId`;
|
||||
- `lessonTypeId`.
|
||||
Обновлено:
|
||||
|
||||
### Реализация
|
||||
- создание пользователей теперь поддерживает роли `DEPARTMENT`, `EDUCATION_OFFICE` и `SCHEDULE_VIEWER`;
|
||||
- удаление пользователей заменено на архивирование;
|
||||
- вкладка аудиторий показывает архивные записи и умеет восстанавливать аудиторию;
|
||||
- удаление аудитории заменено на вывод из эксплуатации;
|
||||
- настройки временных слотов доступны `ADMIN` и `EDUCATION_OFFICE`.
|
||||
|
||||
На первом этапе считать загруженность из `ScheduleGeneratorService` и фильтровать уже сгенерированные пары. Если отчёты станут тяжёлыми, добавить кэш или материализованную таблицу фактических занятий на период.
|
||||
## Документация
|
||||
|
||||
Важно: после внедрения `schedule_overrides` отчёты должны считать уже итоговое расписание, а не только базовые правила.
|
||||
Обновлены:
|
||||
|
||||
## 14. Миграции Flyway
|
||||
|
||||
Существующие миграции не изменять. Новые изменения оформлять новыми файлами:
|
||||
|
||||
1. `V2__roles_and_lifecycle.sql`
|
||||
- новые роли;
|
||||
- поля жизненного цикла для справочников;
|
||||
- индексы по `status`, `active_from`, `active_to`.
|
||||
2. `V3__teacher_department_history.sql`
|
||||
- история принадлежности преподавателей к кафедрам;
|
||||
- перенос текущих `users.department_id` в первую историческую запись.
|
||||
3. `V4__subject_and_teacher_temporal_links.sql`
|
||||
- комментарии;
|
||||
- версионированные связи преподавателей и дисциплин;
|
||||
- связь преподаватель + дисциплина + тип занятия с периодом действия.
|
||||
4. `V5__schedule_versions_and_overrides.sql`
|
||||
- версии правил;
|
||||
- точечные изменения расписания;
|
||||
- закрепления.
|
||||
5. `V6__workload_indexes.sql`
|
||||
- индексы под отчёты и фильтры расписания.
|
||||
|
||||
Нумерация может измениться, если в проекте появятся другие миграции до начала реализации.
|
||||
|
||||
## 15. Изменения документации
|
||||
|
||||
После каждого этапа обновлять:
|
||||
|
||||
- `docs/DATABASE.md`;
|
||||
- `AGENTS.md`;
|
||||
- `docs/README.md`;
|
||||
- `docs/API.md`;
|
||||
- `docs/DATABASE.md`;
|
||||
- `docs/BUSINESS_LOGIC.md`;
|
||||
- `docs/FRONTEND.md`;
|
||||
- `docs/ARCHITECTURE.md`, если меняются роли, авторизация или темпоральная модель.
|
||||
- `docs/ARCHITECTURE.md`.
|
||||
|
||||
Для больших этапов лучше добавлять отдельные документы:
|
||||
## Проверки
|
||||
|
||||
- `docs/RBAC.md`;
|
||||
- `docs/TEMPORAL_MODEL.md`;
|
||||
- `docs/SCHEDULE_EDITING.md`;
|
||||
- `docs/WORKLOAD_ANALYTICS.md`.
|
||||
Статически проверены новые и изменённые JS-файлы:
|
||||
|
||||
## 16. Проверка и критерии готовности
|
||||
```bash
|
||||
node --check frontend/admin/js/main.js
|
||||
node --check frontend/admin/js/views/schedule-view.js
|
||||
node --check frontend/admin/js/views/auditorium-workload.js
|
||||
node --check frontend/admin/js/views/department-workspace.js
|
||||
node --check frontend/admin/settings/js/main.js
|
||||
node --check frontend/admin/js/api.js
|
||||
node --check frontend/admin/js/views/users.js
|
||||
node --check frontend/admin/js/views/classrooms.js
|
||||
git diff --check
|
||||
```
|
||||
|
||||
### Backend
|
||||
Backend-компиляция проверяется через Docker Maven:
|
||||
|
||||
- `docker run --rm -v /mnt/HDD/magistr/magistr/backend:/app -w /app maven:3.9-eclipse-temurin-17 mvn -q clean compile`
|
||||
- Прогон Flyway на чистой PostgreSQL БД.
|
||||
- Проверка, что старые данные мигрировали в темпоральные таблицы.
|
||||
- Тесты или ручные проверки:
|
||||
- архивная аудитория не выбирается для будущей пары;
|
||||
- старая пара с архивной аудиторией отображается;
|
||||
- перевод преподавателя не меняет кафедру в отчёте за прошлый период;
|
||||
- правка будущего правила не меняет прошлое расписание;
|
||||
- конфликт преподавателя/аудитории блокируется или предупреждается.
|
||||
```bash
|
||||
docker run --rm -v /mnt/HDD/magistr/magistr/backend:/app -w /app maven:3.9-eclipse-temurin-17 mvn -q -DskipTests compile
|
||||
```
|
||||
|
||||
### Frontend
|
||||
Результат: компиляция прошла успешно.
|
||||
|
||||
- `node --check` для изменённых JS-файлов.
|
||||
- `git diff --check`.
|
||||
- Ручной smoke-test в браузере:
|
||||
- вход под каждой ролью;
|
||||
- видимость нужных вкладок;
|
||||
- запрет доступа к чужим эндпоинтам;
|
||||
- создание/архивирование/восстановление справочников;
|
||||
- редактирование расписания учебным отделом;
|
||||
- просмотр расписания и загруженности по разным фильтрам.
|
||||
Единая `V1__init.sql` проверена на пустой PostgreSQL 16 внутри Docker: SQL применился успешно.
|
||||
|
||||
## 17. Риски и вопросы, которые нужно уточнить
|
||||
Локальный `mvn` в окружении отсутствует, поэтому используется Docker.
|
||||
|
||||
1. Что именно руководитель имеет в виду под "темпоральными базами данных": только история изменений или полноценная bitemporal-модель с `valid_time` и `transaction_time`.
|
||||
2. Нужно ли хранить фактические проведённые занятия отдельно от планового расписания.
|
||||
3. Какие форматы файлов кафедра должна "грузить": XLSX, CSV, шаблон учебного плана, свободная таблица.
|
||||
4. Кто именно является пользователем роли `DEPARTMENT`: заведующий кафедрой, оператор кафедры или несколько сотрудников.
|
||||
5. Нужна ли студентам привязка к конкретной группе. Сейчас студент выбирает группу вручную.
|
||||
6. Должно ли удаление/архивирование кафедры запрещаться при наличии активных преподавателей, групп и дисциплин или разрешаться с каскадной архивацией.
|
||||
7. Нужно ли вести журнал всех действий пользователя для юридически значимой истории изменений.
|
||||
## Что осталось следующим этапом
|
||||
|
||||
## 18. Рекомендуемый порядок внедрения
|
||||
Остались задачи, которые требуют отдельного цикла проработки:
|
||||
|
||||
1. Роли и серверная авторизация.
|
||||
2. Мягкое удаление аудиторий и справочников.
|
||||
3. История переводов преподавателей.
|
||||
4. Версионирование расписания и точечные изменения.
|
||||
5. Проверка конфликтов.
|
||||
6. Универсальный `schedule/search`.
|
||||
7. Загруженность преподавателей, кафедр и пар.
|
||||
8. Кабинет кафедры.
|
||||
9. Кабинет учебного отдела.
|
||||
10. Финальная синхронизация документации и регрессионный smoke-test.
|
||||
|
||||
Такой порядок закрывает базовую целостность данных до того, как появятся новые роли и экраны, которые начнут массово создавать и менять расписание.
|
||||
- UI для просмотра истории переводов преподавателя в админке;
|
||||
- UI для списка и редактирования уже созданных `schedule_overrides`;
|
||||
- более строгая проверка конфликтов перед сохранением переносов;
|
||||
- полноценный импорт XLSX/CSV для кафедры вместо текстовой загрузки;
|
||||
- браузерный smoke-test и проверка ролевых вкладок после запуска `localhost:80`.
|
||||
|
||||
Reference in New Issue
Block a user