задачи 2 и 8
This commit is contained in:
@@ -286,10 +286,37 @@ erDiagram
|
||||
BIGINT calendar_id FK
|
||||
}
|
||||
|
||||
schedule_versions {
|
||||
BIGSERIAL id PK
|
||||
BIGINT semester_id FK
|
||||
INT version_number
|
||||
VARCHAR name
|
||||
VARCHAR status
|
||||
BIGINT based_on_version_id FK
|
||||
BIGINT restored_from_version_id FK
|
||||
TEXT change_reason
|
||||
BIGINT created_by FK
|
||||
TIMESTAMPTZ created_at
|
||||
BIGINT published_by FK
|
||||
TIMESTAMPTZ published_at
|
||||
TIMESTAMPTZ archived_at
|
||||
}
|
||||
|
||||
schedule_version_history {
|
||||
BIGSERIAL id PK
|
||||
BIGINT version_id FK
|
||||
VARCHAR action
|
||||
BIGINT actor_id FK
|
||||
TEXT reason
|
||||
TIMESTAMPTZ created_at
|
||||
}
|
||||
|
||||
schedule_rules {
|
||||
BIGSERIAL id PK
|
||||
BIGINT subject_id FK
|
||||
BIGINT semester_id FK
|
||||
BIGINT schedule_version_id FK
|
||||
BIGINT version_group_id
|
||||
VARCHAR status
|
||||
DATE valid_from
|
||||
DATE valid_to
|
||||
@@ -442,6 +469,12 @@ erDiagram
|
||||
academic_years ||--o{ semesters : "academic_year_id"
|
||||
academic_years ||--o{ academic_calendars : "academic_year_id"
|
||||
academic_years ||--o{ student_group_calendar_assignments : "academic_year_id"
|
||||
semesters ||--o{ schedule_versions : "semester_id"
|
||||
schedule_versions ||--o{ schedule_rules : "schedule_version_id"
|
||||
schedule_versions ||--o{ schedule_version_history : "version_id"
|
||||
schedule_versions o|--o{ schedule_versions : "based_on/restored_from"
|
||||
users ||--o{ schedule_versions : "created_by/published_by"
|
||||
users ||--o{ schedule_version_history : "actor_id"
|
||||
semesters ||--o{ schedule_rules : "semester_id"
|
||||
specialties ||--o{ academic_calendars : "specialty_id"
|
||||
specialty_profiles ||--o{ academic_calendars : "specialty_profile_id"
|
||||
@@ -896,12 +929,50 @@ V1 создаёт GiST exclusion constraint `ex_academic_years_no_overlap` дл
|
||||
триггеры защищают назначение при изменении группы, графика и границ учебного года; блокировки
|
||||
ссылочных строк закрывают конкурентные записи между несколькими backend-pod.
|
||||
|
||||
#### `schedule_versions` — Версии расписания семестра
|
||||
|
||||
| Колонка | Тип | Описание |
|
||||
|---------|-----|----------|
|
||||
| `id` | BIGSERIAL PK | ID версии |
|
||||
| `semester_id` | BIGINT FK → semesters (CASCADE) | Семестр |
|
||||
| `version_number` | INT CHECK(> 0) | Последовательный номер внутри семестра |
|
||||
| `name` | VARCHAR(160) | Пользовательское название |
|
||||
| `status` | VARCHAR(20) | `DRAFT`, `PUBLISHED` или `ARCHIVED` |
|
||||
| `based_on_version_id` | BIGINT FK → schedule_versions | Версия-основа черновика |
|
||||
| `restored_from_version_id` | BIGINT FK → schedule_versions | Публикация, которую заменили при восстановлении |
|
||||
| `change_reason` | TEXT | Причина последней публикации или восстановления |
|
||||
| `created_by` | BIGINT FK → users | Автор черновика |
|
||||
| `created_at` | TIMESTAMPTZ | Время создания |
|
||||
| `published_by` | BIGINT FK → users | Автор публикации |
|
||||
| `published_at` | TIMESTAMPTZ | Время последней публикации |
|
||||
| `archived_at` | TIMESTAMPTZ | Время архивирования |
|
||||
|
||||
Пара `semester_id + version_number` уникальна. Частичный индекс
|
||||
`uq_schedule_versions_published_semester` запрещает более одной строки `PUBLISHED` на
|
||||
семестр. Начальная загрузка V1 создаёт опубликованную версию 1 для каждого семестра и
|
||||
привязывает к ней существующие seed-правила.
|
||||
|
||||
#### `schedule_version_history` — Аудит версий расписания
|
||||
|
||||
| Колонка | Тип | Описание |
|
||||
|---------|-----|----------|
|
||||
| `id` | BIGSERIAL PK | ID события |
|
||||
| `version_id` | BIGINT FK → schedule_versions (CASCADE) | Версия расписания |
|
||||
| `action` | VARCHAR(30) | `CREATED`, `PUBLISHED`, `ARCHIVED` или `RESTORED` |
|
||||
| `actor_id` | BIGINT FK → users | Автор действия; `NULL` для системной инициализации |
|
||||
| `reason` | TEXT | Причина или описание события, до 2000 символов |
|
||||
| `created_at` | TIMESTAMPTZ | Время события |
|
||||
|
||||
Журнал добавляется при каждом переходе версии и выводится в обратной хронологии. Он не
|
||||
заменяет данные версии, а сохраняет отдельные факты аудита.
|
||||
|
||||
#### `schedule_rules` — Правила расписания
|
||||
| Колонка | Тип | Описание |
|
||||
|---------|-----|----------|
|
||||
| `id` | BIGSERIAL PK | ID |
|
||||
| `subject_id` | BIGINT FK → subjects | Дисциплина |
|
||||
| `semester_id` | BIGINT FK → semesters | Семестр |
|
||||
| `schedule_version_id` | BIGINT FK → schedule_versions (CASCADE) | Версия расписания |
|
||||
| `lecture_academic_hours` | INT | Лимит академических часов лекций |
|
||||
| `laboratory_academic_hours` | INT | Лимит академических часов лабораторных работ |
|
||||
| `practice_academic_hours` | INT | Лимит академических часов практик |
|
||||
@@ -914,7 +985,7 @@ V1 создаёт GiST exclusion constraint `ex_academic_years_no_overlap` дл
|
||||
| `version_group_id` | BIGINT | Группа версий одного правила |
|
||||
| `change_reason` | TEXT | Причина изменения |
|
||||
|
||||
`ScheduleRule` использует собственные поля жизненного цикла `status`, `valid_from` и `valid_to`: архивированное правило или правило вне периода действия не участвует в генерации расписания. В отличие от справочников на `LifecycleEntity`, таблица не содержит `active_from`/`active_to`, поэтому состояние правила проверяется по `valid_*`.
|
||||
`ScheduleRule` использует собственные поля жизненного цикла `status`, `valid_from` и `valid_to`: архивированное правило или правило вне периода действия не участвует в генерации расписания. В отличие от справочников на `LifecycleEntity`, таблица не содержит `active_from`/`active_to`, поэтому состояние правила проверяется по `valid_*`. Публичная генерация дополнительно требует статус `PUBLISHED` у связанной версии. Уникальный индекс по `schedule_version_id + version_group_id` не позволяет дважды скопировать одну логическую линию правила в одну версию.
|
||||
|
||||
Базовая схема V1 требует, чтобы лимиты лекций, лабораторных и практик были кратны двум.
|
||||
Неотрицательность каждого лимита и положительная сумма уже закреплены ограничениями V1;
|
||||
@@ -1111,19 +1182,19 @@ CHECK фиксирует допустимую форму каждого типа
|
||||
|
||||
| Файл | Описание |
|
||||
|------|----------|
|
||||
| `V1__init.sql` | Полная baseline-схема: справочники, роли, refresh-сессии JWT, PostgreSQL rate limit и аудит входа, lifecycle-поля, история кафедр, календарные графики с интервальным хранением активностей и нумерацией недель `понедельник–воскресенье`, динамическое расписание, точечные изменения с переносом даты, seed, CHECK/UNIQUE/GiST-ограничения, конкурентно безопасные триггеры и комментарии |
|
||||
| `V2__teacher_absences_and_replacement_wizard.sql` | Реестр отсутствий преподавателей, статусы согласования и журнал применённых/отклонённых решений со ссылками на обычные `schedule_overrides` |
|
||||
| `V3__teacher_preferences_and_change_requests.sql` | Пожелания преподавателей на семестр, строгая и мягкая доступность, заявки на изменение занятия и неизменяемая история решений |
|
||||
| `V1__init.sql` | Полная baseline-схема: справочники, роли, refresh-сессии JWT, PostgreSQL rate limit и аудит входа, lifecycle-поля, история кафедр, календарные графики, динамическое расписание, версии/черновики и аудит публикаций, точечные изменения, отсутствия и журнал замен, пожелания преподавателей, заявки на изменение занятий и их история, seed, CHECK/UNIQUE/GiST-ограничения, конкурентно безопасные триггеры и комментарии |
|
||||
|
||||
### Этап разработки
|
||||
|
||||
Исторические разработческие миграции V2–V7 по прямому решению владельца проекта были
|
||||
объединены в baseline `V1`. После фиксации baseline нумерация начата заново: `V2`
|
||||
добавляет отсутствия и мастер замены, а `V3` — пожелания преподавателей и заявки на
|
||||
изменение занятий, не изменяя контрольную сумму `V1`.
|
||||
Исторические разработческие миграции V2–V7, а затем повторно созданные V2 с отсутствиями
|
||||
и мастером замены и V3 с пожеланиями и заявками преподавателей по прямому решению владельца
|
||||
проекта объединены в baseline `V1`. В каталоге миграций остаётся один файл
|
||||
`V1__init.sql`.
|
||||
Интервальное хранение активностей и правильная нумерация недель календарного графика входят
|
||||
непосредственно в V1.
|
||||
Перед применением этой редакции требуется полностью пустая tenant-схема.
|
||||
Перед применением этой редакции требуется полностью пустая tenant-схема: для базы, где
|
||||
предыдущая V1 уже записана в `flyway_schema_history`, изменённая контрольная сумма вызовет
|
||||
ошибку проверки.
|
||||
|
||||
### Полный сброс БД (локально)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user