создал систему календарного учебного графика
This commit is contained in:
76
docs/ACADEMIC_CALENDAR.md
Normal file
76
docs/ACADEMIC_CALENDAR.md
Normal file
@@ -0,0 +1,76 @@
|
||||
# Календарный учебный график
|
||||
|
||||
## Назначение
|
||||
|
||||
Календарный учебный график хранит правила учебного года в той же логике, что и исходные Excel-таблицы: для каждого курса и каждой даты указывается код активности. Динамическое расписание использует этот график как фильтр: обычные пары выводятся только в дни теоретического обучения.
|
||||
|
||||
График нужен, чтобы разные образовательные программы могли иметь разные периоды теории, экзаменов, практики, каникул и нерабочих дней. Несколько групп могут использовать один и тот же график, если они учатся по одной календарной модели.
|
||||
|
||||
## Связи данных
|
||||
|
||||
Основная цепочка выглядит так:
|
||||
|
||||
```text
|
||||
специальность -> профиль обучения -> календарный учебный график -> назначение группе
|
||||
```
|
||||
|
||||
- `specialties` хранит код и название специальности, например `09.03.04`.
|
||||
- `specialty_profiles` хранит профили внутри специальности. У одной специальности может быть несколько профилей.
|
||||
- `academic_calendars` хранит график профиля, формы обучения и учебного года.
|
||||
- `academic_calendar_days` хранит дневную сетку графика по курсу и дате.
|
||||
- `student_groups` связана со специальностью и профилем обучения.
|
||||
- `student_group_calendar_assignments` назначает группе конкретный график на учебный год.
|
||||
|
||||
Группа выбирает не код активности напрямую, а календарный график. Поэтому один график можно назначить нескольким группам.
|
||||
|
||||
## Коды активностей
|
||||
|
||||
| Код | Значение | Обычные пары |
|
||||
|-----|----------|--------------|
|
||||
| `Т` | Теоретическое обучение | Да |
|
||||
| `Э` | Экзаменационная сессия | Нет |
|
||||
| `К` | Каникулы | Нет |
|
||||
| `У` | Учебная практика | Нет |
|
||||
| `П` | Производственная практика | Нет |
|
||||
| `Пд` | Преддипломная практика | Нет |
|
||||
| `Н` | Научно-исследовательская работа | Нет |
|
||||
| `Г` | Государственная итоговая аттестация | Нет |
|
||||
| `Д` | Подготовка выпускной квалификационной работы | Нет |
|
||||
| `ПА` | Промежуточная аттестация | Нет |
|
||||
| `С` | Самостоятельная работа или специальный период | Нет |
|
||||
| `*` | Праздничный или нерабочий день | Нет |
|
||||
| `=` | День вне учебного года или пустая ячейка графика | Нет |
|
||||
|
||||
Технически разрешение генерации задаётся полем `academic_calendar_activity_types.allow_schedule`. В seed-данных `true` установлен только для `Т`.
|
||||
|
||||
## Правило генерации расписания
|
||||
|
||||
`ScheduleGeneratorService` при запросе `GET /api/schedule` проверяет календарный график до вывода занятия:
|
||||
|
||||
1. Определяется учебный год и семестр даты.
|
||||
2. Для группы находится назначение графика на этот учебный год.
|
||||
3. По году начала обучения группы вычисляется текущий курс.
|
||||
4. В `academic_calendar_days` ищется ячейка для курса и даты.
|
||||
5. Если код ячейки разрешает обычные пары, применяются правила `schedule_rules`.
|
||||
6. Если код не разрешает пары, день пропускается и академические часы не списываются.
|
||||
|
||||
Если график группе не назначен, расписание группы возвращается пустым списком без ошибки. Это сделано намеренно: отсутствие календаря означает, что нет разрешённых дат для генерации.
|
||||
|
||||
## Работа администратора
|
||||
|
||||
1. В разделе кафедр и специальностей администратор создаёт специальность и её профили.
|
||||
2. В разделе групп администратор создаёт группу, выбирая специальность и профиль обучения.
|
||||
3. В разделе расписания администратор создаёт учебный год и семестры.
|
||||
4. Там же создаётся календарный учебный график: название, учебный год, специальность, профиль, форма обучения и количество курсов.
|
||||
5. Администратор открывает сетку графика, заполняет дни вручную или массово через диапазон дат.
|
||||
6. В разделе групп администратор назначает календарный график группе на нужный учебный год.
|
||||
|
||||
После сохранения графика или назначения группы кэш динамического расписания сбрасывается. Следующий запрос `GET /api/schedule` сразу использует новые правила календаря.
|
||||
|
||||
## Особенности модели
|
||||
|
||||
- Старый отдельный механизм праздников не используется: праздник хранится кодом `*` в дневной сетке.
|
||||
- Дни вне учебного года или пустые периоды Excel хранятся кодом `=`.
|
||||
- График привязан к профилю обучения, а не только к коду специальности.
|
||||
- Название группы не является уникальным ключом; идентичные названия допустимы, если различаются другие параметры.
|
||||
- Excel-импорт в первой реализации не предусмотрен: редактор заполняет данные через сайт.
|
||||
129
docs/API.md
129
docs/API.md
@@ -101,7 +101,7 @@
|
||||
|
||||
## Динамическое расписание
|
||||
|
||||
Новая модель расписания строится из правил (`schedule_rules`) и слотов (`schedule_rule_slots`). Фактические занятия рендерятся на диапазон дат.
|
||||
Новая модель расписания строится из правил (`schedule_rules`) и слотов (`schedule_rule_slots`). Фактические занятия рендерятся на диапазон дат только для дней, где календарный учебный график группы имеет код, разрешающий обычные пары.
|
||||
|
||||
### `GET /api/schedule`
|
||||
|
||||
@@ -116,7 +116,7 @@
|
||||
| `startDate` | Да | Начало периода в формате `YYYY-MM-DD` |
|
||||
| `endDate` | Да | Конец периода в формате `YYYY-MM-DD` |
|
||||
|
||||
Передаётся ровно один параметр: `groupId` или `teacherId`. Максимальный диапазон — 120 дней.
|
||||
Передаётся ровно один параметр: `groupId` или `teacherId`. Максимальный диапазон — 120 дней. Если у группы нет назначения календарного графика на учебный год даты, расписание для неё возвращается пустым списком.
|
||||
|
||||
**Пример:**
|
||||
```http
|
||||
@@ -150,7 +150,7 @@ GET /api/schedule?groupId=1&startDate=2026-04-27&endDate=2026-05-03
|
||||
"subgroupId": null,
|
||||
"groupIds": [1],
|
||||
"groupNames": ["ИВТ-21-1"],
|
||||
"activityType": "THEORY",
|
||||
"activityType": "Т",
|
||||
"totalAcademicHours": 72,
|
||||
"consumedAcademicHoursBeforeLesson": 24,
|
||||
"remainingAcademicHoursAfterLesson": 46
|
||||
@@ -179,7 +179,7 @@ GET /api/schedule?groupId=1&startDate=2026-04-27&endDate=2026-05-03
|
||||
}
|
||||
```
|
||||
|
||||
### Календарный график администратора
|
||||
### Учебные годы, семестры и коды календарного графика
|
||||
|
||||
| Метод | URL | Назначение |
|
||||
|-------|-----|------------|
|
||||
@@ -190,12 +190,59 @@ GET /api/schedule?groupId=1&startDate=2026-04-27&endDate=2026-05-03
|
||||
| `GET` | `/api/admin/calendar/years/{academicYearId}/semesters` | Семестры учебного года |
|
||||
| `POST` | `/api/admin/calendar/years/{academicYearId}/semesters` | Создать семестр |
|
||||
| `PUT` | `/api/admin/calendar/semesters/{id}` | Обновить семестр |
|
||||
| `GET` | `/api/admin/calendar/holidays?academicYearId=1` | Праздники учебного года |
|
||||
| `POST` | `/api/admin/calendar/holidays` | Создать праздник |
|
||||
| `PUT` | `/api/admin/calendar/holidays/{id}` | Обновить праздник |
|
||||
| `DELETE` | `/api/admin/calendar/holidays/{id}` | Удалить праздник |
|
||||
| `GET` | `/api/admin/calendar/matrix?semesterId=1&courseNumber=1&specialtyId=2` | Матрица учебного графика |
|
||||
| `PUT` | `/api/admin/calendar/matrix` | Массовое сохранение матрицы |
|
||||
| `GET` | `/api/admin/calendar/activity-types` | Справочник кодов активностей графика |
|
||||
| `POST` | `/api/admin/calendar/activity-types` | Создать код активности |
|
||||
| `PUT` | `/api/admin/calendar/activity-types/{id}` | Обновить код активности |
|
||||
| `DELETE` | `/api/admin/calendar/activity-types/{id}` | Удалить код активности |
|
||||
|
||||
**Тело создания/обновления кода активности:**
|
||||
```json
|
||||
{
|
||||
"code": "Т",
|
||||
"name": "Теоретическое обучение",
|
||||
"allowSchedule": true,
|
||||
"colorCode": "#22c55e",
|
||||
"displayOrder": 10,
|
||||
"description": "Обычные пары разрешены"
|
||||
}
|
||||
```
|
||||
|
||||
### Календарные учебные графики
|
||||
|
||||
| Метод | URL | Назначение |
|
||||
|-------|-----|------------|
|
||||
| `GET` | `/api/admin/academic-calendars` | Список графиков, фильтры `academicYearId`, `specialtyId`, `profileId` |
|
||||
| `GET` | `/api/admin/academic-calendars/study-forms` | Формы обучения графика |
|
||||
| `GET` | `/api/admin/academic-calendars/{id}` | Один график |
|
||||
| `POST` | `/api/admin/academic-calendars` | Создать график |
|
||||
| `PUT` | `/api/admin/academic-calendars/{id}` | Обновить график |
|
||||
| `DELETE` | `/api/admin/academic-calendars/{id}` | Удалить график |
|
||||
| `GET` | `/api/admin/academic-calendars/{id}/grid` | Дневная сетка графика |
|
||||
| `PUT` | `/api/admin/academic-calendars/{id}/grid` | Полное сохранение дневной сетки |
|
||||
|
||||
**Тело создания/обновления графика:**
|
||||
```json
|
||||
{
|
||||
"title": "09.03.04 очная форма 2025-2026",
|
||||
"academicYearId": 1,
|
||||
"specialtyId": 2,
|
||||
"specialtyProfileId": 3,
|
||||
"studyFormId": 1,
|
||||
"courseCount": 4
|
||||
}
|
||||
```
|
||||
|
||||
**Ячейка сетки графика:**
|
||||
```json
|
||||
{
|
||||
"calendarId": 1,
|
||||
"courseNumber": 1,
|
||||
"date": "2025-09-01",
|
||||
"weekNumber": 1,
|
||||
"dayOfWeek": 1,
|
||||
"activityTypeId": 1
|
||||
}
|
||||
```
|
||||
|
||||
### `POST /api/admin/schedule-rules`
|
||||
|
||||
@@ -274,6 +321,10 @@ CRUD доступен по:
|
||||
| `POST` | `/api/specialties` | Создать специальность |
|
||||
| `PUT` | `/api/specialties/{id}` | Обновить специальность |
|
||||
| `DELETE` | `/api/specialties/{id}` | Удалить специальность |
|
||||
| `GET` | `/api/specialties/{id}/profiles` | Профили выбранной специальности |
|
||||
| `POST` | `/api/specialties/{id}/profiles` | Создать профиль |
|
||||
| `PUT` | `/api/specialties/{id}/profiles/{profileId}` | Обновить профиль |
|
||||
| `DELETE` | `/api/specialties/{id}/profiles/{profileId}` | Удалить профиль |
|
||||
|
||||
**Тело создания/обновления:**
|
||||
```json
|
||||
@@ -283,6 +334,16 @@ CRUD доступен по:
|
||||
}
|
||||
```
|
||||
|
||||
При создании специальности автоматически создаётся профиль `Без профиля`.
|
||||
|
||||
**Тело создания/обновления профиля:**
|
||||
```json
|
||||
{
|
||||
"name": "Безопасность автоматизированных систем",
|
||||
"description": "Необязательное описание"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Группы
|
||||
@@ -301,7 +362,14 @@ CRUD доступен по:
|
||||
"educationFormId": 1,
|
||||
"educationFormName": "Бакалавриат",
|
||||
"departmentId": 1,
|
||||
"yearStartStudy": 2023,
|
||||
"course": 3,
|
||||
"semester": 6,
|
||||
"specialtyId": 1,
|
||||
"specialtyCode": "09.03.04",
|
||||
"specialtyName": "Программная инженерия",
|
||||
"specialtyProfileId": 2,
|
||||
"specialtyProfileName": "Без профиля",
|
||||
"specialityCode": 1
|
||||
}
|
||||
]
|
||||
@@ -322,16 +390,53 @@ CRUD доступен по:
|
||||
"educationFormId": 1,
|
||||
"departmentId": 1,
|
||||
"yearStartStudy": 2026,
|
||||
"specialityCode": 1
|
||||
"specialtyId": 1,
|
||||
"specialtyProfileId": 2
|
||||
}
|
||||
```
|
||||
|
||||
`specialityCode` исторически содержит ID записи из `/api/specialties`; текущий курс вычисляется из `yearStartStudy`.
|
||||
`specialtyId` и `specialtyProfileId` обязательны. Поле `specialityCode` сохранено как legacy-alias для старых клиентов и исторически содержит ID записи из `/api/specialties`. Текущий курс вычисляется из `yearStartStudy`.
|
||||
|
||||
Название группы не является уникальным полем: допускается несколько групп с одинаковым `name`.
|
||||
|
||||
### `PUT /api/groups/{id}`
|
||||
|
||||
Редактирование группы.
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "ИВТ-11",
|
||||
"groupSize": 24,
|
||||
"educationFormId": 1,
|
||||
"departmentId": 1,
|
||||
"yearStartStudy": 2026,
|
||||
"specialtyId": 1,
|
||||
"specialtyProfileId": 2
|
||||
}
|
||||
```
|
||||
|
||||
### `DELETE /api/groups/{id}`
|
||||
|
||||
Удаление группы.
|
||||
|
||||
### Календарные графики группы
|
||||
|
||||
| Метод | URL | Назначение |
|
||||
|-------|-----|------------|
|
||||
| `GET` | `/api/groups/{id}/calendar-assignments` | Список назначений графиков группе |
|
||||
| `PUT` | `/api/groups/{id}/calendar-assignments` | Создать или заменить назначение на учебный год |
|
||||
| `DELETE` | `/api/groups/{id}/calendar-assignments/{assignmentId}` | Удалить назначение |
|
||||
|
||||
**Тело назначения графика:**
|
||||
```json
|
||||
{
|
||||
"academicYearId": 1,
|
||||
"calendarId": 5
|
||||
}
|
||||
```
|
||||
|
||||
Назначаемый график должен относиться к тому же учебному году, специальности и профилю, что и группа.
|
||||
|
||||
---
|
||||
|
||||
## Аудитории
|
||||
|
||||
@@ -28,9 +28,10 @@
|
||||
|
||||
### Специальности (Specialties)
|
||||
|
||||
Учебные направления с кодом по ФГОС.
|
||||
Учебные направления с кодом по ФГОС. У одной специальности может быть несколько профилей обучения, например базовый профиль и профиль конкретной образовательной программы.
|
||||
|
||||
- Примеры: «Информационная безопасность» (10.03.01), «Программная инженерия» (09.03.04)
|
||||
- При создании специальности автоматически создаётся профиль `Без профиля`
|
||||
|
||||
### Формы обучения (Education Forms)
|
||||
|
||||
@@ -41,9 +42,10 @@
|
||||
|
||||
### Учебные группы (Student Groups)
|
||||
|
||||
- **Поля:** Название (уникальное), численность, форма обучения, кафедра, специальность, год начала обучения
|
||||
- **Поля:** Название, численность, форма обучения, кафедра, специальность, профиль обучения, год начала обучения
|
||||
- **Курс:** вычисляется относительно учебного года: `год начала учебного года - year_start_study + 1`
|
||||
- **Подгруппы:** Возможно деление группы на подгруппы (таблица `subgroups`)
|
||||
- **Календарь:** на каждый учебный год группе назначается конкретный календарный учебный график
|
||||
|
||||
### Аудитории (Classrooms)
|
||||
|
||||
@@ -74,8 +76,11 @@
|
||||
| Компонент | Назначение |
|
||||
|-----------|------------|
|
||||
| `academic_years` / `semesters` | Учебные годы и семестры. Неделя 1 считается от `semesters.start_date` |
|
||||
| `holidays` | Даты, когда занятия не проводятся и часы не списываются |
|
||||
| `academic_calendar_matrix` | Тип недели для курса и специальности: теория, сессия, каникулы, практика |
|
||||
| `specialty_profiles` | Профили обучения внутри специальности |
|
||||
| `academic_calendars` | Календарный учебный график профиля, формы обучения и учебного года |
|
||||
| `academic_calendar_activity_types` | Коды Excel-графика: `Т`, `Э`, `К`, `У`, `П`, `Пд`, `Н`, `Г`, `Д`, `ПА`, `С`, `*`, `=` |
|
||||
| `academic_calendar_days` | Дневная сетка по курсу и дате |
|
||||
| `student_group_calendar_assignments` | Назначение конкретного графика группе на учебный год |
|
||||
| `time_slots` | Настраиваемая сетка пар для тенанта |
|
||||
| `schedule_rules` | Лимит часов дисциплины в семестре |
|
||||
| `schedule_rule_groups` | Группы правила, включая потоковые лекции |
|
||||
@@ -84,12 +89,14 @@
|
||||
Генератор `ScheduleGeneratorService` рендерит расписание по запросу:
|
||||
1. Определяет семестр для каждой даты диапазона.
|
||||
2. Вычисляет номер недели и чётность.
|
||||
3. Проверяет праздники и матрицу учебного графика.
|
||||
4. Загружает правила группы или преподавателя.
|
||||
5. Симулирует уже проведённые занятия от `active_from_date`.
|
||||
6. Останавливает вывод правила, когда достигнут `total_academic_hours`.
|
||||
3. Находит назначенный группе календарный учебный график на учебный год даты.
|
||||
4. Определяет код активности по курсу группы и конкретной дате.
|
||||
5. Пропускает день, если код активности не разрешает обычные пары.
|
||||
6. Загружает правила группы или преподавателя.
|
||||
7. Симулирует уже проведённые занятия от `active_from_date`.
|
||||
8. Останавливает вывод правила, когда достигнут `total_academic_hours`.
|
||||
|
||||
Праздник считается пропуском: занятие не переносится и не списывает академические часы.
|
||||
Обычные пары генерируются только на коде `Т` (`allow_schedule = true`). Экзамены, каникулы, практики, нерабочие дни, праздники `*` и дни вне учебного года `=` считаются пропуском: занятие не переносится и не списывает академические часы. Если у группы нет назначения графика на учебный год, `GET /api/schedule` возвращает пустой список для этой группы без ошибки.
|
||||
|
||||
### Временны́е слоты
|
||||
|
||||
|
||||
143
docs/DATABASE.md
143
docs/DATABASE.md
@@ -23,7 +23,14 @@ erDiagram
|
||||
specialties {
|
||||
BIGSERIAL id PK
|
||||
VARCHAR name
|
||||
VARCHAR specialty_code
|
||||
VARCHAR specialty_code UK
|
||||
}
|
||||
|
||||
specialty_profiles {
|
||||
BIGSERIAL id PK
|
||||
BIGINT specialty_id FK
|
||||
VARCHAR name
|
||||
TEXT description
|
||||
}
|
||||
|
||||
users {
|
||||
@@ -47,11 +54,12 @@ erDiagram
|
||||
|
||||
student_groups {
|
||||
BIGSERIAL id PK
|
||||
VARCHAR name UK
|
||||
VARCHAR name
|
||||
BIGINT group_size
|
||||
BIGINT education_form_id FK
|
||||
BIGINT department_id FK
|
||||
BIGINT specialty_code FK
|
||||
BIGINT specialty_id FK
|
||||
BIGINT specialty_profile_id FK
|
||||
BIGINT year_start_study
|
||||
TIMESTAMP created_at
|
||||
}
|
||||
@@ -140,20 +148,48 @@ erDiagram
|
||||
DATE end_date
|
||||
}
|
||||
|
||||
holidays {
|
||||
calendar_study_forms {
|
||||
BIGSERIAL id PK
|
||||
DATE date
|
||||
BIGINT academic_year_id FK
|
||||
VARCHAR description
|
||||
VARCHAR name UK
|
||||
TEXT description
|
||||
}
|
||||
|
||||
academic_calendar_matrix {
|
||||
academic_calendar_activity_types {
|
||||
BIGSERIAL id PK
|
||||
BIGINT semester_id FK
|
||||
INT course_number
|
||||
VARCHAR code UK
|
||||
VARCHAR name
|
||||
BOOLEAN allow_schedule
|
||||
VARCHAR color_code
|
||||
INT display_order
|
||||
}
|
||||
|
||||
academic_calendars {
|
||||
BIGSERIAL id PK
|
||||
VARCHAR title
|
||||
BIGINT academic_year_id FK
|
||||
BIGINT specialty_id FK
|
||||
BIGINT specialty_profile_id FK
|
||||
BIGINT study_form_id FK
|
||||
INT course_count
|
||||
TIMESTAMP created_at
|
||||
TIMESTAMP updated_at
|
||||
}
|
||||
|
||||
academic_calendar_days {
|
||||
BIGSERIAL id PK
|
||||
BIGINT calendar_id FK
|
||||
INT course_number
|
||||
DATE date
|
||||
INT week_number
|
||||
VARCHAR activity_type
|
||||
INT day_of_week
|
||||
BIGINT activity_type_id FK
|
||||
}
|
||||
|
||||
student_group_calendar_assignments {
|
||||
BIGSERIAL id PK
|
||||
BIGINT group_id FK
|
||||
BIGINT academic_year_id FK
|
||||
BIGINT calendar_id FK
|
||||
}
|
||||
|
||||
schedule_rules {
|
||||
@@ -186,9 +222,12 @@ erDiagram
|
||||
departments ||--o{ student_groups : "department_id"
|
||||
departments ||--o{ subjects : "department_id"
|
||||
education_forms ||--o{ student_groups : "education_form_id"
|
||||
specialties ||--o{ student_groups : "specialty_code"
|
||||
specialties ||--o{ specialty_profiles : "specialty_id"
|
||||
specialties ||--o{ student_groups : "specialty_id"
|
||||
specialty_profiles ||--o{ student_groups : "specialty_profile_id"
|
||||
student_groups ||--o{ subgroups : "group_id"
|
||||
student_groups ||--o{ schedule_rule_groups : "group_id"
|
||||
student_groups ||--o{ student_group_calendar_assignments : "group_id"
|
||||
users ||--o{ teacher_subjects : "user_id"
|
||||
users ||--o{ teacher_lesson_types : "user_id"
|
||||
subjects ||--o{ teacher_subjects : "subject_id"
|
||||
@@ -200,10 +239,15 @@ erDiagram
|
||||
classrooms ||--o{ classroom_equipments : "classroom_id"
|
||||
equipments ||--o{ classroom_equipments : "equipment_id"
|
||||
academic_years ||--o{ semesters : "academic_year_id"
|
||||
academic_years ||--o{ holidays : "academic_year_id"
|
||||
semesters ||--o{ academic_calendar_matrix : "semester_id"
|
||||
academic_years ||--o{ academic_calendars : "academic_year_id"
|
||||
academic_years ||--o{ student_group_calendar_assignments : "academic_year_id"
|
||||
semesters ||--o{ schedule_rules : "semester_id"
|
||||
specialties ||--o{ academic_calendar_matrix : "specialty_id"
|
||||
specialties ||--o{ academic_calendars : "specialty_id"
|
||||
specialty_profiles ||--o{ academic_calendars : "specialty_profile_id"
|
||||
calendar_study_forms ||--o{ academic_calendars : "study_form_id"
|
||||
academic_calendars ||--o{ academic_calendar_days : "calendar_id"
|
||||
academic_calendars ||--o{ student_group_calendar_assignments : "calendar_id"
|
||||
academic_calendar_activity_types ||--o{ academic_calendar_days : "activity_type_id"
|
||||
schedule_rules ||--o{ schedule_rule_groups : "schedule_rule_id"
|
||||
schedule_rules ||--o{ schedule_rule_slots : "schedule_rule_id"
|
||||
time_slots ||--o{ schedule_rule_slots : "time_slot_id"
|
||||
@@ -229,7 +273,15 @@ erDiagram
|
||||
|---------|-----|----------|
|
||||
| `id` | BIGSERIAL PK | ID специальности |
|
||||
| `name` | VARCHAR(255) | Название специальности |
|
||||
| `specialty_code` | VARCHAR(255) | Код ФГОС (напр. `10.03.01`) |
|
||||
| `specialty_code` | VARCHAR(255) UNIQUE | Код ФГОС (напр. `10.03.01`) |
|
||||
|
||||
#### `specialty_profiles` — Профили обучения
|
||||
| Колонка | Тип | Описание |
|
||||
|---------|-----|----------|
|
||||
| `id` | BIGSERIAL PK | ID профиля |
|
||||
| `specialty_id` | BIGINT FK → specialties | Специальность, внутри которой существует профиль |
|
||||
| `name` | VARCHAR(255) | Название профиля, уникально внутри специальности |
|
||||
| `description` | TEXT | Описание профиля |
|
||||
|
||||
### Пользователи
|
||||
|
||||
@@ -261,11 +313,12 @@ erDiagram
|
||||
| Колонка | Тип | Описание |
|
||||
|---------|-----|----------|
|
||||
| `id` | BIGSERIAL PK | ID |
|
||||
| `name` | VARCHAR(100) UNIQUE | Название группы (напр. `ИВТ-21-1`) |
|
||||
| `name` | VARCHAR(100) | Название группы (напр. `ИВТ-21-1`), не уникальное |
|
||||
| `group_size` | BIGINT | Количество студентов |
|
||||
| `education_form_id` | BIGINT FK → education_forms | Форма обучения |
|
||||
| `department_id` | BIGINT FK → departments | Кафедра |
|
||||
| `specialty_code` | BIGINT FK → specialties | Специальность |
|
||||
| `specialty_id` | BIGINT FK → specialties | Специальность |
|
||||
| `specialty_profile_id` | BIGINT FK → specialty_profiles | Профиль обучения группы |
|
||||
| `year_start_study` | BIGINT | Год начала обучения, используется для вычисления текущего курса |
|
||||
|
||||
#### `subgroups` — Подгруппы
|
||||
@@ -367,23 +420,55 @@ erDiagram
|
||||
| `start_date` | DATE | Дата начала, от неё считается неделя 1 |
|
||||
| `end_date` | DATE | Дата окончания |
|
||||
|
||||
#### `holidays` — Праздники и исключения
|
||||
#### `calendar_study_forms` — Формы обучения календарного графика
|
||||
| Колонка | Тип | Описание |
|
||||
|---------|-----|----------|
|
||||
| `id` | BIGSERIAL PK | ID |
|
||||
| `date` | DATE | Неучебная дата |
|
||||
| `academic_year_id` | BIGINT FK → academic_years | Учебный год |
|
||||
| `description` | VARCHAR(255) | Описание |
|
||||
| `name` | VARCHAR(100) UNIQUE | Форма обучения графика, seed: `очная` |
|
||||
| `description` | TEXT | Описание |
|
||||
|
||||
#### `academic_calendar_matrix` — Матрица учебного графика
|
||||
#### `academic_calendar_activity_types` — Коды активностей графика
|
||||
| Колонка | Тип | Описание |
|
||||
|---------|-----|----------|
|
||||
| `id` | BIGSERIAL PK | ID |
|
||||
| `semester_id` | BIGINT FK → semesters | Семестр |
|
||||
| `course_number` | INT | Курс |
|
||||
| `code` | VARCHAR(10) UNIQUE | Код из Excel-графика: `Т`, `Э`, `К`, `У`, `П`, `Пд`, `Н`, `Г`, `Д`, `ПА`, `С`, `*`, `=` |
|
||||
| `name` | VARCHAR(100) | Расшифровка кода |
|
||||
| `allow_schedule` | BOOLEAN | Разрешает генерацию обычных пар |
|
||||
| `color_code` | VARCHAR(7) | HEX-цвет для редактора |
|
||||
| `display_order` | INT | Порядок вывода в UI |
|
||||
| `description` | TEXT | Дополнительное описание |
|
||||
|
||||
#### `academic_calendars` — Календарные учебные графики
|
||||
| Колонка | Тип | Описание |
|
||||
|---------|-----|----------|
|
||||
| `id` | BIGSERIAL PK | ID |
|
||||
| `title` | VARCHAR(255) | Название графика |
|
||||
| `academic_year_id` | BIGINT FK → academic_years | Учебный год |
|
||||
| `specialty_id` | BIGINT FK → specialties | Специальность |
|
||||
| `week_number` | INT | Номер недели семестра |
|
||||
| `activity_type` | VARCHAR(20) | `THEORY`, `EXAM`, `VACATION`, `PRACTICE` |
|
||||
| `specialty_profile_id` | BIGINT FK → specialty_profiles | Профиль обучения |
|
||||
| `study_form_id` | BIGINT FK → calendar_study_forms | Форма обучения графика |
|
||||
| `course_count` | INT CHECK(> 0) | Количество курсов в сетке |
|
||||
| `created_at` | TIMESTAMP | Дата создания |
|
||||
| `updated_at` | TIMESTAMP | Дата обновления |
|
||||
|
||||
#### `academic_calendar_days` — Дневная сетка календарного графика
|
||||
| Колонка | Тип | Описание |
|
||||
|---------|-----|----------|
|
||||
| `id` | BIGSERIAL PK | ID |
|
||||
| `calendar_id` | BIGINT FK → academic_calendars (CASCADE) | Календарный график |
|
||||
| `course_number` | INT | Номер курса |
|
||||
| `date` | DATE | Дата учебного года |
|
||||
| `week_number` | INT | Номер недели от начала учебного года |
|
||||
| `day_of_week` | INT CHECK(1–7) | День недели ISO |
|
||||
| `activity_type_id` | BIGINT FK → academic_calendar_activity_types | Код активности |
|
||||
|
||||
#### `student_group_calendar_assignments` — Назначения графиков группам
|
||||
| Колонка | Тип | Описание |
|
||||
|---------|-----|----------|
|
||||
| `id` | BIGSERIAL PK | ID |
|
||||
| `group_id` | BIGINT FK → student_groups (CASCADE) | Учебная группа |
|
||||
| `academic_year_id` | BIGINT FK → academic_years (CASCADE) | Учебный год |
|
||||
| `calendar_id` | BIGINT FK → academic_calendars (CASCADE) | Назначенный график |
|
||||
|
||||
#### `schedule_rules` — Правила расписания
|
||||
| Колонка | Тип | Описание |
|
||||
@@ -426,11 +511,13 @@ erDiagram
|
||||
4. Flyway запускается **программно** при первом обращении к БД тенанта (`TenantConfigWatcher.initDatabaseForTenant()`)
|
||||
5. Настройка `baselineOnMigrate=true` — если в БД уже есть данные, Flyway начнёт с baseline
|
||||
|
||||
> Текущая ветка календарного учебного графика является осознанным исключением: `V1__init.sql` переписан как новая базовая схема, а применение предполагает полный сброс БД без переноса старых данных.
|
||||
|
||||
### Текущие миграции
|
||||
|
||||
| Файл | Описание |
|
||||
|------|----------|
|
||||
| `V1__init.sql` | Инициализация: справочники, динамическое расписание, тестовые правила, триггеры, комментарии |
|
||||
| `V1__init.sql` | Инициализация: справочники, профили специальностей, календарные учебные графики, динамическое расписание, тестовые правила, триггеры, комментарии |
|
||||
|
||||
### Накатывание на существующих тенантов
|
||||
|
||||
|
||||
@@ -103,15 +103,17 @@ frontend/
|
||||
| `equipments` | Оборудование | `/api/equipments` |
|
||||
| `classrooms` | Аудитории | `/api/classrooms` |
|
||||
| `subjects` | Дисциплины | `/api/subjects` |
|
||||
| `schedule` | Конструктор правил динамического расписания, сетка пар, учебные годы, семестры, праздники и матрица графика | `/api/admin/schedule-rules`, `/api/admin/time-slots`, `/api/admin/calendar`, `/api/lesson-types` |
|
||||
| `schedule` | Конструктор правил динамического расписания, сетка пар, учебные годы, семестры и Excel-подобный редактор календарного учебного графика | `/api/admin/schedule-rules`, `/api/admin/time-slots`, `/api/admin/calendar`, `/api/admin/academic-calendars`, `/api/lesson-types` |
|
||||
| `auditorium-workload` | Загруженность аудиторий: аудитории в строках, временные слоты в столбцах | mock-данные |
|
||||
| `database` | Тенанты | `/api/database` |
|
||||
| `departments-data` | Создание, редактирование и удаление кафедр/специальностей | `/api/departments`, `/api/specialties` |
|
||||
|
||||
### Особенности админских вкладок
|
||||
|
||||
- Вкладка `groups` загружает кафедры и специальности из справочников и при создании группы отправляет `yearStartStudy`; поле `specialityCode` содержит ID выбранной специальности.
|
||||
- Вкладка `schedule` не обращается к старым `lessons` API. Создание и редактирование расписания выполняется через правила `/api/admin/schedule-rules`, где каждое правило содержит группы и набор слотов.
|
||||
- Вкладка `departments-data` использует модальные формы редактирования и маршруты `PUT/DELETE /api/departments/{id}` и `PUT/DELETE /api/specialties/{id}`.
|
||||
- Вкладка `groups` загружает кафедры, специальности, профили, учебные годы и календарные графики. Группа создаётся через `/api/groups` с `specialtyId` и `specialtyProfileId`, а блок назначений использует `/api/groups/{id}/calendar-assignments`.
|
||||
- Вкладка `auditorium-workload` показывает матрицу загруженности: строки — аудитории, столбцы — временные слоты.
|
||||
- Вкладка `schedule` не обращается к старым `lessons` API. Создание и редактирование расписания выполняется через правила `/api/admin/schedule-rules`, где каждое правило содержит группы и набор слотов. В этом же модуле администратор создаёт календарные графики, заполняет дневную сетку по курсам и кодам активностей, а сохранение сетки идёт через `/api/admin/academic-calendars/{id}/grid`.
|
||||
- Вкладка `departments-data` использует модальные формы редактирования и маршруты `PUT/DELETE /api/departments/{id}`, `PUT/DELETE /api/specialties/{id}` и CRUD профилей `/api/specialties/{id}/profiles`.
|
||||
|
||||
### Страница настроек (`/admin/settings/`)
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## Обзор
|
||||
|
||||
**Magistr** — веб-приложение для управления расписанием занятий университета. Система поддерживает мультитенантную архитектуру (каждый университет = отдельная база данных), ролевую модель доступа (Администратор, Преподаватель, Студент) и полное управление аудиторным фондом, группами, дисциплинами и преподавательским составом.
|
||||
**Magistr** — веб-приложение для управления расписанием занятий университета. Система поддерживает мультитенантную архитектуру (каждый университет = отдельная база данных), ролевую модель доступа (Администратор, Преподаватель, Студент), календарные учебные графики и полное управление аудиторным фондом, группами, дисциплинами и преподавательским составом.
|
||||
|
||||
- **Продакшн:** [https://magistr.zuev.company](https://magistr.zuev.company)
|
||||
- **Локальная разработка:** [http://localhost:80](http://localhost:80)
|
||||
@@ -106,6 +106,7 @@ magistr/
|
||||
|----------|-----------|
|
||||
| [Архитектура](ARCHITECTURE.md) | Общая архитектура, мультитенантность, взаимодействие компонентов |
|
||||
| [Бизнес-логика](BUSINESS_LOGIC.md) | Ролевая модель, правила расписания, управление ресурсами |
|
||||
| [Календарный учебный график](ACADEMIC_CALENDAR.md) | Модель графиков по специальностям, профилям и группам |
|
||||
| [База данных](DATABASE.md) | Схема БД, описание таблиц, Flyway миграции |
|
||||
| [REST API](API.md) | Все эндпоинты с примерами запросов и ответов |
|
||||
| [Инфраструктура](INFRASTRUCTURE.md) | Docker, Kubernetes, CI/CD, мониторинг |
|
||||
|
||||
Reference in New Issue
Block a user