ролевая моделю доступа + загруженность по кафедрам и преподавателям + просморт расписания
This commit is contained in:
@@ -9,7 +9,13 @@ CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
||||
CREATE TABLE IF NOT EXISTS departments (
|
||||
id BIGSERIAL UNIQUE PRIMARY KEY NOT NULL,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
code BIGINT UNIQUE NOT NULL
|
||||
code BIGINT UNIQUE NOT NULL,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
|
||||
active_from DATE,
|
||||
active_to DATE,
|
||||
archived_at TIMESTAMP,
|
||||
archived_by BIGINT,
|
||||
archive_reason TEXT
|
||||
);
|
||||
|
||||
INSERT INTO departments (name, code) VALUES
|
||||
@@ -20,7 +26,13 @@ INSERT INTO departments (name, code) VALUES
|
||||
CREATE TABLE IF NOT EXISTS specialties (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
specialty_code VARCHAR(255) UNIQUE NOT NULL
|
||||
specialty_code VARCHAR(255) UNIQUE NOT NULL,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
|
||||
active_from DATE,
|
||||
active_to DATE,
|
||||
archived_at TIMESTAMP,
|
||||
archived_by BIGINT,
|
||||
archive_reason TEXT
|
||||
);
|
||||
|
||||
INSERT INTO specialties (name, specialty_code) VALUES
|
||||
@@ -35,6 +47,12 @@ CREATE TABLE IF NOT EXISTS specialty_profiles (
|
||||
name VARCHAR(500) NOT NULL,
|
||||
description TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
|
||||
active_from DATE,
|
||||
active_to DATE,
|
||||
archived_at TIMESTAMP,
|
||||
archived_by BIGINT,
|
||||
archive_reason TEXT,
|
||||
CONSTRAINT uq_specialty_profiles_name UNIQUE (specialty_id, name)
|
||||
);
|
||||
|
||||
@@ -50,20 +68,62 @@ CREATE TABLE IF NOT EXISTS users (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
username VARCHAR(50) UNIQUE NOT NULL,
|
||||
password VARCHAR(255) NOT NULL,
|
||||
role VARCHAR(20) NOT NULL DEFAULT 'STUDENT',
|
||||
role VARCHAR(30) NOT NULL DEFAULT 'STUDENT',
|
||||
full_name VARCHAR(255) NOT NULL,
|
||||
job_title VARCHAR(255) NOT NULL,
|
||||
department_id BIGINT NOT NULL REFERENCES departments(id),
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
|
||||
active_from DATE,
|
||||
active_to DATE,
|
||||
archived_at TIMESTAMP,
|
||||
archived_by BIGINT,
|
||||
archive_reason TEXT
|
||||
);
|
||||
|
||||
-- Админ по умолчанию: admin / admin (bcrypt через pgcrypto)
|
||||
INSERT INTO users (username, password, role, full_name, job_title, department_id)
|
||||
VALUES ('admin', crypt('admin', gen_salt('bf', 10)), 'ADMIN', 'Иванов Админ Иванович', 'Доцент', 1),
|
||||
('Тестовый преподаватель', crypt('1234567890', gen_salt('bf', 10)), 'TEACHER', 'Петров Препод Петрович', 'Профессор', 2)
|
||||
('Тестовый преподаватель', crypt('1234567890', gen_salt('bf', 10)), 'TEACHER', 'Петров Препод Петрович', 'Профессор', 2),
|
||||
('учебный_отдел', crypt('1234567890', gen_salt('bf', 10)), 'EDUCATION_OFFICE', 'Оператор учебного отдела', 'Учебный отдел', 1),
|
||||
('кафедра_иб', crypt('1234567890', gen_salt('bf', 10)), 'DEPARTMENT', 'Оператор кафедры ИБ', 'Кафедра', 1),
|
||||
('просмотр_расписаний', crypt('1234567890', gen_salt('bf', 10)), 'SCHEDULE_VIEWER', 'Оператор просмотра расписаний', 'Просмотр расписаний', 1)
|
||||
ON CONFLICT (username) DO NOTHING;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS teacher_department_assignments (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
teacher_id BIGINT NOT NULL REFERENCES users(id),
|
||||
department_id BIGINT NOT NULL REFERENCES departments(id),
|
||||
valid_from DATE NOT NULL,
|
||||
valid_to DATE,
|
||||
is_primary BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
comment TEXT,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
created_by BIGINT REFERENCES users(id),
|
||||
CONSTRAINT chk_teacher_department_dates CHECK (valid_to IS NULL OR valid_to >= valid_from)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_teacher_department_teacher_dates
|
||||
ON teacher_department_assignments(teacher_id, valid_from, valid_to);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_teacher_department_department_dates
|
||||
ON teacher_department_assignments(department_id, valid_from, valid_to);
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uq_teacher_department_open_primary
|
||||
ON teacher_department_assignments(teacher_id)
|
||||
WHERE is_primary = TRUE AND valid_to IS NULL;
|
||||
|
||||
INSERT INTO teacher_department_assignments (teacher_id, department_id, valid_from, is_primary, comment)
|
||||
SELECT u.id, u.department_id, COALESCE(u.created_at::DATE, CURRENT_DATE), TRUE, 'Начальная кафедра из users.department_id'
|
||||
FROM users u
|
||||
WHERE u.role = 'TEACHER'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM teacher_department_assignments existing
|
||||
WHERE existing.teacher_id = u.id
|
||||
);
|
||||
|
||||
-- ==========================================
|
||||
-- Образовательные формы
|
||||
-- ==========================================
|
||||
@@ -71,7 +131,13 @@ CREATE TABLE IF NOT EXISTS education_forms (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
name VARCHAR(100) UNIQUE NOT NULL,
|
||||
description TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
|
||||
active_from DATE,
|
||||
active_to DATE,
|
||||
archived_at TIMESTAMP,
|
||||
archived_by BIGINT,
|
||||
archive_reason TEXT
|
||||
);
|
||||
|
||||
INSERT INTO education_forms (name) VALUES
|
||||
@@ -92,7 +158,13 @@ CREATE TABLE IF NOT EXISTS student_groups (
|
||||
specialty_id BIGINT NOT NULL REFERENCES specialties(id),
|
||||
specialty_profile_id BIGINT NOT NULL REFERENCES specialty_profiles(id),
|
||||
year_start_study BIGINT NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
|
||||
active_from DATE,
|
||||
active_to DATE,
|
||||
archived_at TIMESTAMP,
|
||||
archived_by BIGINT,
|
||||
archive_reason TEXT
|
||||
);
|
||||
|
||||
-- Тестовая базовая группа для работы
|
||||
@@ -116,6 +188,12 @@ CREATE TABLE IF NOT EXISTS subgroups (
|
||||
group_id BIGINT NOT NULL REFERENCES student_groups(id) ON DELETE CASCADE,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
student_capacity INT,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
|
||||
active_from DATE,
|
||||
active_to DATE,
|
||||
archived_at TIMESTAMP,
|
||||
archived_by BIGINT,
|
||||
archive_reason TEXT,
|
||||
UNIQUE(group_id, name)
|
||||
);
|
||||
|
||||
@@ -146,7 +224,13 @@ CREATE TABLE IF NOT EXISTS subjects (
|
||||
code VARCHAR(20),
|
||||
department_id BIGINT NOT NULL REFERENCES departments(id),
|
||||
description TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
|
||||
active_from DATE,
|
||||
active_to DATE,
|
||||
archived_at TIMESTAMP,
|
||||
archived_by BIGINT,
|
||||
archive_reason TEXT
|
||||
);
|
||||
|
||||
INSERT INTO subjects (name, department_id) VALUES
|
||||
@@ -157,6 +241,17 @@ INSERT INTO subjects (name, department_id) VALUES
|
||||
('Английский язык', 1)
|
||||
ON CONFLICT (name) DO NOTHING;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS subject_comments (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
subject_id BIGINT NOT NULL REFERENCES subjects(id),
|
||||
author_id BIGINT REFERENCES users(id),
|
||||
comment TEXT NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_subject_comments_subject
|
||||
ON subject_comments(subject_id, created_at DESC);
|
||||
|
||||
-- Типы занятий
|
||||
CREATE TABLE IF NOT EXISTS lesson_types (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
@@ -176,7 +271,13 @@ CREATE TABLE IF NOT EXISTS equipments (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
name VARCHAR(50) UNIQUE NOT NULL,
|
||||
description TEXT,
|
||||
inventory_number VARCHAR(50)
|
||||
inventory_number VARCHAR(50),
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
|
||||
active_from DATE,
|
||||
active_to DATE,
|
||||
archived_at TIMESTAMP,
|
||||
archived_by BIGINT,
|
||||
archive_reason TEXT
|
||||
);
|
||||
|
||||
INSERT INTO equipments (name) VALUES
|
||||
@@ -197,7 +298,13 @@ CREATE TABLE IF NOT EXISTS classrooms (
|
||||
floor INT,
|
||||
is_available BOOLEAN DEFAULT TRUE,
|
||||
description TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
|
||||
active_from DATE,
|
||||
active_to DATE,
|
||||
archived_at TIMESTAMP,
|
||||
archived_by BIGINT,
|
||||
archive_reason TEXT
|
||||
);
|
||||
|
||||
INSERT INTO classrooms (name, capacity, building, floor) VALUES
|
||||
@@ -229,6 +336,17 @@ WHERE
|
||||
OR (c.name = '303 Обычная' AND e.name IN ('Проектор'))
|
||||
ON CONFLICT (classroom_id, equipment_id) DO NOTHING;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_departments_status ON departments(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_specialties_status ON specialties(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_specialty_profiles_status ON specialty_profiles(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_users_status ON users(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_education_forms_status ON education_forms(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_student_groups_status ON student_groups(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_subgroups_status ON subgroups(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_subjects_status ON subjects(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_equipments_status ON equipments(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_classrooms_status ON classrooms(status);
|
||||
|
||||
-- ==========================================
|
||||
-- Связи для преподавателей
|
||||
-- ==========================================
|
||||
@@ -483,6 +601,13 @@ CREATE TABLE IF NOT EXISTS schedule_rules (
|
||||
lecture_start_week INT NOT NULL,
|
||||
laboratory_start_week INT NOT NULL,
|
||||
practice_start_week INT NOT NULL,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
|
||||
valid_from DATE,
|
||||
valid_to DATE,
|
||||
version_group_id BIGINT,
|
||||
change_reason TEXT,
|
||||
created_by BIGINT REFERENCES users(id),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT chk_schedule_rules_type_hours_non_negative CHECK (
|
||||
lecture_academic_hours >= 0
|
||||
AND laboratory_academic_hours >= 0
|
||||
@@ -495,11 +620,14 @@ CREATE TABLE IF NOT EXISTS schedule_rules (
|
||||
lecture_start_week > 0
|
||||
AND laboratory_start_week > 0
|
||||
AND practice_start_week > 0
|
||||
)
|
||||
),
|
||||
CONSTRAINT chk_schedule_rules_dates CHECK (valid_to IS NULL OR valid_from IS NULL OR valid_to >= valid_from)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_schedule_rules_semester ON schedule_rules(semester_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_schedule_rules_subject ON schedule_rules(subject_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_schedule_rules_status_dates
|
||||
ON schedule_rules(status, valid_from, valid_to);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS schedule_rule_groups (
|
||||
schedule_rule_id BIGINT NOT NULL REFERENCES schedule_rules(id) ON DELETE CASCADE,
|
||||
@@ -519,6 +647,12 @@ CREATE TABLE IF NOT EXISTS schedule_rule_slots (
|
||||
classroom_id BIGINT NOT NULL REFERENCES classrooms(id),
|
||||
lesson_type_id BIGINT NOT NULL REFERENCES lesson_types(id),
|
||||
lesson_format VARCHAR(30) NOT NULL,
|
||||
time_locked BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
classroom_locked BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
teacher_locked BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
locked_by BIGINT REFERENCES users(id),
|
||||
locked_at TIMESTAMP,
|
||||
lock_comment TEXT,
|
||||
CONSTRAINT chk_schedule_rule_slots_day CHECK (day_of_week BETWEEN 1 AND 7),
|
||||
CONSTRAINT chk_schedule_rule_slots_parity CHECK (parity IN ('BOTH', 'EVEN', 'ODD')),
|
||||
CONSTRAINT chk_schedule_rule_slots_format CHECK (lesson_format IN ('Очно', 'Онлайн'))
|
||||
@@ -537,6 +671,28 @@ CREATE TABLE IF NOT EXISTS schedule_rule_slot_subgroups (
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_schedule_rule_slot_subgroups_subgroup ON schedule_rule_slot_subgroups(subgroup_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS schedule_overrides (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
base_rule_slot_id BIGINT NOT NULL REFERENCES schedule_rule_slots(id),
|
||||
lesson_date DATE NOT NULL,
|
||||
action VARCHAR(20) NOT NULL,
|
||||
new_time_slot_id BIGINT REFERENCES time_slots(id),
|
||||
new_classroom_id BIGINT REFERENCES classrooms(id),
|
||||
new_teacher_id BIGINT REFERENCES users(id),
|
||||
new_lesson_format VARCHAR(30),
|
||||
comment TEXT,
|
||||
created_by BIGINT REFERENCES users(id),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT chk_schedule_overrides_action CHECK (action IN ('MOVE', 'CANCEL', 'REPLACE')),
|
||||
CONSTRAINT uq_schedule_overrides_slot_date UNIQUE (base_rule_slot_id, lesson_date)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_schedule_overrides_date
|
||||
ON schedule_overrides(lesson_date);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_schedule_overrides_new_teacher
|
||||
ON schedule_overrides(new_teacher_id);
|
||||
|
||||
CREATE OR REPLACE FUNCTION validate_schedule_rule_slot_subgroups()
|
||||
RETURNS TRIGGER AS $$
|
||||
DECLARE
|
||||
@@ -762,12 +918,17 @@ COMMENT ON TABLE schedule_rules IS 'Правила динамической ге
|
||||
COMMENT ON TABLE schedule_rule_groups IS 'Привязка правил расписания к учебным группам';
|
||||
COMMENT ON TABLE schedule_rule_slots IS 'Слоты проведения занятий внутри правила расписания';
|
||||
COMMENT ON TABLE schedule_rule_slot_subgroups IS 'Подгруппы лабораторных слотов правила расписания';
|
||||
COMMENT ON TABLE teacher_department_assignments IS 'История принадлежности преподавателей к кафедрам';
|
||||
COMMENT ON TABLE subject_comments IS 'Комментарии кафедр и администраторов к дисциплинам';
|
||||
COMMENT ON TABLE schedule_overrides IS 'Точечные изменения конкретных сгенерированных пар';
|
||||
COMMENT ON COLUMN schedule_rules.lecture_academic_hours IS 'Лимит академических часов лекций';
|
||||
COMMENT ON COLUMN schedule_rules.laboratory_academic_hours IS 'Лимит академических часов лабораторных работ';
|
||||
COMMENT ON COLUMN schedule_rules.practice_academic_hours IS 'Лимит академических часов практик';
|
||||
COMMENT ON COLUMN schedule_rules.lecture_start_week IS 'Неделя начала лекций в семестре';
|
||||
COMMENT ON COLUMN schedule_rules.laboratory_start_week IS 'Неделя начала лабораторных работ в семестре';
|
||||
COMMENT ON COLUMN schedule_rules.practice_start_week IS 'Неделя начала практик в семестре';
|
||||
COMMENT ON COLUMN schedule_rules.valid_from IS 'Дата начала действия версии правила расписания';
|
||||
COMMENT ON COLUMN schedule_rules.valid_to IS 'Дата окончания действия версии правила расписания';
|
||||
|
||||
COMMENT ON TABLE education_forms IS 'Формы обучения';
|
||||
COMMENT ON TABLE subgroups IS 'Подгруппы';
|
||||
@@ -782,6 +943,7 @@ COMMENT ON COLUMN users.id IS 'ID пользователя';
|
||||
COMMENT ON COLUMN users.username IS 'Логин пользователя';
|
||||
COMMENT ON COLUMN users.password IS 'Хэш пароля пользователя';
|
||||
COMMENT ON COLUMN users.role IS 'Роль пользователя';
|
||||
COMMENT ON COLUMN users.status IS 'Жизненный цикл пользователя: ACTIVE или ARCHIVED';
|
||||
COMMENT ON COLUMN users.created_at IS 'Дата и время создания';
|
||||
COMMENT ON COLUMN users.updated_at IS 'Дата и время последнего обновления';
|
||||
COMMENT ON COLUMN users.full_name IS 'ФИО пользователя';
|
||||
@@ -833,6 +995,7 @@ COMMENT ON COLUMN classrooms.floor IS 'Этаж';
|
||||
COMMENT ON COLUMN classrooms.is_available IS 'Доступность аудитории';
|
||||
COMMENT ON COLUMN classrooms.description IS 'Описание аудитории';
|
||||
COMMENT ON COLUMN classrooms.created_at IS 'Дата и время создания';
|
||||
COMMENT ON COLUMN classrooms.status IS 'Жизненный цикл аудитории: ACTIVE или ARCHIVED';
|
||||
|
||||
COMMENT ON COLUMN classroom_equipments.classroom_id IS 'ID аудитории';
|
||||
COMMENT ON COLUMN classroom_equipments.equipment_id IS 'ID оборудования';
|
||||
|
||||
Reference in New Issue
Block a user