Please use this identifier to cite or link to this item:
https://er.chdtu.edu.ua/handle/ChSTU/9537| Title: | Інформаційна система університету. Модуль інтеграції кафедри з іншими підрозділами |
| Authors: | Заспа, Григорій Олександрович Петров, Артем Олегович |
| Keywords: | інформаційно-аналітична система;мікросервісна архітектура;API GATEWAY;JAVA;SPRING BOOT;NESTJS;ANGULAR;POSTGRESQL;вибіркові дисципліни;DEANOFFICE;JWT;REST API.;information-analytical system;microservice architecture;API GATEWAY;JAVA;SPRING BOOT;NESTJS;ANGULAR;POSTGRESQL;selective courses;DEANOFFICE;JWT;REST API. |
| Issue Date: | 17-Jun-2026 |
| Abstract: | Кваліфікаційна робота бакалавра Петрова А.О. на тему «Інформаційна
система університету. Модуль інтеграції кафедри з іншими підрозділами» за
спеціальністю 121 «Інженерія програмного забезпечення». ЧДТУ, Черкаси, 2026.
Робота містить 103 сторінки, 31 рисунків, 4 таблиці 41 джерело, 4 додатки.
Роботу присвячено автоматизації адміністративної діяльності кафедри в
межах інформаційно-аналітичної системи підтримки освітньої діяльності ЧДТУ.
Актуальність обумовлена потребою в усуненні розривів інформаційних потоків
між кафедрами, деканатами та навчально-методичним відділом і мінімізації ручної
обробки даних.
Об'єкт: процес розробки програмного забезпечення інформаційних систем в
галузі освіти.
Предмет: програмний модуль інтеграції кафедри з іншими підрозділами в
рамках інформаційно-аналітичної системи підтримки освітньої діяльності
університету.
Реалізовано три модулі: формування пропозицій вибіркових дисциплін з
генерацією документів .docx, призначення кураторів групам та керування темами
кваліфікаційних робіт студентів. Застосовано мікросервісну архітектуру з
шаблоном API Gateway: Java/Spring Boot (основний бекенд), NestJS (проміжний
шар), Angular (клієнт) та PostgreSQL. Систему протестовано на модульному,
інтеграційному, системному й приймальному рівнях.
Результати інтегровано в робочу версію ІАС ЧДТУ для подальшого розвитку
підсистеми викладача. ANNOTATION The bachelor's qualification work by Petrov A.O. on the topic "University Information System. Module for Integration of the Department with Other University Units" in the specialty 121 "Software Engineering". CSTU, Cherkasy, 2026. The work contains 103 pages, 31 figures, 4 tables 41 references, 4 appendices. The work is dedicated to the automation of the administrative activity of a department within the information-analytical system for supporting the educational activity of CSTU. The relevance is determined by the need to eliminate gaps in information flows between departments, dean's offices, and the educational-methodical department, and to minimize manual data processing. Object : the process of developing software for information systems in the field of education. Subject : a software module for integrating the department with other university units within the information-analytical system for supporting the university's educational activity. Three modules have been implemented: formation of elective course proposals with generation of .docx documents, assignment of curators to academic groups, and management of students' qualification thesis topics. A microservice architecture with the API Gateway pattern was applied: Java/Spring Boot (core backend), NestJS (middleware layer), Angular (client), and PostgreSQL. The system was tested at the unit, integration, system, and acceptance levels. The results have been integrated into the working version of the CSTU information-analytical system for further development of the teacher subsystem. |
| URI: | https://er.chdtu.edu.ua/handle/ChSTU/9537 |
| Appears in Collections: | 121 Інженерія програмного забезпечення (Інженерія програмного забезпечення) |
Files in This Item:
| File | Description | Size | Format | |
|---|---|---|---|---|
| Кваліфікаційна робота бакалавра Петров Артем Олегович_2026.pdf Restricted Access | 5.42 MB | Adobe PDF | View/Open Request a copy |
Items in DSpace are protected by copyright, with all rights reserved, unless otherwise indicated.
Extracted text
МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ
ЧЕРКАСЬКИЙ ДЕРЖАВНИЙ ТЕХНОЛОГІЧНИЙ УНІВЕРСИТЕТ
Факультет інформаційних технологій і систем
Кафедра програмного забезпечення автоматизованих систем
ПОЯСНЮВАЛЬНА ЗАПИСКА
до кваліфікаційної роботи
бакалавра
На тему «Інформаційна система університету. Модуль
інтеграції кафедри з іншими підрозділами»
Виконав: студент 4 курсу, групи ПЗ-2204
спеціальності
121 «Інженерія програмного забезпечення»
(шифр і назва напряму підготовки)
Студент Петров А.О.
(прізвище та ініціали)
Керівник Заспа Г.О.
(прізвище та ініціали)
Рецензент Сметанін О.Г.
(прізвище та ініціали)
Черкаси 2026
Черкаський державний технологічний університет
повне найменування вищого навчального закладу
Факультет інформаційних технологій і систем
Кафедра програмного забезпечення автоматизованих систем
Освітній рівень бакалавр
Спеціальність 121 «Інженерія програмного забезпечення»
Освітня програма Інженерія програмного забезпечення
ЗАТВЕРДЖУЮ
Зав. кафедри ПЗАС, професор
____________________ С. Голуб
«___» _______________ 2026 року
З А В Д А Н Н Я
НА КВАЛІФІКАЦІЙНУ РОБОТУ СТУДЕНТУ
Петров Артем Олегович
(прізвище, ім’я, по батькові)
1. Тему проекту (роботи) Інформаційна система університету. Модуль інтеграції кафедри з
іншими підрозділами
Керівник проекту (роботи) Заспа Г.О. к.т.н., доцент
(прізвище, ім’я , по батькові, науковий ступінь, вчене звання)
Затверджені наказом Черкаського державного технологічного університету від « 12 » березня
2026 року №56/03-03
2. Строк подання студентом проекту (роботи)
3. Вхідні дані до проекту (роботи) структура та API існуючої інформаційно-аналітичної системи
підтримки освітньої діяльності університету; технології розробки мікросервісних веб-
застосунків
4. Зміст розрахунково-пояснювальної записки (перелік питань, які потрібно розробити) Вступ;
Розділ 1. Аналіз інформаційно-аналітичної системи університету, постановка задачі, огляд
аналогів та обґрунтування вибору технологій; Розділ 2. Моделювання предметної області,
формування вимог, проектування логічної структури та архітектури системи; Розділ 3. Розробка
програмного забезпечення модуля інтеграції кафедри та його тестування; Висновки; Список
використаних джерел; Додатки.
5. Перелік графічного матеріалу (з точним зазначенням обов’язкових робіт проекту;
Слайди презентації кваліфікаційної роботи
6. Консультанти розділів роботи
Прізвище, ініціали та посади Підпис, дата
Розділ
консультанта Завдання видав Завдання прийняв
1
2
3
7. Дата видачі завдання 14 листопада 2025 р.
КАЛЕНДАРНИЙ ПЛАН
Строк
виконання
№
Назва етапів випускної роботи етапів Примітки
п/п
кваліфікаційної
роботи
1 Підбір матеріалів 14.11.2025 виконано
2 Аналіз шляхів вирішення поставленої задачі 28.11.2025 виконано
3 Розрахунок основних параметрів роботи 19.12.2025 виконано
4 Вибір кінцевого варіанту проектного рішення 30.01.2026 виконано
5 Оформлення первісної редакції роботи 06.03.2026 виконано
Заключна стадія
1 Узгодження прийнятих проектних рішень з 15.04.2026 виконано
керівником
2 Оформлення пояснювальної записки роботи в 19.05.2026 виконано
кінцевій редакції
3 Попередній захист роботи 20.05.2026 виконано
4 Затвердження роботи 25.05.2026 виконано
5 Рецензування роботи 26.05.2026 виконано
6 Захист роботи
Студент _____________________ Петров А.О.
(підпис) (прізвище та ініціали)
Керівник роботи _____________________ Заспа Г.О.
(підпис) (прізвище та ініціали)
АНОТАЦІЯ
Кваліфікаційна робота бакалавра Петрова А.О. на тему «Інформаційна
система університету. Модуль інтеграції кафедри з іншими підрозділами» за
спеціальністю 121 «Інженерія програмного забезпечення». ЧДТУ, Черкаси, 2026.
Робота містить 103 сторінки, 31 рисунків, 4 таблиці 41 джерело, 4 додатки.
Роботу присвячено автоматизації адміністративної діяльності кафедри в
межах інформаційно-аналітичної системи підтримки освітньої діяльності ЧДТУ.
Актуальність обумовлена потребою в усуненні розривів інформаційних потоків
між кафедрами, деканатами та навчально-методичним відділом і мінімізації ручної
обробки даних.
Об'єкт: процес розробки програмного забезпечення інформаційних систем в
галузі освіти.
Предмет: програмний модуль інтеграції кафедри з іншими підрозділами в
рамках інформаційно-аналітичної системи підтримки освітньої діяльності
університету.
Реалізовано три модулі: формування пропозицій вибіркових дисциплін з
генерацією документів .docx, призначення кураторів групам та керування темами
кваліфікаційних робіт студентів. Застосовано мікросервісну архітектуру з
шаблоном API Gateway: Java/Spring Boot (основний бекенд), NestJS (проміжний
шар), Angular (клієнт) та PostgreSQL. Систему протестовано на модульному,
інтеграційному, системному й приймальному рівнях.
Результати інтегровано в робочу версію ІАС ЧДТУ для подальшого розвитку
підсистеми викладача.
Ключові слова: інформаційно-аналітична система, мікросервісна
архітектура, API GATEWAY, JAVA, SPRING BOOT, NESTJS, ANGULAR,
POSTGRESQL, вибіркові дисципліни, DEANOFFICE, JWT, REST API.
ANNOTATION
The bachelor's qualification work by Petrov A.O. on the topic "University
Information System. Module for Integration of the Department with Other University
Units" in the specialty 121 "Software Engineering". CSTU, Cherkasy, 2026.
The work contains 103 pages, 31 figures, 4 tables 41 references, 4 appendices.
The work is dedicated to the automation of the administrative activity of a
department within the information-analytical system for supporting the educational
activity of CSTU. The relevance is determined by the need to eliminate gaps in
information flows between departments, dean's offices, and the educational-methodical
department, and to minimize manual data processing.
Object : the process of developing software for information systems in the field of
education.
Subject : a software module for integrating the department with other university
units within the information-analytical system for supporting the university's educational
activity.
Three modules have been implemented: formation of elective course proposals
with generation of .docx documents, assignment of curators to academic groups, and
management of students' qualification thesis topics. A microservice architecture with the
API Gateway pattern was applied: Java/Spring Boot (core backend), NestJS (middleware
layer), Angular (client), and PostgreSQL. The system was tested at the unit, integration,
system, and acceptance levels.
The results have been integrated into the working version of the CSTU
information-analytical system for further development of the teacher subsystem.
Keywords: information-analytical system, microservice architecture, API
GATEWAY, JAVA, SPRING BOOT, NESTJS, ANGULAR, POSTGRESQL, selective
courses, DEANOFFICE, JWT, REST API.
ЗМІСТ
ПЕРЕЛІК УМОВНИХ ПОЗНАЧЕНЬ…………………………………………….. 7
ВСТУП………………………………………………………………………………... .9
РОЗДІЛ 1. ІСНУЮЧІ МЕТОДИ ТА ЗАСОБИ РОЗВ’ЯЗАННЯ
ПОСТАВЛЕНИХ ЗАВДАНЬ……………………………………………………... .12
1.1. Опис існуючої інформаційно-аналітичної системи та виявлення проблем
взаємодії підрозділів .................................................................................................. 12
1.2. Постановка задачі ............................................................................................... 15
1.3. Огляд аналогів ..................................................................................................... 18
1.3.1. ІАС «Університет» (Сумський державний університет). ........................ 18
1.3.2. Система «Електронний кампус» (НТУУ «КПІ»). ..................................... 19
1.3.3. Moodle (Modular Object-Oriented Dynamic Learning Environment). ......... 19
1.4. Опис технологій реалізації ................................................................................ 20
РОЗДІЛ 2. Впровадження результатів досліджень у практику проєктвання
програмного забезпечення інформаційних систем……………………………. 24
2.1. Моделювання предметної області . .................................................................. 24
2.1.1. Предметна область моделювання. Модель предметної області. Словник
предметної області. ................................................................................................ 24
2.1.2. Елементи моделювання предметної області. ............................................ 25
2.1.3. Робоча область моделювання. .................................................................... 27
2.2. Формування та аналіз вимог .............................................................................. 28
2.2.1. Формування вимог до програмного забезпечення. Первинні і детальні
вимоги. Вимоги замовника і розробника. Функціональні та нефункціональні
вимоги ...................................................................................................................... 28
ЧДТУ 26. 2255.016 ПЗ
.
Змн. Арк. № докум. Підпис Дата
Розроб. Петров А.О. Літ. Лист Листів
Перевір Заспа Г.О. Інформаційна система 4
університету. Модуль інтеграції
Н. Конт. Півень О.Б. кафедри з іншими підрозділами ФІТІС, кафедра ПЗАС, ПЗ-2204
Затверд. Голуб С.В.
2.2.2. Формування вимог за допомогою діаграми прецедентів. ........................ 30
2.3. Проектування логічної структури програмного комплексу .......................... 35
2.3.1 Діаграми класів. ............................................................................................. 35
2.3.2. Діаграма пакетів. .......................................................................................... 42
2.4. Архітектурне проектування ............................................................................... 44
2.4.1. Діаграма компонентів. ................................................................................. 44
2.4.2. Розгортання програмної системи на апаратних засобах. Діаграма
розгортання. ............................................................................................................ 45
2.5. Поведінкове моделювання системи .................................................................. 46
2.5.1. Діаграма діяльності. ..................................................................................... 46
2.5.2. Діаграма послідовності. ............................................................................... 48
2.5.3. Діаграма комунікації. ................................................................................... 50
2.5.4. Діаграма скінченного автомата................................................................... 51
РОЗДІЛ 3. РОЗРОБКА ТА ТЕСТУВАННЯ ПРОГРАМНОГО
ЗАБЕЗПЕЧЕННЯ…………………………………………….…………………….. 55
3.1. Розробка програмного комплексу. .................................................................... 55
3.1.1. Обґрунтування вибору засобів реалізації. ................................................. 55
3.1.2. Опис структурної (функціональної) схеми. .............................................. 63
3.1.3. Опис логічної схеми системи. ..................................................................... 66
3.1.4. Розробка бази даних. .................................................................................... 69
3.1.5. Розробка інтерфейсу користувача. ............................................................. 72
3.1.6. Опис розробки програмних компонентів. ................................................. 78
3.2. Тестування системи ............................................................................................ 82
3.2.1. Модульне тестування. .................................................................................. 83
3.2.2. Інтеграційне тестування. ............................................................................. 85
3.2.3. Системне тестування.................................................................................... 87
3.2.4. Приймальне тестування. .............................................................................. 89
3.3. Приклади впровадженого програмного комплексу ........................................ 91
ЧДТУ 26. 2255.016 ПЗ
Змн. Арк. № докум Підпис Дата
ВИСНОВКИ………………………………………………………………………… 97
СПИСОК ВИКОРИСТАНИХ ДЖЕРЕЛ………………………………………...100
ДОДАТОК А……………………………………………………………………….. 104
ДОДАТОК Б……………………………………………………………………….. 106
ДОДАТОК В……………………………………………………………………….. 131
ДОДАТОК Г……………………………………………………………………….. 138
ЧДТУ 26. 2255.016 ПЗ
Змн. Арк. № докум Підпис Дата
ЧДТУ 26. 2255.016 ПЗ
ПЕРЕЛІК УМОВНИХ ПОЗНАЧЕНЬ
API – (Application Programming Interface, ua. «Програмний інтерфейс
застосунку») набір методів та правил, через які різні програмні компоненти
взаємодіють між собою.
API Gateway – Архітектурний шаблон, за яким окремий проміжний сервіс
виступає єдиною точкою входу для клієнтського застосунку та проксіює запити до
внутрішніх мікросервісів після перевірки авторизаційних даних.
Bcrypt – Криптографічний алгоритм хешування паролів з механізмом
соління, призначений для безпечного зберігання паролів у базі даних.
CRUD – (Create, Read, Update, Delete) стандартний набір операцій створення,
читання, оновлення та видалення записів у базі даних.
DTO – (Data Transfer Object, ua. «Об'єкт передачі даних») типізована
структура, що використовується для передачі даних між шарами або компонентами
системи.
HTTP – (HyperText Transfer Protocol) мережевий протокол прикладного рівня
для передачі даних у форматі клієнт-сервер.
JPA – (Java Persistence API) стандарт Java для збереження об'єктно-
орієнтованих даних у реляційних базах даних.
JSON – (JavaScript Object Notation) текстовий формат обміну даними,
заснований на синтаксисі JavaScript.
JWT – (JSON Web Token) стандарт відкритого формату для безпечної
передачі інформації між сторонами у вигляді JSON-об'єкта, підписаного секретним
ключем.
LMS – (Learning Management System, ua. «Система управління навчанням»)
програмний застосунок для адміністрування, документації, відстеження та
звітування про навчальні програми.
LTS – (Long-Term Support, ua. «Довгострокова підтримка») версія
програмного забезпечення, для якої виробник гарантує випуск оновлень та
виправлень безпеки протягом тривалого періоду.
7
ЧДТУ 26. 2255.016 ПЗ
MVC – (Model-View-Controller) архітектурний шаблон проектування
програмного забезпечення з розділенням на модель даних, представлення та
контролер.
ORM – (Object-Relational Mapping) технологія програмування, що зв'язує
об'єкти об'єктно-орієнтованої мови програмування із записами реляційної бази
даних.
REST – (Representational State Transfer) архітектурний стиль побудови
розподілених застосунків, заснований на стандартних операціях HTTP-протоколу.
SPA – (Single Page Application, ua. «Односторінковий застосунок») web-
застосунок, який завантажується один раз і динамічно оновлюється без
перезавантаження сторінки.
SQL – (Structured Query Language) декларативна мова запитів до реляційних
баз даних.
UI – (User Interface, ua. «Користувацький інтерфейс») сукупність засобів
взаємодії користувача з програмним забезпеченням.
UML – (Unified Modeling Language) уніфікована мова моделювання, стандарт
для візуального опису структури та поведінки програмних систем.
UX – (User Experience, ua. «Користувацький досвід») сукупність сприйняття
та відчуттів користувача від взаємодії з програмним продуктом.
БД – База даних.
ІАСПОД – Інформаційно-аналітичну систему підтримки освітньої
діяльності Університету.
НМВ – Навчально-методичний відділ.
ПЗ – Програмне забезпечення.
СКБД – Система керування базами даних.
ЧДТУ – Черкаський державний технологічний університет.
8
ЧДТУ 26. 2255.016 ПЗ
ВСТУП
Актуальність теми. Дана кваліфікаційна робота бакалавра належить до
спеціальності «Інженерія програмного забезпечення». Сучасний етап цифровізації
вищої освіти вимагає створення єдиного інформаційного простору університету, де
різні підрозділи можуть ефективно взаємодіяти між собою. Актуальність розробки
модуля інтеграції кафедри з іншими підрозділами зумовлена потребою в усуненні
дублювання даних, паперової тяганини та розсинхронізації інформації між
кафедрами, деканатом та навчально-методичним відділом, необхідності
оперативного внесення достовірної інформації, яку кафедра передає іншим
підрозділам. Розробка інтеграційного модуля дозволить налагодити обмін даними
між підсистемою викладачів та основною базою даних деканату, забезпечуючи
актуальність та цілісність інформації, яка стосується процесу навчання студентів.
Окрім обміну даними, актуальною залишається проблема рутинних
адміністративних процесів кафедри: формування каталогу пропозицій вибіркових
дисциплін, призначення кураторів академічним групам, ведення тем
кваліфікаційних робіт студентів та підготовка офіційних документів для деканату.
Усі ці процеси наразі потребують значних часових витрат та виконуються поза
інформаційною системою – через електронні таблиці, паперові носії або службові
записки. Автоматизація цих процесів у межах єдиного програмного модуля є
основним предметом дослідження кваліфікаційної роботи.
Мета і завдання розробки
Мета розробки: підвищити ефективності управління навчальним процесом
на рівні кафедри, деканату та навчально-методичного відділу шляхом створення
програмного модуля, як частини підсистеми викладача Інформаційно-аналітичної
системи підтримки освітньої діяльності університету, який надає працівникам
кафедри інструменти для введення, передачі іншим підрозділам та подальшої
обробки інформації, яка стосується навчального процесу кафедри.
Завдання розробки
1 Проаналізувати бізнес-процеси кафедри щодо введення, передачі іншим
підрозділам та подальшої обробки інформації, яка стосується навчального процесу
9
ЧДТУ 26. 2255.016 ПЗ
кафедри.
2 Спроєктувати систему з використанням мови UML: побудувати моделі
вимог, логічної структури, архітектури та поведінки системи.
3 Розробити архітектуру взаємодії між мікросервісами системи (Java-
бекенд деканату та NestJS-бекенд викладачів).
4 Розробити програмне забезпечення серверної та клієнтської частини, що
реалізує три взаємопов'язаних функціональних модулі підсистеми викладача:
модуль формування пропозицій вибіркових дисциплін з автоматизованою
генерацією офіційного документа, модуль призначення кураторів академічним
групам та модуль керування темами кваліфікаційних робіт студентів.
5 Реалізувати механізм розмежування прав доступу для безпечної передачі
даних.
6 Провести тестування інтеграційних запитів та оптимізувати роботу з
базою даних.
Об'єкт: процес розробки програмного забезпечення інформаційних систем в
галузі освіти.
Предмет: програмний модуль інтеграції кафедри з іншими підрозділами в
рамках інформаційно-аналітичної системи підтримки освітньої діяльності
університету.
Методи проектування та конструювання
Методи проектування: при розробці використано методи та принципи
інженерії програмного забезпечення, зокрема структурний та об'єктно-
орієнтований підходи до проектування програмних систем. Застосовано принципи
об'єктно-орієнтованого проектування з застосуванням мови моделювання UML для
побудови структурних та поведінкових моделей системи. Архітектуру системи
побудовано на принципах мікросервісної архітектури [9, 10] з шаблоном API
Gateway для забезпечення взаємодії між двома різнорідними бекендами. Серверну
частину деканату реалізовано на основі шаблону «Model-View-Controller» з
використанням фреймворку Spring Boot (Java) [4], тоді як проміжний шар API
Gateway [11] побудовано за модульною архітектурою з розділенням на контролери,
10
ЧДТУ 26. 2255.016 ПЗ
сервіси та віддалені репозиторії на основі фреймворку NestJS (Node.js) [17, 18].
Клієнтська частина побудована на основі компонентно-орієнтованої архітектури з
використанням фреймворку Angular зі standalone-компонентами. Розмежування
прав доступу до функціональних можливостей системи реалізовано на основі
рольової моделі.
Практичне значення отриманих результатів.
Розроблений програмний модуль інтеграції кафедри суттєво зменшує часові
витрати завідувачів кафедр та працівників деканату на рутинні адміністративні
процеси, забезпечує актуальність та цілісність даних кафедри в єдиній
інформаційній системі університету, мінімізує ризик помилок при ручному
перенесенні даних між підрозділами та автоматизує підготовку офіційних
документів кафедри для деканату. Розроблені компоненти інтегровано в робочу
версію інформаційно-аналітичної системи ЧДТУ та можуть бути використані як
основа для подальшого розширення функціональних можливостей підсистеми
викладача. Особистий внесок автора: у процесі виконання роботи автор
самостійно спроектував, реалізував та протестував серверну та клієнтську частину
програмного забезпечення модуля.
11
ЧДТУ 26. 2255.016 ПЗ
РОЗДІЛ 1. ІСНУЮЧІ МЕТОДИ ТА ЗАСОБИ РОЗВ’ЯЗАННЯ
ПОСТАВЛЕНИХ ЗАВДАНЬ
1.1. Опис існуючої інформаційно-аналітичної системи та виявлення
проблем взаємодії підрозділів
Інформаційно-аналітична система підтримки освітньої діяльності
університету (далі – ІАСПОД) є основним інструментом цифровізації
управлінських процесів університету[41]. Її впровадження розпочалося у 2018 році
з метою автоматизації рутинної роботи працівників деканатів, зменшення
паперового документообігу та забезпечення прозорості навчального процесу. За
час експлуатації система зарекомендувала себе як ефективне рішення для
управління контингентом студентів та навчальними планами.
На сьогоднішній день архітектура та функціонал системи дозволяють
вирішувати широкий спектр завдань, які умовно можна поділити на кілька
функціональних блоків, що відповідають етапам навчального року.
Функціональний блок планування навчального року дозволяє
методистам та працівникам деканату формувати базу даних для початку освітнього
процесу. До основних можливостей цього блоку належать:
− керування довідниками спеціальностей та освітніх програм, що включає
створення нових, редагування існуючих та архівування неактуальних програм
відповідно до вимог Міністерства освіти і науки України;
− адміністрування академічних груп факультету, включаючи створення
нових груп для першого курсу, редагування назв та переведення груп у статус
неактивних після випуску;
− робота з каталогом навчальних дисциплін, що викладаються в межах
факультету, з можливістю закріплення конкретних предметів за групами на певний
семестр.
Функціональний блок супроводу навчального процесу є найбільш
використовуваним протягом семестру і включає інструменти для оперативної
роботи зі студентами. Цей модуль дозволяє виконувати такі операції:
12
ЧДТУ 26. 2255.016 ПЗ
− ведення особових карток студентів, що включає перегляд та редагування
персональної інформації, історії навчання, контактних даних;
− формування наказів по контингенту, таких як зарахування, відрахування,
надання академічних відпусток, переведення на наступний курс тощо;
− робота з успішністю студентів, що передбачає внесення та редагування
оцінок за результатами сесій, перегляд академічних заборгованостей;
− розрахунок та призначення стипендій на основі рейтингових списків, які
формуються автоматично на базі внесених оцінок;
− генерація аналітичних звітів щодо успішності студентів у розрізі
спеціальностей, курсів або окремих груп.
Функціональний блок документального забезпечення автоматизує процес
створення офіційних документів, що регламентують завершення навчання або
поточний контроль. Серед можливостей цього блоку варто виділити:
− формування заліково-екзаменаційних відомостей для груп на основі
навчального плану;
− генерація додатків до дипломів європейського зразка, що вимагає високої
точності даних, перевірки коректності перекладу назв дисциплін та відповідності
оцінок;
− створення виписок в особові справи, індивідуальних навчальних планів
студентів та журналів успішності;
− інтеграція з Єдиною державною електронною базою з питань освіти
(ЄДЕБО) для верифікації даних вступників та студентів, що дозволяє уникнути
помилок при ручному введенні інформації.
Попри широкий функціонал, аналіз поточної архітектури та бізнес-процесів
університету виявив суттєвий недолік: система побудована за вертикальним
принципом «Деканат – Студент», і в ній фактично відсутня автоматизована ланка
«Кафедра». На даний момент кафедри, які є основними постачальниками даних про
навчальне навантаження, кадрові ресурси та зміст навчання, залишаються поза
цифровим контуром основної бази даних.
Поточний стан системи призводить до чотирьох груп критичних проблем, які
13
ЧДТУ 26. 2255.016 ПЗ
потребують вирішення в межах даної кваліфікаційної роботи:
1 Проблема формування каталогу вибіркових дисциплін. Наразі процес
подання пропозицій вибіркових дисциплін від кафедри на наступний навчальний
рік не автоматизовано. Процедура відбувається наступним чином: завідувач
кафедри або відповідальна особа формує списки дисциплін у текстових редакторах
або таблицях Excel, після чого ці файли передаються у навчальний відділ або
деканат електронною поштою чи на паперових носіях. Оператори деканату
змушені вручну вносити ці дані в систему. Такий підхід має суттєві недоліки:
− високий ризик механічних помилок при ручному перенесенні даних
(помилки в назвах, кількості кредитів, семестрах);
− відсутність стандартизації описів дисциплін;
− значні часові затрати як з боку кафедри, так і з боку деканату;
− неможливість оперативного редагування пропозицій у разі зміни
навчальних планів.
Крім того, існуюча архітектура не передбачає механізму «чернеток»
(proposals). Дані, внесені в систему, одразу потрапляють до основного каталогу, що
унеможливлює попереднє узгодження дисциплін на рівні кафедри до їх фінального
затвердження деканатом. Ще однією суттєвою проблемою є необхідність ручного
формування офіційної звітності (зокрема, Додатку до розпорядження про каталог
дисциплін вільного вибору), що вимагає від завідувачів кафедр додаткових витрат
часу на бюрократичні процедури.
2 Проблема управління кураторами академічних груп. Призначення
кураторів академічних груп є безпосередньою прерогативою та обов’язком
завідувача кафедри. Однак, в існуючій реалізації ІАСПОД, деканат не бачить цих
призначень в реальному часі, а завідувач кафедри не має технічної можливості
внести ці дані в систему самостійно. Інформація про закріплення кураторів
передається у вигляді службових записок або усних розпоряджень. Це призводить
до таких наслідків:
− відсутність актуальної інформації про кураторів у базі даних, що
унеможливлює відображення цих даних у мобільному додатку студента;
14
ЧДТУ 26. 2255.016 ПЗ
− ускладнення комунікації між адміністрацією та студентами через
кураторів;
− неможливість автоматизованого формування звітів щодо виховної роботи
та навантаження викладачів.
3 Проблема ведення тем кваліфікаційних робіт студентів. Облік тем
дипломних та магістерських робіт є важливим адміністративним процесом, що
супроводжує підготовку студентів старших курсів до випуску. У поточній
реалізації системи поля для зберігання назви теми (українською та англійською) та
посилання на наукового керівника на рівні структури бази даних існують, проте
відсутній зручний інтерфейс для їх масового заповнення завідувачем кафедри. На
практиці це призводить до наступних наслідків:
− теми кваліфікаційних робіт ведуться кафедрами в окремих електронних
таблицях або паперових журналах;
− інформація про теми не є доступною в єдиній системі університету для
подальшої автоматизованої генерації наказів та протоколів засідань кафедри;
− відсутня системна перевірка того, що науковий керівник теми є
викладачем тієї ж кафедри, до якої належить студент.
Таким чином, виникає нагальна потреба у створенні спеціалізованого модуля
інтеграції кафедри. Цей модуль повинен не лише об’єднати існуючі розрізнені
підсистеми технічно, але й надати завідувачам кафедр зручний інструментарій для
прямого впливу на дані в системі, забезпечуючи цілісність, актуальність та безпеку
інформації.
1.2. Постановка задачі
Метою кваліфікаційної роботи є підвищення ефективності управління
навчальним процесом на рівні кафедри шляхом розробки модуля інтеграції, який
забезпечить автоматизований обмін даними між підсистемою викладачів та
центральною базою даних університету. Основна ідея полягає у створенні єдиного
цифрового середовища, де завідувач кафедри має інструменти для безпосереднього
впливу на дані, що стосуються його підрозділу, без необхідності залучення
15
ЧДТУ 26. 2255.016 ПЗ
посередників у вигляді працівників деканату.
Для досягнення поставленої мети необхідно виконати декомпозицію задачі
на ряд послідовних етапів, що охоплюють аналіз, проєктування, розробку та
тестування:
1 Провести детальний аналіз предметної області та існуючих архітектурних
рішень:
− дослідити структуру бази даних існуючої ІАСПОД (Java Backend) для
виявлення таблиць, що відповідають за зв’язки «Викладач – Кафедра» та «Група –
Куратор»;
− проаналізувати API підсистеми викладачів (NestJS Backend) на предмет
наявності необхідних ендпоінтів для отримання даних про користувачів;
− визначити технічні обмеження інтеграції двох різнорідних бекендів
(CORS політики, передача токенів авторизації, узгодження форматів даних JSON).
2 Розробити та імплементувати механізм розширеної авторизації:
− спроєктувати нову рольову модель доступу, додавши специфічні ролі
ROLE_NAVCH_METHOD (для методистів навчального відділу) та
ROLE_TEACHER_BACKEND (для сервісного облікового запису);
− реалізувати захист ендпоінтів на рівні Spring Security, що дозволить
виконувати адміністративні дії лише верифікованим користувачам;
− забезпечити наскрізну передачу ідентифікаторів користувача (User ID)
між сервісами для коректного логування дій.
3 Реалізувати програмний модуль управління вибірковими дисциплінами:
− розробити структуру DTO (Data Transfer Objects) для передачі списків
дисциплін, що включає валідацію назв, кількості кредитів та семестрів контролю;
− створити REST-контролери на стороні Java-бекенду для прийому даних,
їх перевірки на дублікати та збереження в базу даних;
− реалізувати логіку на стороні NestJS-бекенду для формування запитів від
імені завідувача кафедри;
− розробити інтерфейс користувача для формування каталогу дисциплін з
можливістю імпорту даних або ручного введення;
16
ЧДТУ 26. 2255.016 ПЗ
− розробити механізм ізольованого збереження чернеток (пропозицій)
вибіркових дисциплін для попереднього узгодження, без впливу на основний
навчальний план;
− реалізувати функціонал автоматизованої генерації офіційного документа
(каталогу вибіркових дисциплін кафедри) у форматі .docx на основі внесених
пропозицій з подальшим безпечним завантаженням через клієнтський інтерфейс.
4 Реалізувати програмний модуль призначення кураторів:
− розробити алгоритм фільтрації академічних груп за приналежністю до
факультету авторизованого користувача;
− створити механізм отримання списку активних викладачів кафедри для
відображення у випадаючих списках;
− реалізувати PATCH-ендпоінт для пакетного оновлення поля
curator_id у таблиці груп, що дозволить змінювати кураторів одразу для
кількох груп одним запитом;
− забезпечити валідацію вхідних даних, щоб унеможливити призначення
куратором особи, яка не є співробітником університету або вже звільнена.
5 Реалізувати програмний модуль керування темами кваліфікаційних робіт:
− спроектувати спосіб зберігання тем та керівників у структурі бази даних
з мінімальним втручанням у існуючу схему (додавання посилання на викладача-
керівника до запису про навчання студента);
− розробити SQL-міграцію Flyway для додавання нової колонки
thesis_supervisor_id з відповідним зовнішнім ключем;
− створити REST-ендпоінти на Java-бекенді для отримання тем студентів
обраної групи та пакетного оновлення тем;
− розробити клієнтський інтерфейс з двоетапною навігацією: вибір
академічної групи кафедри, потім масове редагування тем студентів цієї групи з
призначенням наукових керівників.
6 Спроектувати та реалізувати клієнтську частину (Frontend):
− розробити архітектуру Angular-компонентів для нових сторінок
«Призначення кураторів» та «Вибіркові дисципліни»;
17
ЧДТУ 26. 2255.016 ПЗ
− впровадити сервіси для HTTP-взаємодії з обома бекендами;
− створити адаптивний інтерфейс з використанням бібліотеки Angular
Material (таблиці з пагінацією, модальні вікна підтвердження, спливаючі
повідомлення про помилки);
− реалізувати клієнтську валідацію форм (Reactive Forms) для миттєвого
зворотного зв’язку з користувачем.
7 Забезпечити надійність та відмовостійкість системи:
− реалізувати глобальний обробник помилок (Global Exception Handler) для
коректного відображення повідомлень про помилки доступу або валідації;
− провести інтеграційне тестування сценаріїв взаємодії між Java та NestJS
сервісами.
− реалізувати глобальний обробник помилок (на базі ControllerAdvice у
Spring Boot) для централізованого перехоплення виключень та коректного
відображення повідомлень про помилки доступу або валідації без дублювання коду
в контролерах;
1.3. Огляд аналогів
Аналіз існуючих рішень на ринку освітніх інформаційних систем дозволяє
виявити загальні тенденції розвитку та визначити недоліки, які має врахувати
розроблювана підсистема [40]. Для порівняння було обрано декілька систем, що
широко використовуються у вищих навчальних закладах України.
1.3.1. ІАС «Університет» (Сумський державний університет)
Дана система є одним з еталонів комплексної автоматизації ВНЗ в Україні.
Вона побудована за модульним принципом і охоплює практично всі сфери
діяльності університету. У контексті задач, поставлених у даній роботі, варто
детальніше розглянути підсистеми, що стосуються навчального процесу:
– Підсистема «Навчання»: забезпечує формування навчальних планів та
розрахунок навантаження. Важливою особливістю є те, що кафедри мають
безпосередній доступ до цього модуля для внесення своїх пропозицій. Це
18
ЧДТУ 26. 2255.016 ПЗ
реалізовано через єдину монолітну базу даних, що спрощує інтеграцію, але робить
систему менш гнучкою до змін;
– Підсистема «Персонал»: веде облік кадрів, що дозволяє автоматично
підтягувати дані про викладачів при призначенні їх на дисципліни або кураторство.
Переваги: Високий рівень інтеграції даних, відсутність дублювання
інформації.
Недоліки: Система є пропрієтарною, складною у впровадженні та має
застарілий інтерфейс у деяких модулях. Монолітна архітектура ускладнює
додавання нових сучасних сервісів (наприклад, мобільних додатків) без суттєвих
доробок ядра.
1.3.2. Система «Електронний кампус» (НТУУ «КПІ»)
Ця система є прикладом сучасного підходу до побудови освітнього
середовища. Вона орієнтована на користувача і надає особисті кабінети для
студентів, викладачів та адміністраторів. Особливістю архітектури є використання
мікросервісів [9, 10], що дозволяє різним командам розробляти окремі модулі
незалежно один від одного.
– Модуль «Кафедра»: дозволяє завідувачу керувати профілями викладачів
та переглядати статистику успішності. Однак, інтеграція з центральною базою
даних деканату часто реалізується через складні механізми синхронізації, що може
призводити до затримок актуалізації даних.
– Модуль «Вибір дисциплін»: реалізований як окремий сервіс, де студенти
голосують за предмети. Результати голосування передаються в деканат для
формування груп.
Переваги: Сучасний стек технологій, зручний UI/UX, орієнтація на
мобільних користувачів.
Недоліки: Складність підтримки розподіленої системи, можливі проблеми з
консистентністю даних між різними мікросервісами.
1.3.3. Moodle (Modular Object-Oriented Dynamic Learning Environment)
Хоча Moodle позиціонується як система управління навчанням (LMS), багато
19
ЧДТУ 26. 2255.016 ПЗ
університетів намагаються адаптувати її для адміністративних потреб через
механізм плагінів.
– Управління курсами: Moodle ідеально підходить для створення контенту
дисциплін, але не має вбудованих інструментів для формування навчальних планів
з точки зору стандартів Міністерства освіти (кредити, години, семестровий
контроль).
– Роль «Управлінець» (Manager): дозволяє бачити списки користувачів, але
функціонал призначення кураторів або формування наказів у Moodle відсутній за
замовчуванням.
Висновок до огляду аналогів: Аналіз показав, що існуючі комерційні рішення
(як АСУ «ВНЗ») є занадто дорогими та надлишковими для потреб конкретного
факультету або кафедри. Водночас, використання LMS Moodle не покриває
адміністративних задач. Розробка власного модуля інтеграції, який би поєднував
надійність Java-ядра (як у ІАС «Університет») та гнучкість мікросервісів (як у
«Електронний кампус»), є найбільш оптимальним рішенням для ЧДТУ.
1.4. Опис технологій реалізації
Програмний комплекс ІАСПОД, у межах якого розроблюється модуль
інтеграції кафедри, побудовано за принципом трирівневої клієнт-серверної
архітектури з виокремленням проміжного шару API Gateway. Основний бекенд
системи реалізовано на платформі Java 17 зі Spring Boot 2.5.7[4, 13], що забезпечує
бізнес-логіку, доступ до основної бази даних університету та інтеграцію зі
зовнішніми сервісами. Проміжний шар (API Gateway) підсистеми викладача
побудовано на TypeScript з фреймворком NestJS та виконує функції маршрутизації
запитів, перевірки авторизаційних даних та координації звернень до основного
бекенду. Клієнтську частину реалізовано на TypeScript з фреймворком Angular зі
standalone-компонентами та бібліотекою Angular Material для оформлення
інтерфейсу.
Для зберігання даних використовується система управління базами даних
PostgreSQL[27] з двома логічно ізольованими базами: основною базою деканату
20
ЧДТУ 26. 2255.016 ПЗ
deanoffice, що обслуговується Java-бекендом через JPA-провайдер Hibernate [5, 16],
та допоміжною базою deanoffice-teacher, що обслуговується NestJS-сервісом через
ORM Prisma [21]. Обмін даними між компонентами системи відбувається через
REST API [33] за протоколом HTTP у форматі JSON; для авторизації
використовується стандарт JSON Web Token (JWT) [38].
Обраний технологічний стек є успадкованим обмеженням існуючої ІАСПОД,
що накладає принципово важливі умови на розробку: значна частина стеку – мова
програмування, фреймворк серверної частини, СУБД, інструмент збирання – не
може бути змінена в межах виконання кваліфікаційної роботи. Завданням
розробника є інтеграція нових функціональних можливостей у вже наявну
архітектуру з максимальним використанням існуючих компонентів. Детальне
обґрунтування вибору кожного інструменту стеку, аналіз його переваг та
особливостей використання в розроблюваному модулі наведено в підрозділі 3.1.1.
21
ЧДТУ 26. 2255.016 ПЗ
ВИСНОВКИ ДО ПЕРШОГО РОЗДІЛУ
У першому розділі кваліфікаційної роботи проведено комплексний аналіз
предметної області та функціонування існуючої інформаційно-аналітичної системи
університету. Встановлено, що попри високий рівень автоматизації роботи
деканатів, існує критичний розрив інформаційних потоків на рівні взаємодії з
кафедрами. Відсутність інтегрованих інструментів для завідувачів кафедр
призводить до необхідності ручної обробки даних при формуванні каталогу
вибіркових дисциплін та призначенні кураторів, що знижує загальну ефективність
управління навчальним процесом.
У ході постановки задачі було формалізовано вимоги до майбутнього модуля
інтеграції з виокремленням трьох взаємопов'язаних функціональних блоків:
модуля формування пропозицій вибіркових дисциплін, модуля призначення
кураторів академічним групам та модуля керування темами кваліфікаційних робіт
студентів. Визначено, що система повинна забезпечувати двосторонній обмін
даними між основною базою даних університету та підсистемою викладачів, а
також надавати розширені права доступу для адміністративного персоналу кафедр
з дотриманням принципу ізоляції даних за кафедральною ознакою.
Аналіз аналогів вітчизняних та закордонних освітніх систем показав загальну
тенденцію до переходу від монолітних рішень до мікросервісної архітектури, яка
передбачає наявність персональних кабінетів для всіх учасників освітнього
процесу. Виявлено, що існуючі готові рішення не покривають специфічних потреб
університету або є складними для інтеграції в поточну інфраструктуру, що
обґрунтовує доцільність розробки власного програмного забезпечення.
Для реалізації поставлених завдань обґрунтовано вибір стеку технологій, що
базується на використанні мови програмування Java (з фреймворком Spring Boot)
для ядра системи, платформи Node.js (фреймворк NestJS) для сервісів взаємодії з
викладачами, а також фреймворку Angular для побудови клієнтського інтерфейсу.
Такий підхід дозволяє поєднати надійність та безпеку корпоративного рівня з
гнучкістю та високою швидкодією сучасних веб-застосунків.
22
ЧДТУ 26. 2255.016 ПЗ
Окрім аналізу предметної області, у першому розділі визначено
методологічну основу подальшого проєктування системи. Обрано об'єктно-
орієнтований підхід із застосуванням уніфікованої мови моделювання UML, що
дозволяє послідовно описати як статичну структуру системи (діаграми класів,
пакетів, компонентів), так і динаміку її поведінки (діаграми діяльності,
послідовності та станів). Такий підхід забезпечує цілісність проєктних рішень та їх
однозначне трактування на етапі реалізації, а також спрощує подальшу підтримку
та розширення модуля інтеграції в межах інформаційно-аналітичної системи
університету.
Результати, отримані в ході аналізу предметної області та технологічних
засобів, стали теоретичним підґрунтям для переходу до етапу проєктування та
практичної реалізації модуля інтеграції у наступних розділах роботи.
23
ЧДТУ 26. 2255.016 ПЗ
РОЗДІЛ 2. ВПРОВАДЖЕННЯ РЕЗУЛЬТАТІВ ДОСЛІДЖЕНЬ У
ПРАКТИКУ ПРОЄКТВАННЯ ПРОГРАМНОГО ЗАБЕЗПЕЧЕННЯ
ІНФОРМАЦІЙНИХ СИСТЕМ
2.1. Моделювання предметної області
2.1.1. Предметна область моделювання. Модель предметної області. Словник
предметної області
Предметна область моделювання: програмний модуль інтеграції кафедри з
іншими підрозділами університету в межах ІАСПОД. Розроблюваний модуль
охоплює три основні бізнес-процеси: формування каталогу вибіркових дисциплін,
призначення кураторів академічним групам та керування темами кваліфікаційних
робіт студентів.
Архітектурною особливістю системи є наявність двох окремих баз даних:
основна база деканату deanoffice містить структурні дані університету (факультети,
кафедри, групи, викладачі, студенти, дисципліни), а допоміжна база deanoffice-
teacher зберігає облікові записи користувачів підсистеми викладача разом з
призначеними ролями. Зв'язок між базами забезпечується через зовнішній
ідентифікатор у запису користувача.
Модель предметної області включає такі ключові концептуальні об'єкти:
– User (Користувач) – особа з обліковим записом у підсистемі викладача та
однією або декількома ролями;
− Role (Роль) – формалізоване право доступу. У підсистемі викладача
передбачено ролі HEAD_OF_DEPARTMENT та
RESPONSIBLE_FOR_SELECTIVE_COURSES;
− Department (Кафедра) – структурний підрозділ факультету,
відповідальний за подання пропозицій вибіркових дисциплін;
− Teacher (Викладач) – співробітник кафедри, який може бути куратором
групи або керівником кваліфікаційної роботи;
− StudentGroup (Академічна група) – об'єднання студентів зі спеціальністю
та опціональним куратором з числа викладачів відповідної кафедри;
24
ЧДТУ 26. 2255.016 ПЗ
− Student (Студент) – особа, що належить до групи та може мати тему
кваліфікаційної роботи з керівником;
− SelectiveCourseProposal (Пропозиція вибіркової дисципліни) – запис у
каталозі дисциплін вільного вибору, що подається кафедрою на навчальний рік та
проходить етап затвердження;
− SelectiveCoursesYearParameters (Параметри року вибіркових дисциплін) –
налаштування навчально-методичного відділу, що визначають часові межі етапів
вибору та норматив годин і кредитів за освітнім ступенем;
− Degree (Освітній ступінь) – рівень вищої освіти (бакалавр, магістр, доктор
філософії);
− ThesisTheme (Тема кваліфікаційної роботи) – тема дипломної роботи, що
зберігається в межах запису про навчання студента з посиланням на викладача-
керівника.
Моделювання предметної області є необхідним підготовчим етапом перед
безпосередньою розробкою програмного забезпечення, оскільки дозволяє
виокремити сутності реального світу, які мають бути відображені в системі,
визначити їх атрибути та зв'язки між ними.
Словник предметної області
Розглянемо словник предметної області:
− період подачі пропозицій – часовий інтервал, у межах якого кафедра має
право створювати, редагувати або видаляти пропозиції вибіркових дисциплін.
Інтервал обчислюється відносно дати початку першого раунду вибору дисциплін
студентами та становить проміжок від 90 до 30 днів до цієї дати;
− куратор групи – викладач, призначений завідувачем кафедри
відповідальним за виховну роботу зі студентами групи. Куратором може бути
виключно викладач тієї ж кафедри, до якої приписана група;
− завідувач кафедри (HEAD_OF_DEPARTMENT) – користувач з
розширеними правами в межах своєї кафедри.
2.1.2. Елементи моделювання предметної області
25
ЧДТУ 26. 2255.016 ПЗ
Для побудови візуальної моделі предметної області використано уніфіковану
мову моделювання UML 2.0 – загальноприйнятий стандарт об'єктно-орієнтованого
аналізу та проектування інформаційних систем[1]. У межах моделювання
використано такі основні елементи нотації UML: клас (прямокутник з трьома
секціями), асоціація (суцільна лінія з позначенням кратності), агрегація (порожній
ромб, відношення «частина-ціле»), композиція (зафарбований ромб) та
узагальнення (порожній трикутник). Основні графічні символи мови UML
наведено на рисунку 2.1.
Рисунок 2.1 – Основні графічні символи UML
На основі виділених у підрозділі 2.1.1 сутностей побудовано концептуальну
діаграму класів предметної області (рисунок 2.2), яка відображає основні об'єкти
модуля та логічні зв'язки між ними. На діаграмі опущено технічні деталі реалізації
(типи даних, ідентифікатори, службові поля), оскільки її призначення –
забезпечити зведений візуальний словник предметної області. Детальні діаграми
класів з повним переліком атрибутів та зв'язків наведено в підрозділі 2.3.
Рисунок 2.2 – Модель предметної області модуля інтеграції кафедри
26
ЧДТУ 26. 2255.016 ПЗ
Центральною сутністю діаграми є Користувач, який володіє однією або
кількома ролями та зіставляється з конкретним викладачем основної бази даних
через зовнішній ідентифікатор. Кафедра є структурним вузлом моделі, до якого
прив'язано викладачів та який виступає автором пропозицій вибіркових дисциплін.
Викладач може виступати у двох ролях стосовно інших об'єктів: як куратор
академічної групи та як науковий керівник теми кваліфікаційної роботи.
Окрему підмодель утворюють сутності формування каталогу вибіркових
дисциплін: Пропозиція вибіркової дисципліни пов'язана з кафедрою, назвою
дисципліни, освітнім ступенем та параметрами навчального року, а Параметри
року визначають часові межі етапів вибору. Підмодель тем кваліфікаційних робіт
включає сутність Тема кваліфікаційної роботи у зв'язку «один-до-одного» зі
студентом та «багато-до-одного» з викладачем-керівником.
2.1.3. Робоча область моделювання
Робоча область модуля інтеграції кафедри – це сукупність бізнес-сценаріїв,
що виконуються користувачами в межах підсистеми викладача та централізованої
системи деканату. Виокремлено чотири функціональні блоки, що становлять
цілісну робочу область.
1 Блок подання пропозицій вибіркових дисциплін. Найбільш
функціонально насичений блок. Бізнес-процес охоплює визначення параметрів
навчального року навчально-методичним відділом, на основі яких система
автоматично обчислює часовий період подачі пропозицій кафедрами (90–30 днів
до початку першого етапу вибору дисциплін студентами). У межах цього періоду
завідувач кафедри або відповідальна особа формує каталог пропозицій з
підтримкою укомплектованих нормативів годин і кредитів за освітнім ступенем.
Стан вікна подачі визначається на стороні Java-бекенду та обмежує доступні
бізнес-операції з пропозиціями. Після завершення формування пропозиції
проходять етап затвердження працівниками деканату з подальшим перенесенням
до основного каталогу вибіркових дисциплін. Окремо в межах блоку передбачено
формування офіційного документа каталогу у форматі Microsoft Word.
27
ЧДТУ 26. 2255.016 ПЗ
2 Блок призначення кураторів академічним групам. Завідувач кафедри
здійснює призначення викладачів кафедри кураторами академічних груп цієї ж
кафедри. Принциповою бізнес-вимогою є дотримання організаційного принципу:
куратором групи може бути виключно викладач тієї ж кафедри, до якої приписана
група. Реалізовано пакетне збереження множинних призначень в межах однієї
бізнес-операції.
3 Блок керування темами кваліфікаційних робіт. Завідувач кафедри веде
облік тем дипломних робіт студентів кафедри з призначенням наукових керівників
з числа співробітників цієї ж кафедри. Дані теми зберігаються в межах запису про
навчання студента, що забезпечує природний зв'язок «студент – тема – керівник»
та готує основу для подальшої автоматизованої генерації наказів і протоколів
засідань кафедри.
Загальна логіка взаємодії між блоками побудована на принципі рольової
моделі: кожен користувач відповідно до своїх ролей отримує доступ виключно до
підмножини операцій, що відповідає його обов'язкам у бізнес-процесах кафедри.
Конкретні сценарії використання інтерфейсу та приклади роботи з кожним блоком
наведено в підрозділі 3.3.1.
2.2. Формування та аналіз вимог
2.2.1. Формування вимог до програмного забезпечення. Первинні і детальні
вимоги. Вимоги замовника і розробника. Функціональні та нефункціональні
вимоги
Формування вимог до програмного забезпечення. Етап формування вимог
є фундаментальним у процесі розробки програмного забезпечення, оскільки на
ньому здійснюється перехід від загального розуміння задачі до формалізованих
специфікацій. Замовником розроблюваного модуля виступає Черкаський
державний технологічний університет, а кінцевими користувачами є завідувачі
кафедр, відповідальні за вибіркові дисципліни, працівники навчально-методичного
відділу та працівники деканату.
28
ЧДТУ 26. 2255.016 ПЗ
Вимоги до системи розрізняються за рівнем деталізації на первинні (вимоги
замовника) та детальні (вимоги розробника), а також класифікуються на
функціональні та нефункціональні[1].
Первинні вимоги
Розглянемо первинні вимоги:
– надати завідувачам кафедр інструмент для самостійного формування
каталогу пропозицій вибіркових дисциплін;
– забезпечити можливість призначення кураторів академічним групам
безпосередньо завідувачем кафедри;
– надати засіб для централізованого керування темами кваліфікаційних
робіт;
– забезпечити чітке розмежування доступу за посадовими обов'язками;
– забезпечити автоматизовану генерацію офіційних документів у форматі,
придатному для друку та підписання.
Функціональні вимоги
Функціональні вимоги описують поведінку системи та сервіси, які вона
повинна виконувати:
– F1. Модуль вибіркових дисциплін. Створення, редагування та
видалення пропозицій вибіркових дисциплін користувачами з ролями завідувача
кафедри або відповідального; автоматичне обчислення стану вікна подачі;
автодоповнення назв з можливістю введення нової; копіювання пропозицій з
попередніх років; автоматична підстановка нормативу годин і кредитів за освітнім
ступенем; затвердження пропозицій працівником деканату; генерація офіційного
документа каталогу у форматі .docx.
– F2. Модуль кураторів. Призначення кураторів академічним групам
завідувачем кафедри з пакетним збереженням; фільтрація списків груп та
потенційних кураторів за кафедральною приналежністю користувача.
– F3. Модуль тем робіт. Створення, редагування та видалення тем
кваліфікаційних робіт студентів кафедри з призначенням викладача-керівника з
числа співробітників кафедри.
29
ЧДТУ 26. 2255.016 ПЗ
– F4. Контроль доступу. Розмежування доступу до функціональних
можливостей системи на основі рольової моделі: кожен користувач отримує доступ
виключно до тих сторінок та операцій, що відповідають його ролям.
Нефункціональні вимоги належать до характеристик системи в цілому та
обмежень її роботи:
– N1. Безпека. Усі запити до серверної частини супроводжуються токеном
авторизації, що перевіряється на проміжному рівні NestJS API Gateway та повторно
на рівні Java-бекенду; доступ до ендпоінтів обмежується відповідно до ролей
користувача.
– N2. Цілісність даних. Серверна частина забезпечує валідацію вхідних
даних на рівні DTO та додаткові бізнес-перевірки; за порушення цілісності
операція скасовується з поверненням структурованого повідомлення про помилку.
– N3. Продуктивність. Час відповіді типового запиту до API має
залишатися прийнятним для інтерактивного використання; пакетне оновлення
кураторів виконується одним запитом для зменшення мережевого трафіку.
– N4. Масштабованість. Архітектура побудована за принципом
розділення відповідальності між Angular-фронтендом, NestJS API Gateway та Java-
бекендом, що дозволяє масштабувати компоненти незалежно.
– N5. Зручність використання. Інтерфейс оформлено в єдиному стилі
підсистеми викладача; для незворотних операцій передбачено підтвердження дії;
для форм забезпечено клієнтську валідацію з миттєвим зворотним зв'язком.
– N6. Підтримуваність. Серверний код побудовано з дотриманням
пошарової архітектури: Java-бекенд використовує шаблон MVC, NestJS-сервіс –
модульну архітектуру з аналогічним розділенням на контролери, сервіси та
репозиторії.
2.2.2. Формування вимог за допомогою діаграми прецедентів
Для візуалізації функціональних вимог до системи з боку її користувачів
побудовано три діаграми прецедентів – по одній на кожен функціональний блок
розроблюваного модуля.
30
ЧДТУ 26. 2255.016 ПЗ
Актори системи. Перед побудовою діаграм наведено перелік акторів, що
беруть участь у бізнес-процесах розроблюваного модуля:
− завідувач кафедри (відповідальний викладач) – основний користувач
підсистеми викладача, що об'єднує дві формальні ролі: завідувача кафедри
(HEAD_OF_DEPARTMENT) та відповідального за вибіркові дисципліни
(RESPONSIBLE_FOR_SELECTIVE_COURSES). На рівні бази даних підсистеми
викладача ці ролі представлені окремо, проте з точки зору доступу до
функціональності модуля вибіркових дисциплін вони є рівноправними: завідувач
кафедри має можливість делегувати відповідальній особі частину своїх обов'язків,
не надаючи їй ширших адміністративних повноважень. На діаграмах прецедентів
обидві ролі представлено одним актором для зменшення кількості дублюючих
стрілок;
− працівник навчально-методичного відділу (НМВ) (роль
ROLE_NAVCH_METHOD в основній базі деканату) – користувач, що задає
параметри навчального року, визначає дати етапів вибору вибіркових дисциплін
студентами та нормативи навантаження за освітніми ступенями, а також
затверджує подані кафедрами пропозиції;
− працівник деканату (роль ROLE_DEANOFFICER) – користувач, який
переглядає затверджені пропозиції вибіркових дисциплін та переносить їх до
основного каталогу вибіркових дисциплін, що є джерелом даних для подальшого
вибору цих дисциплін студентами.
На рівні бази даних деканату ролі працівника НМВ та працівника деканату
представлені окремими ролями. Розподіл функціональних обов'язків між
конкретними співробітниками університету є організаційним рішенням і може
відрізнятися: на практиці один і той самий працівник може виконувати обидві ролі
одночасно. У межах роботи актори моделюються окремо, оскільки вони мають
відмінні набори функціональних можливостей у системі.
Прецедент «Авторизація в системі» включено до кожної з чотирьох діаграм
як обов'язкову передумову для виконання будь-яких інших операцій. Це відповідає
31
ЧДТУ 26. 2255.016 ПЗ
базовому архітектурному правилу системи: жодна функціональність модулю
недоступна анонімному користувачеві.
Перший функціональний блок модуля інтеграції є найбільш насиченим за
кількістю варіантів використання та охоплює повний життєвий цикл пропозиції
вибіркової дисципліни – від встановлення параметрів навчального року
працівником НМВ до перенесення затвердженої пропозиції до основного каталогу
працівником деканату. Діаграму прецедентів цього блоку наведено на рисунку 2.3.
Рисунок 2.3 – Діаграма прецедентів модуля подання пропозицій вибіркових
дисциплін
Як видно з діаграми, основним актором модуля є завідувач кафедри
(відповідальний викладач), який виконує операції зі створення, редагування та
видалення пропозицій вибіркових дисциплін, а також ініціює формування
офіційного документа каталогу у форматі .docx.
32
ЧДТУ 26. 2255.016 ПЗ
Працівник НМВ виступає в ролі регулятора процесу: саме він створює
параметри навчального року, що визначають часовий період подачі пропозицій, та
виконує затвердження поданих кафедрами пропозицій. Працівник деканату
виконує завершальну функцію – переносить затверджені пропозиції до основного
каталогу вибіркових дисциплін, який є джерелом даних для подальшого вибору цих
дисциплін студентами.
Прецедент «Перевірити стан вікна подачі» включений (через відношення
<<include>>) до прецедентів створення та редагування пропозицій, що формалізує
наскрізну бізнес-перевірку: будь-яка операція зі зміни каталогу пропозицій
можлива лише за умови, що поточна дата перебуває в межах відкритого вікна
подачі для відповідного навчального року. Перегляд раніше поданих пропозицій
залишається доступним у будь-якому стані вікна, тому цю перевірку до нього не
включено.
Функціональність другого блоку обмежена двома акторами та компактним
набором варіантів використання, об'єднаних спільною предметною областю –
призначенням викладачів кураторами академічних груп. Діаграму прецедентів
цього модуля наведено на рисунку 2.4.
Рисунок 2.4 – Діаграма прецедентів модуля призначення кураторів академічним
групам
Основним актором модуля є завідувач кафедри, який призначає кураторів для
груп своєї кафедри. Прецедент «Переглянути групи кафедри» включений до
прецеденту призначення куратора, оскільки перегляд списку груп є необхідною
33
ЧДТУ 26. 2255.016 ПЗ
передумовою для виконання цієї операції. Працівник деканату має змогу
переглянути закріплених кураторів усіх груп факультету в інформаційному
режимі, що дозволяє йому контролювати повноту інформації про кураторство в
межах факультету.
Принципово важливою бізнес-вимогою, що формалізована через цю
діаграму, є обмеження за кафедральною ознакою: завідувач кафедри має доступ
виключно до груп своєї кафедри, а у випадаючому списку потенційних кураторів
відображаються виключно викладачі тієї ж кафедри. Реалізація цього обмеження
забезпечується на стороні клієнтської частини та API Gateway за допомогою
попередньої фільтрації списків груп і викладачів за ідентифікатором кафедри
авторизованого користувача.
Третій функціональний блок присвячено введенню та управлінню темами
кваліфікаційних робіт студентів кафедри з призначенням наукових керівників.
Діаграму прецедентів цього модуля наведено на рисунку 2.5.
Рисунок 2.5 – Діаграма прецедентів модуля керування темами кваліфікаційних
робіт
Основним актором модуля є завідувач кафедри, який вводить теми
кваліфікаційних робіт студентів кафедри та призначає для кожної з них наукового
керівника з числа викладачів тієї ж кафедри. Передбачено можливість редагування
34
ЧДТУ 26. 2255.016 ПЗ
раніше внесених тем та формування офіційного документа списку тем для подачі в
деканат. Працівник деканату виступає у ролі спостерігача – має змогу переглянути
поточні та минулі теми робіт студентів факультету в інформаційному режимі для
подальшого контролю та використання у звітних документах.
Як було зазначено в підрозділі 2.1, дані теми кваліфікаційної роботи
зберігаються в межах запису про навчання студента, що забезпечує природний
зв'язок теми зі студентом, з його освітнім ступенем та з академічною групою. Така
структура даних дозволяє в подальшому реалізувати функціональність
автоматичної генерації офіційних документів, що супроводжують процес
затвердження тем (наказів, протоколів засідань кафедри).
Поведінкові аспекти ключових прецедентів та логіка переходів між їхніми
станами розглянуті у підрозділі 2.5.
2.3. Проектування логічної структури програмного комплексу
2.3.1. Діаграми класів
Логічну структуру програмного комплексу подано через діаграми класів за
трьома технологічними шарами розроблюваного модуля:
– граничні класи (<<boundary>>) – компоненти, що розташовані на межі
системи та забезпечують взаємодію із зовнішнім світом. У межах роботи це
Angular-компоненти на стороні клієнта та контролери (Controller) на сторонах обох
бекендів;
– управляючі класи (<<control>>) – компоненти, що інкапсулюють бізнес-
логіку та координують роботу між граничними класами та класами-сутностями. У
межах роботи це Angular-сервіси на клієнті та сервіси (Service) на сторонах обох
бекендів;
– класи-сутності (<<entity>>) – компоненти, що моделюють предметні
об'єкти та забезпечують їх збереження. У межах роботи це JPA-сутності на стороні
Java-бекенду, типізовані моделі (DTO/інтерфейси) на стороні NestJS та Angular, а
також репозиторії як шар доступу до даних.
35
ЧДТУ 26. 2255.016 ПЗ
Для зменшення кількості допоміжних деталей на діаграмах опущено
стандартні службові методи (геттери, сетери, конструктори), а також технічні
елементи інфраструктури фреймворків, що не несуть інформаційного
навантаження стосовно бізнес-логіки модуля.
Загальну діаграму класів модуля, що відображає основні класи всіх трьох
шарів та зв'язки між ними без деталізації атрибутів, наведено на рисунку 2.6. Для
зменшення кількості допоміжних деталей на діаграмах опущено стандартні
службові методи (геттери, сетери, конструктори), а також технічні елементи
інфраструктури фреймворків, що не несуть інформаційного навантаження
стосовно бізнес-логіки модуля.
Рисунок 2.6 – Загальна діаграма класів модуля інтеграції кафедри
Загальна діаграма демонструє наскрізний шлях обробки запиту: від
компонентів клієнтської частини Angular через контролери та сервіси API Gateway
NestJS до контролерів, сервісів і репозиторіїв основного бекенду Java Spring Boot
та бази даних PostgreSQL. Детальні діаграми класів кожного шару з повним
переліком атрибутів та методів наведено в наступних підпідрозділах.
36
ЧДТУ 26. 2255.016 ПЗ
Діаграми класів серверної частини Java Spring Boot
Бекенд деканату побудовано за класичним шаблоном MVC [8] з
виокремленням трьох пошарових компонентів: контролерів, сервісів та
репозиторіїв. Контролери відповідають за обробку HTTP-запитів, серіалізацію та
десеріалізацію даних у форматі JSON, а також за перевірку прав доступу через
анотацію @Secured [14]. Сервіси інкапсулюють бізнес-логіку та координують
взаємодію з декількома репозиторіями за потреби. Репозиторії, побудовані на
основі Spring Data JPA [15], забезпечують доступ до бази даних через автоматично
генеровані запити та власні JPQL-запити для складних випадків. Для передачі
даних між клієнтом та сервером застосовано шаблон Data Transfer Object (DTO) [8]
з валідацією на основі Jakarta Bean Validation. Діаграму класів серверної частини
модуля вибіркових дисциплін наведено на рисунку 2.7.
Рисунок 2.7 – Діаграма класів модуля вибіркових дисциплін на стороні Java Spring
Boot
37
ЧДТУ 26. 2255.016 ПЗ
Контролер SelectiveCourseProposalController приймає запити клієнта та
делегує обробку відповідним сервісам. Метод getProposalsByStudyYear повертає
поточні пропозиції кафедри для зазначеного навчального року; метод saveProposals
приймає список пропозицій для збереження та повертає збережені сутності у
вигляді DTO для читання; метод deleteProposal видаляє пропозицію за
ідентифікатором; метод exportProposalsToDocx ініціює формування офіційного
документа каталогу. Кафедра користувача визначається опосередковано через
ідентифікатор викладача – це дозволяє уникнути зайвої передачі ідентифікатора
кафедри з клієнта та водночас забезпечити коректну ізоляцію даних за
кафедральною ознакою.
Принциповою особливістю архітектури є розмежування DTO для читання
(SelectiveCourseProposalDTO) та DTO для запису
(SelectiveCourseProposalWriteDTO): запитовий DTO містить ідентифікатори
пов'язаних сутностей у вигляді обгорток ExistingIdDTO з відповідними анотаціями
@NotNull, тоді як читальний DTO передає повну вкладену інформацію
(NamedDTO, TeacherDTO, DepartmentDTO). Такий підхід дозволяє чітко
розмежувати контракти на читання та запис, спростити валідацію вхідних даних та
зменшити обсяг переданих по мережі даних під час збереження.
Сервіс SelectiveCourseProposalDocumentService виокремлено в самостійний
клас, оскільки його відповідальність – генерація офіційних документів у форматі
Office Open XML – суттєво відрізняється від CRUD-операцій основного сервісу.
Така організація дотримується принципу єдиної відповідальності (Single
Responsibility Principle) [35, 36].
Діаграми класів сервісу NestJS
API Gateway підсистеми викладача не є прозорим проксі: кожен модуль
містить власну бізнес-логіку, що включає маппінг між контрактами Java-бекенду
та контрактами клієнтської частини, фільтрацію за кафедральною приналежністю
авторизованого користувача, перетворення сирих даних з використанням
бібліотеки class-transformer (декоратори @Exclude та @Expose), а також
координацію декількох запитів до Java-бекенду в межах однієї операції.
38
ЧДТУ 26. 2255.016 ПЗ
Кожен функціональний модуль NestJS дотримується єдиної структури
«контролер – сервіс – віддалений репозиторій», що уніфікує організацію коду в
межах усього проекту та спрощує його розуміння і подальшу підтримку. Діаграму
класів модуля вибіркових дисциплін на стороні NestJS наведено на рисунку 2.8.
Рисунок 2.8 – Діаграма класів модуля вибіркових дисциплін на стороні NestJS
Контролер SelectiveCoursesController приймає HTTP-запити від клієнта та
делегує їх обробку сервісу. На рівні контролера виконується витягнення інформації
про авторизованого користувача з JWT-токена через декоратор @User(), що
дозволяє визначити кафедру та факультет, до яких належить запит. Сервіс
SelectiveCoursesService виконує бізнес-логіку проміжного шару: координує
виклики до віддаленого репозиторію, перетворює відповіді Java-бекенду на
типізовані DTO за допомогою бібліотеки class-transformer та забезпечує однакову
обробку помилок для всіх endpoints модуля.
Окремим методом сервісу є getSubmissionStatus, який повертає клієнту
структурований об'єкт SubmissionStatusDto з двома полями – message (текстове
повідомлення про поточний стан вікна подачі) та canSubmit (логічний прапорець,
39
ЧДТУ 26. 2255.016 ПЗ
що дозволяє чи забороняє редагування). Це формалізує контракт між клієнтом і
сервером щодо станів вікна подачі та дозволяє клієнтській частині приймати
рішення про блокування елементів керування на основі простої логіки без знання
деталей обчислення.
Діаграми класів клієнтської частини Angular
Клієнтську частину побудовано як односторінковий застосунок (Single Page
Application) на основі сучасного підходу Angular зі standalone-компонентами[23],
що скасовує необхідність явного оголошення модулів та спрощує управління
залежностями між компонентами. Структура коду організована за принципом
feature-modules: код кожного функціонального блоку зосереджено в окремій теці
features/, що містить підтеки pages/ (для компонентів-сторінок), services/ (для
класів-сервісів роботи з HTTP API) та models/ (для типізованих моделей даних).
Спільні елементи для всього застосунку винесено в окрему теку core/, що
містить інфраструктурні компоненти: налаштування авторизації (auth.ts,
auth.interceptor.ts), сторожі маршрутів (role.guard.ts), компоненти спільного
інтерфейсу (layout/header, layout/main-layout, layout/sidebar) та довідниковий сервіс
dictionaries.ts. Тека shared/ містить моделі, що повторно використовуються між
кількома функціональними модулями (наприклад, teacher.ts). Діаграму класів
інфраструктурних компонентів клієнтської частини наведено на рисунку 2.9.
Рисунок 2.9 – Діаграма класів інфраструктурних компонентів Angular
40
ЧДТУ 26. 2255.016 ПЗ
Кореневий компонент App ініціалізує застосунок та підключає лейаут
MainLayout, який, у свою чергу, відповідає за відображення спільних для всіх
сторінок елементів – шапки (Header) та бічної панелі навігації (Sidebar).
Конфігурація застосунку та маршрутизація винесені в окремі файли app.config.ts та
app.routes.ts відповідно до сучасних практик Angular зі standalone-компонентами.
AuthService – центральний сервіс авторизації, що зберігає інформацію про
поточного користувача в локальному стані та надає її іншим компонентам та
сервісам. AuthInterceptor – HTTP-перехоплювач, що автоматично додає JWT-токен
до заголовка Authorization кожного вихідного запиту до бекенду. RoleGuard –
сторож маршрутів, що блокує доступ до сторінок користувачам без відповідної
ролі.
DictionariesService забезпечує отримання довідникових даних, що
використовуються у всіх функціональних модулях системи: переліки освітніх
ступенів, форм контролю, кафедр, назв дисциплін та викладачів. Виокремлення
цього сервісу в інфраструктурний шар дозволяє кешувати довідникові дані в межах
однієї сесії та уникати дублювання запитів до сервера. Діаграму класів модуля
вибіркових дисциплін на стороні клієнтської частини наведено на рисунку 2.10.
Рисунок 2.10 – Діаграма класів модуля вибіркових дисциплін на стороні Angular
Компонент CreateCourse (features/selective-courses/pages/create-course/) є
основною сторінкою формування каталогу пропозицій вибіркових дисциплін. Він
підтримує локальний стан таблиці пропозицій разом зі структурою changedRows,
41
ЧДТУ 26. 2255.016 ПЗ
що зберігає індекси модифікованих рядків. Така організація реалізує оптимізацію
передачі даних: під час збереження на сервер надсилаються виключно ті рядки, які
реально були змінені користувачем.
Допоміжний компонент CourseFormDialog (features/selective-
courses/pages/course-form-dialog/) реалізує модальне діалогове вікно для додавання
нової пропозиції з повним набором полів та валідацією через Reactive Forms.
Винесення форми в окремий діалоговий компонент дозволяє повторно
використовувати її для редагування існуючих записів.
Сервіс SelectiveCoursesService (features/selective-courses/services/selective-
courses.ts) інкапсулює всю комунікацію з NestJS API Gateway за маршрутами
/api/selective-courses/* та виконує перетворення відповідей сервера на типізовані
екземпляри моделі SelectiveCourseModel.
2.3.2. Діаграма пакетів
Логічну організацію вихідного коду модуля на високому рівні відображає
діаграма пакетів (рисунок 2.11).
Рисунок 2.11 – Діаграма пакетів модуля інтеграції кафедри
42
ЧДТУ 26. 2255.016 ПЗ
Як видно з діаграми, програмний комплекс побудовано за принципом
тришарової архітектури з чітким розділенням клієнта, проміжного шару (API
Gateway) та основного бекенду, плюс окремий шар постійного зберігання даних.
Обмін інформацією між шарами організовано однонаправленим способом: клієнт
звертається тільки до API Gateway, який, у свою чергу, є єдиним споживачем Java-
бекенду з боку зовнішніх запитів.
На рівні клієнтського застосунку код організовано за принципом feature-
modules: три основні функціональні модулі (selective-courses, group-curators, thesis-
themes) розташовані в теці features/, а спільні інфраструктурні компоненти – у теках
core/ (авторизація, гарди, лейаут, довідники) та shared/ (моделі повторного
використання). Така організація забезпечує високу когезію коду в межах кожного
функціонального блоку та слабку зв'язність між блоками.
На рівні API Gateway кожному функціональному модулю Angular відповідає
окремий модуль NestJS, що дотримується принципу симетрії проекцій бізнес-
функціональності на технічні шари. Окрему групу складають службові модулі:
AuthModule та UsersModule працюють виключно з локальною базою підсистеми
викладача через Prisma ORM, тоді як DeanOfficeModule та HttpRequestModule
забезпечують уніфіковану взаємодію всіх функціональних модулів з основним
Java-бекендом. Спільний модуль DeanOfficeModule виокремлено для розв'язання
типової проблеми мікросервісних архітектур – повторного використання
компонентів доступу до зовнішнього сервісу: всі віддалені репозиторії
(Remote*Repository) зосереджені в одному модулі, що уніфікує їх ініціалізацію та
конфігурацію.
На рівні основного Java-бекенду пакетна структура побудована за класичним
багатошаровим принципом: пакети api.* містять контролери для відповідних
предметних областей, пакет service – реалізації бізнес-логіки, пакет repository –
інтерфейси Spring Data JPA, пакет entity – JPA-сутності, а пакет security –
компоненти контролю доступу. Така організація відповідає шаблону «технічне
розділення пакетів» і дозволяє швидко знаходити код потрібного шару.
43
ЧДТУ 26. 2255.016 ПЗ
Окрему увагу варто звернути на наявність двох баз даних, що відображає
реальний стан системи: основна база deanoffice зберігає всю структурну та
операційну інформацію університету та обслуговується Java-бекендом через шар
Spring Data JPA, а допоміжна база deanoffice-teacher зберігає виключно дані
облікових записів та ролей користувачів підсистеми викладача й обслуговується
NestJS-сервісом через ORM Prisma. Такий поділ зумовлений історичним розвитком
системи та забезпечує ізоляцію даних авторизації підсистеми викладача від
основних даних деканату.
2.4. Архітектурне проектування
2.4.1. Діаграма компонентів
Фізичну архітектуру розроблюваного модуля з виокремленням
розгортуваних компонентів та інтерфейсів між ними подано на рисунку 2.12.
Рисунок 2.12 – Діаграма компонентів модуля інтеграції кафедри
44
ЧДТУ 26. 2255.016 ПЗ
Архітектура модуля побудована за принципом трирівневої клієнт-серверної
моделі з виокремленням проміжного шару API Gateway. Клієнтський Angular-
застосунок взаємодіє виключно з NestJS-сервісом через REST API, а NestJS, у свою
чергу, є єдиним споживачем основного Java-бекенду серед зовнішніх запитів.
Принципово важливою архітектурною характеристикою є однонаправленість
залежностей: жоден внутрішній сервіс не звертається до клієнтського застосунку,
а Java-бекенд не має жодних залежностей від NestJS-сервісу. Це дозволяє
масштабувати та підтримувати кожен з компонентів незалежно. Технологічна
реалізація кожного компонента детально розглянута в підрозділах 1.4 та 3.1.1.
2.4.2. Розгортання програмної системи на апаратних засобах. Діаграма
розгортання
На діаграмі розгортання (рисунок 2.13) представлено триланкову топологію
розподіленої системи. Клієнтський застосунок (Angular), проміжний шлюз (NestJS)
та основний бекенд (Java Spring Boot) розгорнуті у локальному середовищі на
ізольованих мережевих портах. Взаємодія між компонентами здійснюється за
протоколом HTTP/REST, де NestJS виконує роль єдиної точки входу для
фронтенду, проксіюючи системні запити до відповідних сервісів ядра
Рисунок 2.13 – Діаграма розгортання модуля інтеграції кафедри в середовищі
розробки
У продуктивному середовищі функцію проксіювання виконує веб-сервер
(Nginx або Apache), який одночасно обслуговує статичні файли Angular-застосунку
та перенаправляє API-запити до NestJS-сервісу. Усі три процеси на продуктивному
45
ЧДТУ 26. 2255.016 ПЗ
середовищі запускаються як системні служби з автоматичним відновленням після
збою; конкретні інструкції з запуску компонентів у середовищі розробки наведено
в підрозділі 3.3.2.
2.5. Поведінкове моделювання системи
Поведінкове моделювання системи дозволяє відобразити динамічні аспекти
її функціонування – порядок виконання операцій, обмін повідомленнями між
компонентами, переходи між станами об'єктів. У межах цього підрозділу
побудовано чотири типи поведінкових діаграм мови UML: діаграму діяльності, що
описує послідовність дій у межах найскладнішого бізнес-процесу системи;
діаграму послідовності, що деталізує часову послідовність обміну повідомленнями
між компонентами; діаграму комунікації, що відображає взаємодію об'єктів з
акцентом на структурній організації; та діаграму скінченного автомата, що
формалізує життєвий цикл ключового об'єкта системи.
Як основний об'єкт поведінкового моделювання обрано процес подання
пропозицій вибіркових дисциплін, оскільки саме цей процес є найбільш складним
з функціональної точки зору та об'єднує всі ключові архітектурні особливості
системи: розмежування доступу за ролями, перевірку часових обмежень, взаємодію
між трьома мікросервісами, валідацію бізнес-правил і збереження даних у двох
окремих базах.
2.5.1. Діаграма діяльності
Бізнес-процес подання пропозицій вибіркових дисциплін з усіма гілками
рішень та паралельними діями подано на діаграмі діяльності (рисунок 2.14).
Важливим аспектом моделювання є відображення паралельних потоків
виконання, що виникають під час асинхронних запитів до API, та точок
синхронізації перед оновленням клієнтського інтерфейсу. Такий підхід до
формалізації логіки гарантує повноту охоплення всіх можливих станів застосунку
ще на етапі його проектування, мінімізуючи ризик архітектурних помилок.
46
ЧДТУ 26. 2255.016 ПЗ
Рисунок 2.14 – Діаграма діяльності процесу подання пропозицій вибіркових
дисциплін
47
ЧДТУ 26. 2255.016 ПЗ
Як видно з діаграми, процес подання пропозицій включає в себе кілька
принципово важливих точок прийняття рішень. Першою з них є перевірка
наявності параметрів навчального року, що задаються методистом навчально-
методичного відділу: за відсутності цих параметрів подання пропозицій неможливе
в принципі. Другою точкою рішення є перевірка поточної дати на належність до
вікна подачі: залежно від результату цієї перевірки система переходить в один з
чотирьох можливих режимів роботи зі сторінкою – повного редагування, перегляду
в очікуванні відкриття вікна, перегляду після закриття вікна, повного блокування.
Третьою точкою прийняття рішень є двоетапна валідація: спочатку
клієнтська (з негайним зворотним зв'язком користувачеві), потім серверна (з
гарантією цілісності даних незалежно від клієнта). Така архітектура валідації
відповідає принципу «довіряй, але перевіряй»: клієнтська валідація потрібна для
зручності користувача, серверна – для безпеки системи.
Особливістю реалізованого процесу є оптимізація обсягу переданих даних:
на сервер надсилаються виключно ті рядки, які реально були модифіковані
користувачем у поточному сеансі. Це досягається завдяки веденню на стороні
клієнта списку «брудних» (модифікованих) рядків та формуванню запиту на основі
цього списку. Така оптимізація особливо важлива для пакетного збереження
великого каталогу дисциплін, де користувач може редагувати лише декілька рядків
з кількох десятків.
2.5.2. Діаграма послідовності
Хронологічну взаємодію компонентів системи під час типового запиту
збереження пропозицій вибіркових дисциплін подано на діаграмі послідовності
(рисунок 2.15). Ця діаграма деталізує процес обміну повідомленнями між об'єктами
у часі, демонструючи життєвий цикл запиту від ініціалізації на стороні
клієнтського застосунку до фіксації транзакції у базі даних. Відображення
синхронних та асинхронних викликів дозволяє виявити потенційні вузькі місця у
продуктивності, зокрема під час міжсервісної взаємодії через HTTP-протокол. Крім
того, на схемі чітко виділено зони відповідальності кожного архітектурного шару:
48
ЧДТУ 26. 2255.016 ПЗ
первинна валідація на рівні шлюзу, обробка бізнес-правил на основному бекенді та
безпосереднє збереження стану в репозиторії бази даних.
Рисунок 2.15 – Діаграма послідовності збереження пропозицій вибіркових
дисциплін
Діаграма наочно відображає особливості мікросервісної архітектури
системи. Кожен клієнтський запит проходить через два рівні валідації (клієнтський
та серверний) та два рівні авторизації (JWT користувача на рівні NestJS і сервісний
JWT на рівні Java-бекенду). Така багаторівнева перевірка є вартістю розподіленої
архітектури, але вона ж забезпечує і її головну перевагу – можливість незалежної
модифікації кожного шару без впливу на інші.
Цикл loop для кожного DTO у межах роботи Java-сервісу виокремлено
свідомо, оскільки в реалізації методу saveProposals для кожної пропозиції
виконується низка однотипних операцій маппінгу та встановлення зв'язків з
довідниковими сутностями. Завершальний виклик saveAll у репозиторії дозволяє
49
ЧДТУ 26. 2255.016 ПЗ
виконати збереження всіх пропозицій однією транзакцією, що мінімізує кількість
звернень до бази даних та забезпечує атомарність операції.
2.5.3. Діаграма комунікації
Діаграма комунікації (Communication Diagram) є альтернативною формою
представлення взаємодії об'єктів, що акцентує увагу на структурних зв'язках між
учасниками, тоді як часова послідовність повідомлень позначається їх нумерацією.
У контексті модуля інтеграції кафедри діаграма комунікації корисна для
відображення архітектури взаємодії під час виконання операції призначення
куратора академічній групі.
На рисунку 2.16 наведено діаграму комунікації для процесу пакетного
оновлення кураторів кількох груп.
Рисунок 2.16 — Діаграма комунікації процесу призначення кураторів
академічним групам
50
ЧДТУ 26. 2255.016 ПЗ
Як видно з діаграми, операція призначення куратора пакетно охоплює
одинадцять програмних об'єктів, розподілених між трьома фізичними процесами
(клієнт, API Gateway, основний бекенд) та однією системою управління базами
даних. Принциповим архітектурним рішенням є пакетна обробка: на стороні
клієнта зміни накопичуються в локальній структурі changedGroups, після чого
передаються одним HTTP-запитом, який, у свою чергу, призводить до пакетного
UPDATE-запиту в межах однієї транзакції бази даних. Така організація суттєво
зменшує мережеві накладні витрати порівняно з варіантом, у якому кожна зміна
куратора передавалася б окремим запитом, та забезпечує атомарність змін.
2.5.4. Діаграма скінченного автомата
Стани вікна подачі пропозицій вибіркових дисциплін та переходи між ними
подано на діаграмі скінченного автомата (рисунок 2.17).
Рисунок 2.17 – Діаграма скінченного автомата вікна подачі пропозицій
51
ЧДТУ 26. 2255.016 ПЗ
На діаграмі представлено чотири стани, в яких може перебувати вікно подачі
пропозицій на конкретний навчальний рік:
– Undefined (період не визначений) – параметри навчального року ще не
задано методистом навчально-методичного відділу; це початковий стан для будь-
якого нового навчального року;
– NotYetOpen (період ще не відкрито) – параметри року задано, проте
поточна дата ще не досягла моменту початку вікна подачі (тобто залишається понад
90 днів до початку першого раунду вибору студентами);
– Open (період відкрито) – поточна дата перебуває в межах вікна подачі;
кафедри мають право створювати, редагувати та видаляти пропозиції;
– Closed (період закрито) – поточна дата перебуває після завершення вікна
подачі; редагування заборонено, але збережені раніше пропозиції залишаються
доступними для перегляду.
Переходи між станами зумовлені двома типами подій: природним перебігом
часу (переходи NotYetOpen → Open та Open → Closed, що відбуваються
автоматично з настанням відповідних календарних дат) та діями методиста
навчально-методичного відділу (створення або видалення параметрів навчального
року). Зворотний перехід Closed → Open діаграмою свідомо не передбачений: якщо
період закрито, повторне його відкриття можливе лише шляхом створення
параметрів для нового навчального року або через коригування параметрів
поточного року методистом НМВ – і в такому разі фактично відбувається
перевизначення параметрів, що в моделі відображається через стан Undefined.
Реалізація опису життєвого циклу вікна подачі на стороні Java-бекенду
інкапсульована в окремому сервісі, який повертає клієнту структурований об'єкт
SelectiveCourseSubmissionStatusDTO з двома полями: текстовим повідомленням
для відображення в інтерфейсі та логічним прапорцем canSubmit, що визначає
допустимість змін у поточному стані. Така організація дозволяє приховати від
клієнтської частини конкретні правила обчислення вікна подачі та зосередити всю
логіку в одному місці, що відповідає принципу «одне джерело істини» (Single
Source of Truth).
52
ЧДТУ 26. 2255.016 ПЗ
ВИСНОВКИ ДО ДРУГОГО РОЗДІЛУ
У другому розділі кваліфікаційної роботи виконано впровадження
результатів теоретичних досліджень першого розділу в практичну площину
проектування програмного забезпечення модуля інтеграції кафедри з іншими
підрозділами університету в межах ІАСПОД.
Здійснено моделювання предметної області, у ході якого виокремлено
основні концептуальні сутності системи – користувача, кафедру, факультет,
академічну групу, викладача, пропозицію вибіркової дисципліни, параметри
навчального року, тему кваліфікаційної роботи – та визначено логічні зв'язки між
ними. На основі результатів моделювання побудовано діаграму класів предметної
області у нотації UML 2.0, а також сформовано словник предметної області, що
включає термінологію бізнес-процесів кафедри та зафіксовує єдине розуміння
ключових понять усіма учасниками розробки.
Виконано формування та аналіз вимог до програмного забезпечення на двох
рівнях деталізації – первинному (вимоги замовника) та детальному (вимоги
розробника). На основі цих вимог сформульовано п'ятнадцять функціональних та
вісім нефункціональних вимог, що в сукупності описують усі функціональні
можливості модуля та обмеження, які накладаються на його роботу. Для
візуалізації функціональних вимог побудовано діаграму прецедентів з
виокремленням трьох акторів – завідувача кафедри (відповідального викладача),
підсистеми викладача, працівника навчально-методичного відділу та працівника
деканату – а також формалізовано наскрізну бізнес-перевірку «стан вікна подачі»
через відношення <<include>> між прецедентами.
Проведено проектування логічної структури програмного комплексу з
побудовою детальних діаграм класів для трьох технологічних шарів системи:
серверної частини на основі Java Spring Boot, проміжного шару API Gateway на
основі NestJS, та клієнтської частини на основі Angular. Для кожного шару
дотримано класичних шаблонів пошарової архітектури: на стороні Java-бекенду –
шаблон MVC з тришаровою структурою «контролер – сервіс – репозиторій», на
стороні NestJS-сервісу – модульна архітектура з аналогічною структурою
53
ЧДТУ 26. 2255.016 ПЗ
«контролер – сервіс – віддалений репозиторій». Окремо побудовано діаграму
пакетів, що відображає логічну організацію вихідного коду на високому рівні.
У межах архітектурного проектування побудовано діаграму компонентів, яка
демонструє розподіл відповідальності між Angular SPA, NestJS API Gateway, Java
Spring Boot та СУБД PostgreSQL, а також ключові службові компоненти на
кожному з рівнів (Angular Material та RxJS на клієнті; на проміжному шарі – Prisma
ORM для роботи з базою підсистеми викладача та Swagger UI для документації
API; Spring Security, Spring Data JPA та docx4j на основному бекенді). Діаграма
розгортання деталізує фізичну організацію системи в локальному середовищі
розробки з зазначенням TCP-портів та механізмів взаємодії між процесами;
додатково розглянуто можливі сценарії промислового розгортання системи.
Поведінкове моделювання системи здійснено через побудову чотирьох типів
діаграм: діаграми діяльності, що описує повний бізнес-процес подання пропозицій
вибіркових дисциплін; діаграми послідовності, що деталізує часову послідовність
обміну повідомленнями між компонентами при збереженні пропозицій; діаграми
комунікації, що відображає взаємодію об'єктів у процесі пакетного призначення
кураторів академічним групам; та діаграми скінченного автомата, що формалізує
життєвий цикл вікна подачі пропозицій з чотирма його станами та переходами між
ними.
Результати, отримані в цьому розділі, формують методичну та архітектурну
основу для практичної реалізації модуля інтеграції кафедри, опис якої наведено в
наступному розділі кваліфікаційної роботи.
54
ЧДТУ 26. 2255.016 ПЗ
РОЗДІЛ 3. РОЗРОБКА ТА ТЕСТУВАННЯ ПРОГРАМНОГО
ЗАБЕЗПЕЧЕННЯ
3.1. Розробка програмного комплексу
Процес розробки програмного забезпечення модуля інтеграції кафедри
охоплює етапи вибору інструментів реалізації, проектування архітектури,
створення бази даних, розробки користувацького інтерфейсу, реалізації серверної
логіки на двох технологічних платформах та забезпечення інтеграції між ними. У
цьому розділі детально розглянуто обґрунтування вибору технологій, побудову
основних компонентів системи, особливості реалізації функціональних блоків
модуля та застосування сучасних практик розробки інформаційних систем
масштабу університету.
3.1.1. Обґрунтування вибору засобів реалізації
Особливість розроблюваного програмного модуля полягає в тому, що він є
складовою частиною вже існуючої ІАСПОД Черкаського державного
технологічного університету. Це накладає принципово важливі обмеження на вибір
технологій: значна частина стеку – мова програмування, фреймворк серверної
частини, система управління базами даних, інструмент збирання – успадковується
від основної системи та не може бути змінена в межах виконання кваліфікаційної
роботи. Завданням розробника є інтеграція нових функціональних можливостей у
вже наявну архітектуру з мінімальним порушенням її цілісності та максимальним
використанням існуючих компонентів.
Водночас підсистема викладача (deanoffice-teacher-backend і deanoffice-
teacher-frontend) була розроблена пізніше за основну систему деканату та
використовує сучасніший технологічний стек. Це створило цікавий технічний
контекст для роботи: розроблюваний модуль одночасно вимагав внесення змін у
класичну Java Spring Boot частину (для розширення основних API) та реалізації
нових компонентів у Node.js-сервісі API Gateway і Angular-клієнті.
Мова програмування серверної частини: Java 17. Основний бекенд
системи deanoffice-backend реалізовано мовою Java версії 17 [6, 7] – поточною
55
ЧДТУ 26. 2255.016 ПЗ
довгостроково підтримуваною (LTS) версією платформи Java. Java 17 надає всі
необхідні можливості для реалізації поставлених задач: лямбда-вирази та
функціональні інтерфейси для роботи з колекціями, Stream API для обробки
списків сутностей, анотації для декларативної конфігурації, нову нотацію var для
виведення типів локальних змінних, оператор switch як вираз, текстові блоки для
багаторядкових рядків, а також зрілу екосистему бібліотек з повною сумісністю з
усіма основними фреймворками.
Фреймворк серверної частини: Spring Boot 2.5.7. Java-бекенд побудовано
на основі Spring Boot [4, 13] – спеціалізованого розширення Spring Framework, яке
суттєво спрощує розробку Spring-застосунків завдяки автоматичній конфігурації та
принципу «convention over configuration». У межах роботи з фреймворком
використовуються такі ключові модулі стартової конфігурації (starters):
− Spring Web MVC – реалізує модель «модель-вид-контролер» та
забезпечує обробку HTTP-запитів через анотовані методи контролерів. Анотації
@RestController, @RequestMapping, @GetMapping, @PostMapping, @PathVariable,
@RequestParam, @RequestBody дозволяють декларативно описувати
маршрутизацію API без потреби в програмній конфігурації;
− Spring Security – забезпечує комплексну систему безпеки з підтримкою
автентифікації, авторизації, захисту від атак типу CSRF та XSS. У межах
розроблюваного модуля найбільш активно використовується механізм авторизації
на основі ролей через анотацію @Secured, яка дозволяє декларативно обмежувати
доступ до окремих методів контролерів;
− Spring Data JPA – забезпечує об'єктно-реляційне відображення (ORM) на
основі специфікації Java Persistence API з провайдером Hibernate. Ключовою
перевагою цього модуля є можливість декларативного оголошення репозиторіїв як
інтерфейсів-розширень JpaRepository: фреймворк автоматично генерує реалізацію
для базових операцій (save, findById, findAll, deleteById), а складніші запити
описуються або через іменування методів за конвенцією Spring Data
(findByStudyYearAndDepartmentId), або через анотацію @Query з JPQL-виразом;
56
ЧДТУ 26. 2255.016 ПЗ
– spring-boot-starter-validation – забезпечує валідацію вхідних даних на
основі специфікації Jakarta Bean Validation. Анотації @NotNull, @Size, @Min,
@NotBlank дозволяють декларативно описувати правила перевірки полів DTO; за
порушення цих правил повертається структуроване повідомлення про помилку зі
статусом HTTP 400;
– spring-boot-starter-actuator – додає до застосунку набір сервісних
ендпоінтів моніторингу: статус застосунку, інформація про середовище виконання,
метрики продуктивності тощо.
– Spring Dependency Injection – реалізує впровадження залежностей через
конструктори або поля з анотаціями @Autowired, що забезпечує слабку зв'язність
між компонентами та полегшує модульне тестування.
Конфігурація застосунку поділена на дві категорії: типові налаштування
(підключення до бази даних, порт сервера, рівні логування) виконуються через
файл application.properties [39], тоді як складні конфігурації Spring-компонентів
виносяться в окремі Java-класи з анотаціями @Configuration та @Bean. Як
вбудований сервер додатків застосунок використовує Jetty замість стандартного
для Spring Boot Tomcat – це історичний вибір основної системи деканату, що
зберігається з міркувань сумісності. Для пулу з'єднань з базою даних
застосовується HikariCP – найшвидший на сьогодні JDBC-пул, що забезпечує
мінімальні накладні витрати на отримання та повернення з'єднань.
Допоміжні бібліотеки Java-бекенду. Окрім стартових модулів Spring Boot,
у проекті активно використовуються такі бібліотеки, що суттєво підвищують
продуктивність розробки та якість коду:
– Lombok – бібліотека, що шляхом анотацій (@Getter, @Setter, @Data,
@RequiredArgsConstructor, @Slf4j) генерує під час компіляції стандартний
шаблонний код – геттери, сетери, конструктори, методи toString та equals. Це
дозволяє суттєво скоротити обсяг візуально надлишкового коду в класах-сутностях
та DTO без втрати функціональності;
– MapStruct – інструмент компіляційного часу для генерації
перетворювачів (мапперів) між класами. На основі інтерфейсу з декларативним
57
ЧДТУ 26. 2255.016 ПЗ
описом перетворень MapStruct генерує реалізацію, яка не використовує рефлексію
та працює зі швидкістю звичайного Java-коду. У межах проекту MapStruct
використовується разом з Lombok-MapStruct binding для коректної взаємодії двох
інструментів обробки анотацій;
– ModelMapper – додатковий інструмент перетворення об'єктів, що
працює переважно через рефлексію та використовується в тих місцях коду, де
MapStruct ще не було впроваджено;
– jjwt 0.9.1 – бібліотека для роботи з JSON Web Tokens на стороні Java:
створення, підпис та верифікація токенів, видані Spring Security-механізмом
авторизації;
– Flyway – інструмент керування версіями схеми бази даних через
міграційні SQL-скрипти. Кожна зміна структури бази (додавання таблиці, колонки,
індексу) описується окремим файлом-міграцією з порядковим номером
(наприклад, V001__create_selective_courses_proposals.sql), що автоматично
виконується під час старту застосунку. Це забезпечує відтворюваність схеми бази
даних на будь-якому середовищі та контроль версій структурних змін у тій самій
системі контролю версій, що й код;
– OpenCSV 5.7.1 – бібліотека для роботи з даними у форматі CSV, що
використовується в інших модулях системи деканату для імпорту та експорту
табличних даних;
– iText 5.0.6 – бібліотека генерації PDF-документів, що використовується
для інших звітних форм системи деканату.
Інструмент збирання Java-проекту: Gradle. Для збирання Java-частини
обрано інструмент Gradle, який порівняно з традиційним Apache Maven надає
гнучкіший синтаксис на основі DSL мови Groovy та значно швидшу
інкрементальну компіляцію. У межах роботи Gradle використовується для
керування залежностями, компіляції коду, запуску застосунку у режимі розробки
(команда gradle bootRun), а також для збирання виконуваного JAR-файлу для
розгортання.
58
ЧДТУ 26. 2255.016 ПЗ
Бібліотека генерації документів: docx4j 3.3.6. Однією з ключових
функціональних вимог розроблюваного модуля є можливість генерації офіційного
документа «Додаток до розпорядження про каталог дисциплін вільного вибору» у
форматі Office Open XML (.docx). Для розв'язання цієї задачі обрано бібліотеку
docx4j – провідну Java-бібліотеку для роботи з документами Microsoft Office.
Бібліотека дозволяє завантажити заздалегідь підготовлений шаблон документа з
оформленим заголовком університету, реквізитами та табличною структурою,
програмно заповнити його даними поточної кафедри та зберегти результат як
готовий до друку файл.
Документація API на стороні Java: Springfox Swagger 2.8.0. Окрім
автогенерованої документації NestJS-сервісу, Java-бекенд також має власну
Swagger-документацію на основі бібліотеки Springfox версії 2.8.0. Це дозволяє
розробникам перевіряти та документувати ендпоінти основного бекенду незалежно
від проміжного шару, що особливо корисно під час налагодження інтеграції між
двома сервісами.
Мова програмування проміжного шару: TypeScript. Сервіс API Gateway
(deanoffice-teacher-backend) реалізовано мовою TypeScript [20] – типобезпечним
розширенням JavaScript, що компілюється у звичайний JavaScript та виконується
середовищем Node.js [19]. Вибір TypeScript замість «чистого» JavaScript
мотивований такими міркуваннями: статична типізація на етапі компіляції
дозволяє виявляти значну частину помилок до запуску застосунку; підтримка
інтерфейсів, типів-об'єднань та узагальнень дає можливість точно описувати
контракти між модулями; інтегрована підтримка декораторів дозволяє писати
декларативний код, типовий для сучасних фреймворків.
Фреймворк проміжного шару: NestJS. Для побудови API Gateway обрано
фреймворк NestJS [17, 18] – прогресивний серверний фреймворк для Node.js,
концептуально подібний до Angular на стороні клієнта. NestJS базується на сильно
типізованому коді TypeScript і повністю підтримує принципи об'єктно-
орієнтованого програмування, функціонального програмування та функціонально-
реактивного програмування.
59
ЧДТУ 26. 2255.016 ПЗ
Для роботи з HTTP-запитами на серверній стороні використовується
вбудований модуль @nestjs/axios, що базується на популярній бібліотеці Axios. Для
перетворення сирих JSON-даних, отриманих від Java-бекенду, на типізовані
екземпляри DTO використовується бібліотека class-transformer з декораторами
@Expose та @Exclude, що дозволяє точно контролювати поверхню даних,
доступну клієнту.
ORM проміжного шару: Prisma. Для роботи з локальною базою даних
підсистеми викладача (deanoffice-teacher) обрано сучасну ORM-бібліотеку Prisma
[21]. На відміну від традиційних ORM на кшталт TypeORM або Sequelize, Prisma
використовує власну декларативну мову опису схеми (Prisma Schema Language) у
файлі schema.prisma, з якого автоматично генерується типобезпечний клієнт. Це
дає декілька суттєвих переваг: повна типова підтримка операцій з базою даних на
рівні TypeScript, автогенерація міграцій з порівняння двох версій схеми,
інтегрований інструмент перегляду даних Prisma Studio.
Авторизація: JWT + bcrypt. Авторизація користувачів підсистеми
викладача реалізована на основі стандарту JSON Web Token (JWT) [38]. Токени
видаються після успішної автентифікації за обліковим записом та містять
закодовану інформацію про користувача й термін дії, підписану секретним ключем.
Перевірка автентичності токена на кожному запиті виконується через стандартну
стратегію passport-jwt. Паролі користувачів зберігаються у базі не у відкритому
вигляді, а у вигляді хеш-значень, обчислених алгоритмом bcrypt з налаштованою
кількістю раундів соління (10 раундів), що забезпечує захист від атак на основі
попередньо обчислених таблиць хешів [12].
Документування API: Swagger / OpenAPI. Для автоматизованої генерації
документації API використовується модуль @nestjs/swagger, що на основі
декораторів та типів TypeScript формує специфікацію API у форматі OpenAPI 3.0
[32] та надає інтерактивний веб-інтерфейс за маршрутом /docs. Цей інструмент
відіграв ключову роль на етапі ручного тестування системи, оскільки дозволяє
виконувати запити до API безпосередньо з браузера без потреби у зовнішніх
60
ЧДТУ 26. 2255.016 ПЗ
засобах на кшталт Postman, а також автоматично документує всі ендпоінти модуля
для майбутніх розробників.
Фреймворк клієнтської частини: Angular. Клієнтський застосунок
підсистеми викладача побудовано на основі фреймворку Angular [22, 23] –
повноцінного фреймворку для розробки односторінкових застосунків (Single Page
Applications), розробленого компанією Google. Перевагами Angular, що зумовили
його вибір, є:
– компонентна архітектура з чітким відокремленням шаблону, стилів та
логіки компонента, що забезпечує модульність та повторне використання коду;
– повна типобезпечність завдяки використанню TypeScript як основної
мови, що гармонує з NestJS на серверній стороні та забезпечує одноманітний підхід
до розробки в усьому проекті;
– двостороннє зв'язування даних та реактивні форми – два потужні
механізми синхронізації стану інтерфейсу з даними застосунку, що особливо
корисні для роботи зі складними табличними формами на кшталт каталогу
пропозицій вибіркових дисциплін;
– standalone-компоненти – сучасний підхід організації Angular-застосунку
без явного оголошення NgModules, де кожен компонент самостійно декларує свої
залежності через властивість imports; цей підхід використовується в розроблюваній
клієнтській частині та забезпечує спрощену структуру коду й кращу tree-shaking-
оптимізацію збірки;
– вбудована маршрутизація через @angular/router з підтримкою сторожів
маршрутів (route guards), що використано для розмежування доступу до сторінок
за ролями користувача;
– багата екосистема готових бібліотек UI-компонентів, найвідомішою з
яких є Angular Material.
Бібліотека UI-компонентів: Angular Material. Для оформлення інтерфейсу
використано бібліотеку Angular Material [24] – офіційну реалізацію дизайн-системи
Material Design від Google для Angular. Бібліотека надає широкий набір готових до
використання компонентів: кнопки, поля введення, таблиці з сортуванням та
61
ЧДТУ 26. 2255.016 ПЗ
пагінацією, модальні діалоги, селектори, автодоповнення, банери, прогрес-
індикатори. Використання готової бібліотеки замість самостійного оформлення
кожного елемента дозволяє суттєво пришвидшити розробку та забезпечити
узгоджений вигляд інтерфейсу.
Реактивне програмування: RxJS. Усі асинхронні операції на стороні
клієнта реалізовано через бібліотеку RxJS [25] – реалізацію патерну Observer [34]
для JavaScript. Замість традиційних промісів Angular використовує концепцію
Observable – потоків даних, що можуть бути перетворені через ланцюжки
операторів (map, filter, tap, switchMap, combineLatest). Це особливо корисно для
роботи з HTTP-запитами через вбудований HttpClient, який повертає Observable, та
для синхронізації стану кількох незалежних потоків даних (наприклад,
одночасного завантаження списку груп і списку викладачів кафедри для сторінки
призначення кураторів).
Інструмент збирання клієнтської частини: Angular CLI. Для збирання та
розгортання клієнтського застосунку використовується Angular CLI – офіційний
інструмент командного рядка Angular. У режимі розробки команда npm run start
запускає dev-сервер з гарячим перезавантаженням модулів (Hot Module
Replacement) та проксіюванням запитів /api на сервер NestJS згідно з файлом
proxy.conf.json. Для збирання продакшн-версії використовується команда npm run
build, що формує статичні бандли з оптимізацією та мінімізацією.
Система управління базами даних: PostgreSQL. Як СУБД у системі
використано PostgreSQL [27, 28] – провідну об'єктно-реляційну систему управління
базами даних з відкритим вихідним кодом. PostgreSQL обрана за такими
критеріями: повна підтримка стандарту SQL з широким набором розширень; високі
показники продуктивності та надійності; зріла підтримка транзакцій з рівнем
ізоляції до Serializable [26, 29]; багатий набір вбудованих типів даних, включно з
numeric для точних числових значень (наприклад, кредитів вибіркових дисциплін)
та timestamp with time zone для часових міток із врахуванням часового поясу.
Обидві бази даних – deanoffice та deanoffice-teacher – розміщені на одному
62
ЧДТУ 26. 2255.016 ПЗ
екземплярі PostgreSQL і взаємодіють з відповідними бекенд-сервісами через
стандартний JDBC-драйвер (для Java) та через ORM Prisma (для NestJS).
Система контролю версій: Git + GitHub. Розробка велася з використанням
системи контролю версій Git та хостингу репозиторіїв GitHub в межах організації
chdtu-fitis. Для організації роботи використано класичний робочий процес GitFlow:
основна гілка main містить стабільну версію коду, окремі функціональні гілки
створюються для кожної задачі (issue) та зливаються в основну через Pull Request
після ревʼю. Усі задачі трекалися через систему GitHub Issues, де кожна задача
отримувала номер, опис, мітки за типом (Feature, Task, enhancement, complement
feature) та призначеного виконавця. Project-board у GitHub з колонками «In
Progress» – «Review» – «Done» забезпечував візуальне відстеження прогресу робіт.
Такий стек технологій забезпечує оптимальний баланс між сумісністю з
існуючою системою деканату (Java/Spring/PostgreSQL), сучасними практиками
веб-розробки (TypeScript/Angular/NestJS) та продуктивністю команди завдяки
використанню зрілих та добре документованих інструментів.
3.1.2. Опис структурної (функціональної) схеми
Структурна схема програмної системи відображає її основні функціональні
блоки та зв'язки між ними. На відміну від детальної діаграми компонентів,
наведеної в підрозділі 2.4, структурна схема надає більш узагальнений погляд на
систему та зосереджується на розподілі відповідальності між підсистемами, а не на
технічних деталях їхньої реалізації.
Структурну схему програмного комплексу модуля інтеграції кафедри
наведено на рисунку 3.1.
Представлена структура базується на принципах слабкої зв'язності та високої
згуртованості компонентів, що є критично важливим для масштабованих систем.
Використання шаблону API Gateway не лише спрощує клієнтську маршрутизацію,
але й створює єдину точку входу для агрегації даних, моніторингу та контролю
безпеки. Розділення основного бекенду на окремі шари доступу до даних, бізнес-
логіки та представлення відповідає класичній багаторівневій архітектурі, що
значно спрощує підтримку та розширення кодової бази у майбутньому. Інтеграція
63
ЧДТУ 26. 2255.016 ПЗ
з існуючою базою даних вимагає ретельного підходу до відображенню сутностей,
що також враховано в архітектурному рішенні.
Рисунок 3.1 – Структурна схема програмного комплексу
Як видно зі схеми, програмний комплекс має чітке функціональне
розшарування. Клієнтська частина на основі Angular складається з трьох
функціональних модулів, що відповідають основним бізнес-блокам
розроблюваного модуля, а також інфраструктурного шару, який забезпечує
загальні для всього застосунку функції – оформлення сторінок (layout),
авторизацію та сторожі маршрутів. API Gateway на основі NestJS виокремлює три
внутрішні відповідальності: маршрутизація вхідних запитів та перевірка
авторизаційних даних, бізнес-логіка проміжного шару (фільтрація даних,
перетворення DTO, координація запитів), а також інтеграційний HTTP-клієнт для
звернень до Java-бекенду.
Основний бекенд на основі Java Spring Boot також має чотири функціональні
блоки: REST API як точка входу для запитів, шар сервісів з бізнес-логікою, шар
доступу до даних на основі JPA-репозиторіїв, а також виокремлений блок генерації
офіційних документів на основі бібліотеки docx4j. Між основним бекендом і базою
даних deanoffice реалізовано класичне з'єднання через JDBC-драйвер з
використанням пулу з'єднань HikariCP та ORM-провайдера Hibernate.
64
ЧДТУ 26. 2255.016 ПЗ
Принциповою архітектурною характеристикою системи є однонаправленість
залежностей: користувач взаємодіє лише з клієнтською частиною, клієнтська
частина – лише з API Gateway, а API Gateway виступає єдиним споживачем
основного Java-бекенду. Такий підхід гарантує можливість незалежного оновлення
кожного зі шарів та полегшує тестування системи.
Більш повне уявлення про систему дає функціональна схема, що відображає
інформаційні потоки між компонентами на типовому прикладі – збереженні пакету
пропозицій вибіркових дисциплін. Функціональну схему наведено на рисунку 3.2.
Рисунок 3.2 – Функціональна схема збереження пропозицій вибіркових дисциплін
65
ЧДТУ 26. 2255.016 ПЗ
На функціональній схемі показано, які саме інформаційні потоки виникають
у системі під час виконання типового бізнес-сценарію – пакетного збереження
пропозицій вибіркових дисциплін. Особливості, які варто відмітити:
– оптимізація обсягу переданих даних – на стороні клієнта виокремлено
блок «Відстеження змінених рядків», що формує до запиту виключно ті записи, які
реально були модифіковані користувачем; інші рядки таблиці, які залишилися без
змін, на сервер не передаються;
– двоетапна авторизація – кожен запит проходить дві окремі перевірки:
на рівні NestJS Gateway перевіряється JWT-токен користувача, а на рівні Java-
бекенду – сервісний JWT-токен від імені облікового запису teacher_backend;
– двоетапна валідація – серверна частина виконує спочатку формальну
перевірку DTO через Bean Validation (анотації @NotNull, @Size тощо), а потім –
додаткові бізнес-перевірки на рівні сервісу;
– транзакційність – пакетне збереження виконується в межах однієї
транзакції бази даних завдяки анотації @Transactional, що гарантує
атомарність змін: або зберігаються всі пропозиції, або жодна.
Така функціональна архітектура забезпечує надійність, продуктивність і
безпеку системи на всіх етапах обробки запиту.
3.1.3. Опис логічної схеми системи
Логічна схема системи описує послідовність дій, які відбуваються у
проектованому об'єкті від початку взаємодії користувача із застосунком до
отримання результату. У межах модуля інтеграції кафедри логічна схема
представлена у вигляді узагальненої блок-схеми алгоритму роботи системи,
наведеної на рисунку 3.3.
Побудована логічна схема слугує не лише документацією для розробників,
але й базою для формування тестових сценаріїв на етапі тестування та забезпечення
якості. Вона формалізує переходи між станами застосунку, ілюструючи, як саме
система реагує на різноманітні тригери – від інтерактивних дій користувача до
відповідей від зовнішніх сервісів. Кожен блок схеми відповідає ізольованому етапу
66
ЧДТУ 26. 2255.016 ПЗ
обробки інформації, що дозволяє легко локалізувати потенційні дефекти та
оптимізувати окремі кроки виконання алгоритму без ризику порушення загального
потоку управління системою.
Рисунок 3.3 – Логічна схема алгоритму роботи системи
67
ЧДТУ 26. 2255.016 ПЗ
Логічна схема відображає узагальнений життєвий цикл взаємодії
користувача з системою. Розглянемо її основні етапи детальніше.
Етап 1. Автентифікація. Усі сторінки модуля, окрім сторінки входу,
захищені сторожем маршруту AuthGuard, що перевіряє наявність дійсного JWT-
токена у локальному сховищі браузера. За відсутності токена або його закінченим
терміном дії користувач автоматично перенаправляється на сторінку входу, де
вводить логін та пароль. Після успішної автентифікації NestJS видає новий JWT-
токен з терміном дії 5 діб (432000 секунд згідно з конфігурацією .env), що
зберігається на клієнті та автоматично додається до всіх наступних запитів через
HTTP-перехоплювач AuthInterceptor.
Етап 2. Завантаження інтерфейсу. Після успішної автентифікації
клієнтський застосунок завантажує головний лейаут з боковим меню. Вміст меню
формується динамічно залежно від ролей користувача: користувач з роллю
HEAD_OF_DEPARTMENT або RESPONSIBLE_FOR_SELECTIVE_COURSES
бачить пункти «Подати вибіркові», «Куратори» та «Теми дипломних робіт».
Етап 3. Перевірка прав доступу до сторінки. Під час навігації між
сторінками виконується перевірка прав через RoleGuard – сторож маршруту, що
читає вимоги до ролей із конфігурації маршруту та порівнює їх з ролями поточного
користувача. Якщо користувач не має необхідної ролі, відбувається
перенаправлення на головну сторінку без виконання запиту до сервера.
Етап 4. Завантаження даних сторінки. Кожна сторінка під час ініціалізації
виконує запит на отримання необхідних даних до NestJS Gateway за маршрутами
вигляду /api/<модуль>/<операція>. Запит автоматично оснащується JWT-токеном
через AuthInterceptor.
Етап 5. Обробка запиту на стороні NestJS Gateway. Gateway виконує дві
перевірки: верифікацію підпису JWT-токена через стратегію passport-jwt та
перевірку відповідності ролі користувача вимогам ендпоінта через декоратор
@Roles. У разі успішної авторизації виконується виклик відповідного сервісу,
який, у свою чергу, делегує запит до RemoteRepository – компонента, що формує
68
ЧДТУ 26. 2255.016 ПЗ
HTTP-запит до Java-бекенду з додаванням сервісного JWT-токена для облікового
запису teacher_backend.
Етап 6. Обробка запиту на стороні Java Spring Boot. Spring Security
перевіряє сервісний JWT-токен та визначає, що запит надходить від облікового
запису з роллю ROLE_TEACHER_BACKEND. Контролер приймає запит, виконує
валідацію вхідних даних через Bean Validation (анотації @Valid, @NotNull, @Size),
потім делегує обробку відповідному сервісу. Сервіс реалізує бізнес-логіку,
координує виклики до репозиторіїв та повертає результат, який автоматично
серіалізується у формат JSON.
Етап 7. Повернення результату клієнту. Відповідь Java-бекенду
повертається до NestJS Gateway, де може бути додатково оброблена (наприклад,
перетворена з використанням бібліотеки class-transformer для приховування
службових полів), після чого передається клієнту. Клієнтський сервіс отримує дані
та оновлює стан компонента, що автоматично призводить до перерисування
інтерфейсу завдяки реактивності Angular.
Така логічна організація забезпечує однорідну обробку всіх запитів у системі
та полегшує розуміння поведінки застосунку для нових розробників, які
приєднуються до проекту.
3.1.4. Розробка бази даних
Розробка бази даних модуля виконувалась з урахуванням архітектурної
особливості системи – наявності двох окремих фізичних баз даних: основної
deanoffice (обслуговується Java-бекендом через JPA з провайдером Hibernate) та
допоміжної deanoffice-teacher (обслуговується NestJS через ORM Prisma). Обидві
бази працюють на одному екземплярі PostgreSQL, є логічно ізольованими та не
мають фізичних зовнішніх ключів одна на одну. Зв'язок реалізується через поле
externalId у таблиці користувачів, що містить значення teacher.id з основної бази.
Для версійного контролю схеми бази deanoffice використовується інструмент
Flyway, що автоматично виконує SQL-міграції під час старту Java-застосунку
(формат V<номер>__<опис>.sql). Для бази deanoffice-teacher аналогічну функцію
69
ЧДТУ 26. 2255.016 ПЗ
виконує Prisma Migrate, що генерує міграції на основі різниці між поточним станом
схеми у файлі schema.prisma та станом бази даних.
Концептуальну модель частини бази даних, релевантної для розроблюваного
модуля, наведено на рисунку 3.4.
Рисунок 3.4 – Концептуальна модель частини бази даних модуля
У межах розроблюваного модуля внесено дві нові міграції у схему бази
deanoffice та використано раніше додану колонку student_group.curator_id.
Міграція V63: створення таблиці selective_courses_proposals. Найскладніша з
виконаних міграцій. Створено таблицю з 15 стовпцями для зберігання пропозицій
вибіркових дисциплін, що подаються кафедрами. Принциповою особливістю
таблиці є складене CHECK-обмеження only_one_course_name_filled, що гарантує
заповненість рівно одного з двох полів – course_name_id (посилання на довідник)
або proposed_course_name (текст нової назви), але не обох одночасно. Це реалізує
бізнес-правило F3 (автодоповнення з можливістю введення нової назви) на рівні
бази даних, незалежно від клієнтської логіки. Також створено шість зовнішніх
ключів для забезпечення цілісності даних та два часткові унікальні індекси
(unique_proposal_by_course_name_id і unique_proposal_by_proposed_name), що
гарантують відсутність дублювання пропозицій у межах однакового навчального
року, семестру та освітнього ступеня. Використання саме часткових індексів
зумовлене коректною обробкою випадку, коли одне з полів NULL: у звичайному
індексі такі значення вважаються різними, тому загальне обмеження працювало б
некоректно.
Міграція V65: додавання колонки thesis_supervisor_id до існуючої таблиці
student_degree з посиланням на викладача-керівника кваліфікаційної роботи.
70
ЧДТУ 26. 2255.016 ПЗ
Колонка є опціональною, що відповідає реальній бізнес-логіці – тема та керівник
призначаються не одразу під час зарахування студента, а на старшому курсі.
Окремої таблиці для тем кваліфікаційних робіт не створювалося, оскільки тема є
природним атрибутом запису про навчання конкретного студента та не існує
незалежно від нього.
Колонка student_group.curator_id для функціональності призначення
кураторів вже існувала на момент початку роботи над модулем. Розроблюваний
модуль додав новий шар функціональності над цією колонкою – інтерфейс
масового призначення кураторів завідувачем кафедри з пакетним API-ендпоінтом
та фільтрацією за кафедрою. Таке рішення є типовим прикладом інтеграційної
розробки – додавання нової бізнес-функціональності над існуючими структурами
даних без створення нових таблиць та дублювання інформації.
Структура бази deanoffice-teacher складається з трьох таблиць: User, Role та
автоматично згенерованої Prisma таблиці-зв'язку _UserRoles (рисунок 3.5). Поле
username має формат <п>.<п>.<прізвище>.<абрев>.<рік> (наприклад,
p.i.baran.ftbrp26); password зберігає bcrypt-хеш з 10 раундами соління; externalId
забезпечує логічний зв'язок з teacher.id основної бази.
Рисунок 3.5 – Структура бази даних deanoffice-teacher
Таблиця User зберігає облікові записи користувачів підсистеми викладача.
Поле username має формат <п>.<п>.<прізвище>.<абревіатура_факультету><рік>
(наприклад, p.i.baran.ftbrp26. Поле password зберігає bcrypt-хеш пароля з 10
71
ЧДТУ 26. 2255.016 ПЗ
раундами соління; Поле externalId містить ідентифікатор відповідного запису
викладача в основній базі deanoffice та забезпечує логічний зв'язок між двома
базами без фізичного зовнішнього ключа.
Таблиця Role є довідником ролей, що фіксує перелік можливих рівнів
доступу: TEACHER, HEAD_OF_DEPARTMENT,
RESPONSIBLE_FOR_SELECTIVE_COURSES. Зв'язок між користувачами та
ролями є відношенням «багато-до-багатьох» і реалізується автоматично
згенерованою Prisma таблицею-зв'язком _UserRoles з двома стовпцями-зовнішніми
ключами.
3.1.5. Розробка інтерфейсу користувача
Інтерфейс користувача є ключовим елементом, що забезпечує ефективну
взаємодію користувача з розроблюваним програмним модулем. Основною метою
під час проектування та розробки інтерфейсу було забезпечити інтуїтивну
зрозумілість, естетичну привабливість, узгодженість з рештою підсистеми
викладача та дотримання загальноприйнятих принципів проектування інтерфейсів.
Інтерфейс розроблено з урахуванням десяти евристичних принципів
зручності використання Якоба Нільсена [37], серед яких найбільш суттєвими для
розроблюваного модуля є:
– видимість стану системи – користувач завжди отримує інформацію про
поточний стан застосунку через індикатори завантаження (Material Progress
Spinner), банери стану вікна подачі пропозицій, повідомлення про успіх або
помилку через MatSnackBar;
– відповідність системи реальному світу – використано термінологію
предметної області («Подати вибіркові», «Куратори», «Теми дипломних робіт»)
замість технічних термінів;
– запобігання помилкам – для незворотних операцій (видалення
пропозиції або користувача) застосовано модальні діалоги підтвердження
(ConfirmDialog); поля з примусовим значенням (наприклад, «Контроль: Залік»)
заблоковані для редагування; кнопка «Зберегти» неактивна, коли немає змін для
збереження;
72
ЧДТУ 26. 2255.016 ПЗ
– впізнавання замість пригадування – використано випадаючі списки з
повними назвами (викладачі, ступені, цикли) замість текстового введення;
автодоповнення назв дисциплін з довідника;
– гнучкість та ефективність використання – підтримка пакетного
збереження множинних змін одним натисканням кнопки;
– естетичний і мінімалістичний дизайн – використано бібліотеку Angular
Material для єдиного візуального стилю; усі сторінки мають однакову структуру
(бічне меню зліва, заголовок сторінки, основний контент).
Сторінкою входу в підсистему викладача є форма авторизації, наведена на
рисунку 3.6.
Рисунок 3.6 – Сторінка входу в підсистему викладача
Сторінка містить мінімальну форму з двома обов'язковими полями – «Логін»
та «Пароль» – та кнопкою «Увійти». Кнопка залишається неактивною до моменту
заповнення обох полів, що реалізовано через Reactive Forms Angular. Після
успішної автентифікації NestJS-сервіс повертає JWT-токен, який зберігається в
localStorage браузера через сервіс Auth, після чого користувач автоматично
перенаправляється на головну сторінку.
73
ЧДТУ 26. 2255.016 ПЗ
Головна сторінка модуля вибіркових дисциплін, наведена на рисунку 3.7,
відображає каталог раніше поданих пропозицій кафедри, згрупованих за
навчальними роками.
Рисунок 3.7 – Сторінка «Подати вибіркові»: каталог за попередні роки
Інтерфейс реалізовано у вигляді набору розкривних секцій (Material
Expansion Panel) – по одній на кожен навчальний рік. Кожна секція показує
загальну кількість затверджених дисциплін за рік (наприклад, «Затверджених: 3»)
та при розкритті відображає список пропозицій з основною інформацією: назва
дисципліни, освітній ступінь, викладач, семестр. Кнопка «+» біля кожного запису
дозволяє швидко скопіювати дисципліну з попереднього року як основу для нової
пропозиції на поточний рік. Це суттєво пришвидшує формування каталогу,
оскільки в більшості випадків кафедра пропонує ті самі дисципліни щороку з
мінімальними змінами.
Натискання на кнопку копіювання відкриває діалогове вікно з формою
редагування, наведене на рисунку 3.8.
74
ЧДТУ 26. 2255.016 ПЗ
Рисунок 3.8 – Діалог копіювання дисципліни
Форма містить такі поля:
– навчальний рік – заблоковане поле з автоматично підставленим
поточним навчальним роком (наприклад, «2025–2026»);
– назва дисципліни – поле з функцією автодоповнення на основі довідника
course_name; користувач також може ввести нову назву, якщо такої ще немає в
довіднику;
– семестр – випадаючий список з номерами семестрів;
– години та кредити – числові поля, що підставляються автоматично
залежно від обраного освітнього ступеня згідно з нормативом ЧДТУ;
– контроль – заблоковане поле зі значенням «Залік» згідно з регламентом
університету для вибіркових дисциплін;
– викладач – опціональне поле з вибором викладача з числа співробітників
кафедри (може бути не заповненим, якщо викладач ще не визначений);
– кафедра – заблоковане поле з автоматично підставленою кафедрою
користувача (наприклад, «робототехніки та спеціалізованих ком...»);
– ступінь – випадаючий список (Бакалавр, Магістр, PhD);
– цикл – випадаючий список з двох варіантів: «Загальна (General)» або
«Професійна (Professional)»;
75
ЧДТУ 26. 2255.016 ПЗ
– галузь знань – випадаючий список з кодом та назвою галузі (наприклад,
«12 - Інформаційні те...»);
– опис – багаторядкове текстове поле для опису змісту дисципліни.
Кнопка «Додати копію» залишається неактивною до моменту заповнення
всіх обов'язкових полів, що відповідає принципу запобігання помилкам Нільсена.
Після додавання нових дисциплін до каталогу вони відображаються в нижній
частині сторінки в окремій секції «Нові дисципліни», наведеній на рисунку 3.9.
Рисунок 3.9 – Секція «Нові дисципліни» перед збереженням
Кожна нова дисципліна відображається як окрема карточка з лівим синім
бордюром, назвою дисципліни, інформацією про викладача та семестр, а також
кнопками редагування (синя іконка олівця) та видалення (червона іконка кошика).
У нижній частині сторінки розташовані дві основні дії: «Завантажити каталог»
(експорт у формат .docx) та «Зберегти нові дисципліни» (надсилання змінених
записів на сервер пакетним запитом).
Сторінка призначення кураторів академічним групам, наведена на рисунку
3.10, реалізована як інтерактивна таблиця з двома стовпцями.
76
ЧДТУ 26. 2255.016 ПЗ
Рисунок 3.10 – Сторінка «Призначення кураторів»
У першому стовпці відображаються академічні групи кафедри (наприклад,
АКІТ-2109, АКІТ-2209, АКІТ-2309, АКІТС-2109, АКІТС-2209, MAKIT-2309).
Назви груп відображені як гіперпосилання для майбутньої навігації до детальної
інформації про групу. У другому стовпці кожен запис містить випадаючий список
(Material Select) з переліком викладачів кафедри для вибору куратора. Якщо в групі
ще не призначено куратора (як це бачимо для групи АКІТС-2209), випадаючий
список відображає placeholder «Куратор» сірим кольором.
Принципово важливою архітектурною деталлю є те, що в випадаючому
списку відображаються виключно викладачі тієї кафедри, до якої належить
авторизований користувач. Це реалізовано на рівні NestJS Gateway через метод
getDepartmentGroups(externalId), що читає teacherId авторизованого користувача з
JWT-токена та запитує у Java-бекенду тільки відповідні групи.
Кнопка «Зберегти зміни» залишається неактивною доки користувач не внесе
хоча б одну зміну; після натискання кнопки всі змінені призначення
відправляються одним пакетним запитом PATCH /api/student-groups. Цей механізм
реалізовано через структуру Map<number, number> (асоціативний словник «id
групи → id куратора»), що накопичує всі зміни локально та формує масив об'єктів
для серверного запиту лише в момент збереження.
Сторінка керування темами кваліфікаційних робіт, наведена на рисунку 3.11,
77
ЧДТУ 26. 2255.016 ПЗ
реалізована як двоетапний інтерфейс.
Рисунок 3.11 – Сторінка «Теми кваліфікаційних робіт»
Спершу користувач обирає академічну групу зі випадаючого списку
«Оберіть групу», після чого автоматично завантажується та відображається
таблиця студентів цієї групи. Таблиця має такі стовпці:
– № – порядковий номер студента в групі;
– ПІБ – прізвище, ім'я та по батькові студента;
– Тема (UA) – багаторядкове поле для назви теми українською;
– Тема (EN) – багаторядкове поле для назви теми англійською;
– Керівник – випадаючий список для вибору викладача-керівника з числа
співробітників кафедри.
Для зручності використання кожне поле має placeholder («Тема
українською», «Тема англійською», «Керівник»), що зникає при введенні значення.
Кнопка «Зберегти всі» виконує пакетне оновлення тем для всіх студентів обраної
групи одним запитом до сервера.
3.1.6. Опис розробки програмних компонентів
У цьому підрозділі наведено опис основних програмних компонентів модуля
інтеграції кафедри з ілюстрацією ключових фрагментів коду. Подача матеріалу
організована за чотирма функціональними блоками, що відповідають реалізованим
модулям системи. У межах кожного блоку розглянуто компоненти трьох
78
ЧДТУ 26. 2255.016 ПЗ
технологічних шарів – клієнтського застосунку Angular, проміжного шару NestJS
та основного бекенду Java Spring Boot, причому увагу зосереджено на
нетривіальних аспектах реалізації, що демонструють архітектурні рішення
розробника.
Загальна архітектурна закономірність полягає в тому, що для кожного
функціонального блоку в Angular реалізовано компонент-сторінку та сервіс роботи
з HTTP API; у NestJS – модуль з контролером, сервісом та віддаленим репозиторієм
для звернень до Java-бекенду; на Java-бекенді – контролер, сервіс та JPA-
репозиторій. Така симетрія архітектурних шарів забезпечує одноманітність кодової
бази та полегшує її подальшу підтримку.
Модуль вибіркових дисциплін
Розмежування доступу до сторінок та операцій модуля реалізовано наскрізно
через стандартний механізм Angular Route Guards на клієнтській частині та
системних guards (JwtAuthGuard, RolesGuard) на стороні NestJS-сервісу – кожен
користувач отримує доступ виключно до операцій, що відповідають його ролям.
Розглянемо найбільш характерні компоненти реалізації функціональних блоків
модуля.
Клієнтський компонент CreateCourse (features/selective-courses/pages/create-
course/) реалізує сторінку формування каталогу пропозицій. Найбільш цікавою з
точки зору алгоритмічної реалізації є оптимізація передачі даних на сервер:
надсилаються виключно ті записи, які реально були змінені користувачем. Для
цього в компоненті паралельно зберігаються два списки – proposals (поточні дані
форми) та originalProposals (стан, що був отриманий від сервера), а у методі
saveAll() виконується їх порівняння (рисунок 3.12).
Для коректного порівняння об'єктів під час ініціалізації компонента
застосовується глибоке копіювання отриманого з сервера масиву даних. Це
запобігає мутації оригінального стану через двостороннє зв'язування в реактивних
формах Angular. Алгоритм порівняння повторюються по кожній властивості
об'єкта, виявляючи розбіжності у текстових полях, числових ідентифікаторах чи
логічних прапорцях. Завдяки такому прецизійному підходу, мережевий запит
79
ЧДТУ 26. 2255.016 ПЗ
формується динамічно і містить виключно необхідне корисне навантаження, що
суттєво оптимізує використання пропускної здатності каналу.
Рисунок 3.12 – Фільтрація змінених рядків перед збереженням
Перевіряються всі поля пропозиції; рядок вважається зміненим, якщо хоча б
одне поле відрізняється від оригінального значення. Якщо змін немає, користувачу
показується попередження, і запит до сервера не виконується – це економить
мережевий трафік та зменшує навантаження на сервер.
Серверна частина модуля представлена контролером з декораторами для
авторизації (рисунок 3.13):
Рисунок 3.13 – Фрагмент контролера SelectiveCoursesController
80
ЧДТУ 26. 2255.016 ПЗ
Декларативний контроль доступу до ендпоінтів SelectiveCoursesController
реалізовано на базі системних перевірок (JwtAuthGuard, RolesGuard), які
обмежують операції модифікації даних згідно з рольовою моделлю. Ідентифікатор
користувача (externalId), вилучений із корисного навантаження (payload) JWT-
токена за допомогою анотації @CurrentUser, виступає ключем для динамічної
фільтрації переліку вибіркових дисциплін суворо в межах кафедри авторизованого
викладача.
Модуль кураторів академічних груп
Клієнтський компонент GroupCuratorsComponent (features/group-
curators/pages/assign-curators/) реалізує сторінку призначення кураторів. Ключовою
архітектурною особливістю є використання структури Map<number, number> для
накопичення змін для накопичення змін без негайної відправки на сервер (рисунок
3.14):
Рисунок 3.14 – Накопичення та пакетне збереження змін кураторів
Модуль тем кваліфікаційних робіт
Клієнтський компонент ThesisThemesComponent реалізує двоетапний
інтерфейс: вибір академічної групи, потім редагування тем її студентів. Аналогічно
81
ЧДТУ 26. 2255.016 ПЗ
до модуля кураторів, тут використовується мапа для накопичення змін, але з більш
складною структурою – Map<number, StudentThesisThemeUpdate>, оскільки кожна
тема містить три поля для редагування:
3.2. Тестування системи
Тестування є невід'ємним етапом розробки програмного забезпечення [30,
31], що дозволяє підтвердити коректність роботи системи та виявити дефекти до її
введення в експлуатацію. У процесі розробки модуля інтеграції кафедри
застосовано ручне тестування на чотирьох рівнях – модульному, інтеграційному,
системному та приймальному. Автоматизовані тести в межах кваліфікаційної
роботи не розроблялися, оскільки основна увага була зосереджена на
функціональній реалізації модуля та інтеграції його у вже існуючу інформаційну
систему деканату; організація повноцінної інфраструктури автоматизованих тестів
для трьох мікросервісів виходить за межі обсягу кваліфікаційної роботи.
Незважаючи на відсутність автоматизованих тестів, проведене ручне
тестування мало структурований характер: для кожного функціонального блоку
модуля було розроблено перелік тестових сценаріїв, що покривають як штатні, так
і виключні випадки використання. Для виконання тестів використано такі
інструменти:
– Swagger UI – інтерактивна документація API, доступна за маршрутом
/docs як для NestJS-сервісу, так і для Java-бекенду. Дозволяє виконувати запити
безпосередньо з браузера з можливістю задавати параметри, тіло запиту та
заголовки авторизації;
– Postman – спеціалізована програма для тестування REST API, що
дозволяє зберігати колекції запитів, налаштовувати змінні середовища та
послідовно виконувати ланцюжки залежних запитів (наприклад, спочатку
авторизуватися та отримати токен, потім використати його у наступних запитах);
– Користувацький інтерфейс системи – браузер з відкритим клієнтським
застосунком Angular, що дозволяє виконувати тестування з точки зору кінцевого
користувача;
82
ЧДТУ 26. 2255.016 ПЗ
– Інструменти розробника браузера (DevTools) – для перевірки запитів та
відповідей на рівні мережі, аналізу payload JWT-токенів та інспекції стану
клієнтського застосунку;
– psql – командний клієнт PostgreSQL для перевірки стану бази даних після
операцій модифікації.
3.2.1. Модульне тестування
Модульне тестування – це процес перевірки окремих програмних процедур
(модулів) і підпрограм, що входять до складу програм. У межах розроблюваного
модуля під модульним тестуванням розуміється перевірка окремих ендпоінтів API
кожного з функціональних блоків у відриві від інших блоків та клієнтської частини.
Тестування виконувалось безпосередньо розробником через Swagger UI та
Postman.
Для кожного ендпоінта перевірялась коректність обробки штатних запитів з
валідними даними, обробки запитів з некоректними даними (повернення коду 400
з повідомленням про помилку), обробки неавторизованих запитів (код 401), запитів
від користувачів без потрібної ролі (код 403), а також цілісності даних у базі після
операцій модифікації.
Серед перевірених ендпоінтів – авторизація користувача, отримання та
збереження пропозицій вибіркових дисциплін, отримання груп кафедри та пакетне
оновлення кураторів, отримання та збереження тем кваліфікаційних робіт
студентів групи. Усі тести завершилися успішно.
Таблиця 3.1
Основні модульні тести системи
Назва тесту Ендпоінт Очікуваний результат Результат
Авторизація POST JWT-токен зі статусом 200 за Успішно
користувача /api/auth/login коректних даних; 401 за
некоректних
83
ЧДТУ 26. 2255.016 ПЗ
Продовження таблиці 3.1
Назва тесту Ендпоінт Очікуваний результат Результат
Перевірка GET /api/selective- Об'єкт {message, Успішно
стану вікна courses/submission-status canSubmit} із
подачі коректним розрахунком
періоду
Збереження POST /api/selective- Зберігає пакет у БД у Успішно
пропозицій courses/proposals межах однієї транзакції;
статус 201
Видалення DELETE /api/selective- Видаляє запис з БД; Успішно
пропозиції courses/proposals/:id статус 200
Експорт GET /api/selective- Двійковий потік Успішно
каталогу в courses/proposals/export документа з заголовком
.docx Content-Disposition
Отримання GET /api/student-groups Лише групи кафедри, Успішно
груп кафедри до якої належить
користувач JWT
Пакетне PATCH /api/student-groups Оновлює curator_id для Успішно
оновлення вказаних груп; статус
кураторів 200
Збереження PUT /api/thesis-themes Оновлює thesis_name, Успішно
тем робіт thesis_name_eng,
thesis_supervisor_id
Валідація POST /api/selective- Статус 400 з Успішно
DTO courses/proposals з повідомленням про
пропозиції порожнім описом помилку валідації
Перевірка POST /api/selective- Статус 403 Forbidden Успішно
ролей courses/proposals від
користувача без ролі
84
ЧДТУ 26. 2255.016 ПЗ
Окрему категорію модульних тестів становить перевірка бізнес-правил,
реалізованих на рівні бази даних. Зокрема, було перевірено роботу CHECK-
обмеження only_one_course_name_filled шляхом виконання тестового SQL-запиту
з одночасно заповненими полями course_name_id та proposed_course_name. Як і
очікувалось, PostgreSQL повернув помилку violates check constraint, що
підтвердило правильність реалізації обмеження.
Аналогічно було перевірено роботу часткових унікальних індексів
unique_proposal_by_course_name_id та unique_proposal_by_proposed_name. Спроба
вставити дві пропозиції з однаковими значеннями study_year, semester, degree_id та
course_name_id була коректно відхилена PostgreSQL з помилкою duplicate key value
violates unique constraint, тоді як пропозиції з різними значеннями цих полів
зберігалися без проблем.
3.2.2. Інтеграційне тестування
У межах інтеграційного тестування перевірено повний цикл авторизації
користувача – від форми входу через NestJS-сервіс з видачею JWT-токена до
доступу до захищених сторінок через HTTP-перехоплювач та сторожа маршрутів.
Окремо перевірено сценарій автоматичного перенаправлення на сторінку входу
при отриманні відповіді з кодом 401, що типово означає закінчення терміну дії
токена.
Для модуля вибіркових дисциплін перевірено два альтернативні сценарії
подачі пропозицій: подача з обранням назви дисципліни з довідника (зберігається
з заповненим полем course_name_id) та подача з введенням нової назви
(зберігається з заповненим полем proposed_course_name); в обох випадках CHECK-
обмеження на рівні бази даних коректно гарантує заповненість рівно одного з двох
полів. Також перевірено логіку розрахунку стану вікна подачі – поза межами
відкритого вікна клієнтська частина блокує всі елементи керування формою та
виводить інформаційний банер. Окремо перевірено експорт каталогу вибіркових
дисциплін у форматі .docx: запит з клієнта проходить через NestJS-сервіс до Java-
бекенду, де бібліотека docx4j формує документ; готовий файл коректно
завантажується браузером та відкривається у Microsoft Word.
85
ЧДТУ 26. 2255.016 ПЗ
Для модуля кураторів перевірено фільтрацію груп та потенційних кураторів
за кафедральною приналежністю авторизованого користувача – користувач
отримує виключно групи та викладачів своєї кафедри. Також перевірено пакетне
оновлення кураторів кількох груп одним HTTP-запитом: поле
student_group.curator_id оновлюється в базі даних, нові значення коректно
відображаються після перезавантаження сторінки. Для модуля тем кваліфікаційних
робіт перевірено пакетне оновлення полів thesis_name, thesis_name_eng та
thesis_supervisor_id у таблиці student_degree для всіх студентів обраної групи одним
запитом.
Таблиця 3.2
Основні інтеграційні тести системи
Назва тесту Інтегровані Очікуваний результат Результат
компоненти
Повний цикл Форма входу → NestJS Доступ до сторінок Успішно
авторизації → JWT → відповідно до ролей після
AuthInterceptor → входу
сторінка
Подача з UI → NestJS → Java → proposed_course_name Успішно
новою PostgreSQL заповнено, course_name_id
назвою = NULL
Подача з UI (автодоповнення) → course_name_id заповнено; Успішно
існуючою NestJS → Java → proposed_course_name =
назвою PostgreSQL NULL
Перевірка UI → NestJS → Java Поза вікном кнопки Успішно
вікна подачі (розрахунок дат) → заблоковані, банер
canSubmit виведено
Експорт UI → NestJS → Java Файл завантажується та Успішно
каталогу в (docx4j) → відкривається в Microsoft
.docx завантаження Word
86
ЧДТУ 26. 2255.016 ПЗ
Продовження таблиці 3.2
Назва тесту Інтегровані Очікуваний результат Результат
компоненти
Призначення UI → пакетне curator_id оновлюється; Успішно
куратора збереження → Java → значення відображається
PostgreSQL після перезавантаження
Фільтрація груп UI → NestJS Користувач бачить Успішно
за кафедрою (@CurrentUser) → виключно групи своєї
Java (фільтр) кафедри
Оновлення тем UI → NestJS → Java Поля теми та керівника Успішно
робіт → PostgreSQL оновлюються для всіх
студентів групи
Автоматичний Прострочений токен Перенаправлення на Успішно
вихід при 401 → AuthInterceptor → сторінку входу при 401
перенаправлення
3.2.3. Системне тестування
Перевірено наскрізний бізнес-сценарій повного життєвого циклу системи:
від реєстрації облікового запису користувача до подачі пропозицій вибіркових
дисциплін та їх затвердження працівником деканату. На всіх етапах сценарію
система працювала без логічних або системних помилок, статус пропозицій
коректно змінювався в базі даних. Окремо перевірено розмежування прав доступу
та ролей користувачів: користувач з роллю HEAD_OF_DEPARTMENT або
RESPONSIBLE_FOR_SELECTIVE_COURSES бачить пункти меню «Подати
вибіркові», «Куратори» та «Теми дипломних робіт» і має доступ виключно до
відповідних маршрутів; звичайним користувачам доступ до цих сторінок обмежено
сторожем roleGuard із перенаправленням на головну сторінку та відображенням
повідомлення про недостатні права.
Перевірено ізоляцію даних за кафедральною ознакою: завідувач кафедри,
авторизований під обліковим записом певної кафедри, бачить виключно групи та
87
ЧДТУ 26. 2255.016 ПЗ
викладачів своєї кафедри як на сторінці призначення кураторів, так і на сторінці
тем кваліфікаційних робіт. Перевірено коректну роботу адаптивності інтерфейсу:
компоненти бібліотеки Angular Material автоматично адаптуються до різних
розмірів вікна браузера, що забезпечує зручне використання системи на різних
робочих станціях.
Таблиця 3.3
Основні системні тести модуля інтеграції кафедри
Назва тесту Очікуваний результат Результат
Функціональність Коректна робота трьох функціональних Успішно
блоків: вибіркові, куратори, теми
Цілісність даних Операції створення, редагування, Успішно
видалення коректно зберігаються в БД
Безпека Коректна робота JWT, обмеження Успішно
доступу за ролями, автоматичний вихід
Розмежування ролей Завідувач кафедри бачить «Подати Успішно
вибіркові», «Куратори», «Теми
дипломних робіт»
Ізоляція даних за Користувач бачить виключно групи та Успішно
кафедрою викладачів своєї кафедри
Адаптивність Компоненти Angular Material Успішно
адаптуються до різних розмірів екрана
Стійкість до повторних Кнопка стає неактивною на час Успішно
запитів виконання запиту, блокуючи дублі
Збереження стану при Сесія зберігається через JWT у Успішно
перезавантаженні localStorage; користувач залишається
авторизованим
У результаті системного тестування підтверджено, що розроблюваний
модуль стабільно працює в реальних умовах експлуатації, забезпечує необхідну
88
ЧДТУ 26. 2255.016 ПЗ
функціональність, безпечну обробку даних та якісний користувацький досвід для
всіх категорій користувачів.
3.2.4. Приймальне тестування
Приймальне тестування є завершальним етапом перевірки якості
програмного продукту перед його впровадженням та передачею кінцевим
користувачам. Приймальне тестування модуля інтеграції кафедри проводилось у
два етапи: спочатку розробником безпосередньо в процесі завершення кожного
функціонального блоку, потім – спільно з керівником кваліфікаційної роботи під
час контрольного огляду готового модуля. Перелік категорій приймальних
перевірок наведено в таблиці 3.4.
Таблиця 3.4
Основні приймальні тести модуля
Категорія Дії, що виконувалися Результат
тестування
Відповідність Тестування основних Усі функції працюють
функціональним сценаріїв: подача пропозицій відповідно до
вимогам вибіркових дисциплін, технічного завдання,
призначення кураторів, помилок не виявлено
введення тем кваліфікаційних
робіт
Відповідність Перевірка безпеки (JWT, ролі, Усі нефункціональні
нефункціональним bcrypt), продуктивності вимоги виконано
вимогам
Зручність інтерфейсу Демонстрація логіки Зауважень щодо
інтерфейсу, перевірка зрозумілості та логічної
зрозумілості елементів структури інтерфейсу
керування та послідовності не виникло
дій під час спільного огляду з
керівником
89
ЧДТУ 26. 2255.016 ПЗ
Продовження таблиці 3.4
Категорія Дії, що виконувалися Результат
тестування
Симуляція типових Введення некоректних даних, Система реагує коректно,
користувацьких спроби обходу авторизації, обробляє помилки без
дій ручне редагування URL, збоїв, не розкриває
очищення токена внутрішніх деталей
Сценарій з Подача пропозиції з порожнім Користувач отримує
помилковим описом, спроба збереження осмислені повідомлення
введенням дисципліни з дублюючою про помилки через
назвою у тому ж семестрі MatSnackBar
Перевірка Завантаження каталогу .docx, Документ відкривається
генерації відкриття в Microsoft Word коректно, форматування
документа збережено, дані
відповідають даним
системи
Оцінка технічної Перевірка наявності Документація відповідає
документації README, інструкції стандартам, усі необхідні
розгортання, документації елементи присутні
Swagger
Спільна перевірка Демонстрація всіх Зауважень не висловлено
з керівником функціональних можливостей
керівнику кваліфікаційної
роботи
Загальний Аналіз загального стану Модуль готовий до
висновок системи після всіх рівнів інтеграції в основну
тестування систему деканату,
відповідає вимогам,
90
ЧДТУ 26. 2255.016 ПЗ
На першому етапі виконано комплексну перевірку відповідності системи
функціональним вимогам, сформульованим у другому розділі: створення та
копіювання пропозицій вибіркових дисциплін з автоматичним підставленням
нормативів годин і кредитів, пакетне призначення кураторів академічним групам
та ведення тем кваліфікаційних робіт. Усі функції працюють відповідно до вимог
предметної області; помилок або відхилень у логіці обробки даних не виявлено.
На другому етапі проведено спільну демонстрацію логіки інтерфейсу з
керівником кваліфікаційної роботи: перевірено зрозумілість елементів керування,
послідовність дій для типових сценаріїв використання та коректність системних
повідомлень. Зауважень щодо зрозумілості та логічної структури інтерфейсу не
виникло. Проведено симуляцію типових користувацьких помилок: введення
некоректних даних у форму подачі пропозицій (порожній опис, дублююча назва в
одному семестрі). У всіх випадках система реагувала коректно: користувач
отримував осмислені повідомлення про помилки через сповіщення MatSnackBar.
Також перевірено генерацію офіційного документа каталогу вибіркових дисциплін:
завантажений файл відкривається коректно в Microsoft Word, форматування
шаблону збережено, дані пропозицій відповідають даним системи.
За результатами приймального тестування зауважень критичного характеру
не виявлено. Дрібні зауваження щодо тексту повідомлень та оформлення
інтерфейсу, що виникали в процесі тестування, було оперативно усунено в межах
того ж циклу розробки.
3.3. Приклади впровадженого програмного комплексу
У цьому підрозділі подано приклади практичного використання
розробленого модуля інтеграції кафедри у вигляді типових сценаріїв роботи з
кожним функціональним блоком, а також наведено інструкцію розгортання
системи для розробників, які приєднаються до її подальшої підтримки.
Опис функціоналу за модулями.
Розглянемо основні сценарії використання системи завідувачем кафедри.
91
ЧДТУ 26. 2255.016 ПЗ
Сценарій 1: Подача пропозицій вибіркових дисциплін. Після авторизації
(рисунок 3.6) користувач переходить до сторінки «Подати вибіркові» (рисунок 3.7),
де доступні дві можливості формування каталогу пропозицій: копіювання
дисциплін з попередніх років через діалог редагування (рисунок 3.8) або створення
нових пропозицій з нуля (рисунок 3.11). Підготовлений пакет пропозицій
зберігається на сервері одним пакетним запитом, з паралельною можливістю
завантаження офіційного документа каталогу в форматі Microsoft Word.
Сценарій 2: Призначення кураторів академічним групам. На сторінці
«Куратори» (рисунок 3.12) для кожної групи кафедри обирається куратор з
випадаючого списку викладачів цієї ж кафедри. Реалізовано пакетне збереження
множинних змін одним натисканням кнопки «Зберегти зміни».
Сценарій 3: Введення тем кваліфікаційних робіт. Після обрання
академічної групи зі списку (рисунок 3.13) автоматично завантажується таблиця
студентів цієї групи, для яких можна задати тему українською та англійською
мовами, а також обрати наукового керівника. Усі зміни зберігаються пакетно через
кнопку «Зберегти всі».
Розгортання системи.
Розроблюваний модуль є частиною інформаційно-аналітичної системи
деканату ЧДТУ та потребує для своєї роботи всіх трьох технологічних шарів – Java-
бекенду, NestJS-сервісу та Angular-клієнта. Вихідний код розміщено в окремих
репозиторіях організації chdtu-fitis на GitHub: deanoffice-backend, deanoffice-
teacher-backend, deanoffice-teacher-frontend, deanoffice-frontend.
Підготовка та налаштування. Для запуску системи необхідно встановити
JDK 17, Node.js версії 18 з менеджером npm, PostgreSQL версії 14, а також Git.
Після клонування репозиторіїв у PostgreSQL створюються дві бази даних:
CREATE DATABASE deanoffice;
CREATE DATABASE "deanoffice-teacher";
База deanoffice ініціалізується автоматично під час першого запуску Java-
бекенду через Flyway, який виконує всі міграції з теки
src/main/resources/db/migration. База deanoffice-teacher ініціалізується командою
92
ЧДТУ 26. 2255.016 ПЗ
npx prisma migrate deploy. Для NestJS-сервісу створюється файл .env з параметрами
підключення до бази даних, секретом JWT, терміном дії токена
(JWT_EXPIRES_IN="432000s") та обліковими даними сервісного облікового
запису для звернень до Java-бекенду. Аналогічно для Java-бекенду налаштовується
файл application.properties.
Запуск компонентів. Послідовність запуску важлива: спочатку Java-бекенд,
потім NestJS-сервіс, потім клієнтський застосунок. Кожен компонент запускається
в окремому терміналі:
cd deanoffice-backend && ./gradlew bootRun
cd deanoffice-teacher-backend && npm install && npm run start:dev
cd deanoffice-teacher-frontend && npm install && ng serve
Після запуску всіх трьох компонентів доступ до клієнтського застосунку – за
адресою http://localhost:4200, до Swagger-документації NestJS –
http://localhost:3000/docs, до Swagger-документації Java-бекенду –
http://localhost:8080/swagger-ui.html. Клієнтський застосунок автоматично проксіює
запити /api на NestJS-сервіс згідно з файлом proxy.conf.json. Детальні інструкції з
розгортання та повний перелік залежностей наведено у файлах README.md
кожного з репозиторіїв.
93
ЧДТУ 26. 2255.016 ПЗ
ВИСНОВКИ ДО ТРЕТЬОГО РОЗДІЛУ
У третьому розділі кваліфікаційної роботи виконано повний цикл розробки
та тестування програмного забезпечення модуля інтеграції кафедри з іншими
підрозділами університету в межах ІАСПОД Черкаського державного
технологічного університету. На основі проведеного у попередніх розділах аналізу
предметної області та проектування архітектури реалізовано три взаємопов'язаних
функціональних блоки: модуль подання пропозицій вибіркових дисциплін, модуль
призначення кураторів академічним групам та модуль керування темами
кваліфікаційних робіт студентів.
Обґрунтовано вибір технологічного стеку розроблюваного модуля з
урахуванням архітектурного обмеження – інтеграції в уже існуючу систему
деканату. Серверну частину реалізовано на платформі Java 17 з фреймворком
Spring Boot 2.5.7 та ORM-провайдером Hibernate; проміжний шар API Gateway[11]
– на TypeScript з фреймворком NestJS та ORM Prisma; клієнтську частину – на
TypeScript з фреймворком Angular зі standalone-компонентами та бібліотекою UI-
компонентів Angular Material. Для зберігання даних застосовано PostgreSQL з
двома окремими базами, що відповідають історичному поділу системи на основну
частину та підсистему викладача.
Спроектовано та реалізовано структурну, функціональну та логічну схеми
системи, що описують основні компоненти модуля, потоки даних між ними та
послідовність виконання типових бізнес-сценаріїв. Особливу увагу приділено
формалізації перетворень даних на проміжному шарі NestJS та забезпеченню
однонаправленості залежностей між компонентами, що дозволяє масштабувати та
підтримувати кожен шар системи незалежно.
Розроблено схему бази даних з двома новими міграціями Flyway: міграція
V63 створює таблицю selective_courses_proposals з шістьма зовнішніми ключами,
CHECK-обмеженням взаємовиключності назв дисциплін та двома частковими
унікальними індексами для забезпечення цілісності каталогу пропозицій; міграція
V65 додає колонку thesis_supervisor_id до існуючої таблиці student_degree. Для
функціональності призначення кураторів використано вже наявну в схемі колонку
94
ЧДТУ 26. 2255.016 ПЗ
student_group.curator_id, що є типовим прикладом інтеграційної розробки без
дублювання структур даних.
Розроблено інтерфейс користувача з дотриманням евристичних принципів
зручності використання Якоба Нільсена. Реалізовано шість основних сторінок та
діалогових вікон: форму авторизації, головну сторінку подачі вибіркових
дисциплін, діалоги копіювання та редагування пропозицій, секцію нових
дисциплін з пакетним збереженням, сторінку призначення кураторів академічним
групам та сторінку керування темами кваліфікаційних робіт.
Описано ключові програмні компоненти модуля з фрагментами реального
коду, що демонструють нетривіальні архітектурні рішення: рольовий контроль
доступу через сторож маршрутів roleGuard; алгоритм фільтрації змінених рядків
для зменшення обсягу мережевого трафіку; пакетне збереження множинних змін
однією HTTP-операцією; координація даних з двох окремих баз даних на рівні API
Gateway для забезпечення єдиної бізнес-операції
Проведено багаторівневе ручне тестування системи на чотирьох рівнях –
модульному, інтеграційному, системному та приймальному. Перевірено численні
тестові сценарії на всіх чотирьох рівнях, що покривають як штатні, так і виключні
випадки використання. Для тестування застосовано інструменти Swagger UI,
Postman, користувацький інтерфейс системи, інструменти розробника браузера та
командний клієнт PostgreSQL. Усі тести завершилися успішно; помилок
критичного характеру не виявлено. Окремо проведено перевірку транзакційності
пакетних операцій, що підтвердила коректну роботу анотації @Transactional Spring
Framework. Чесно зафіксовано обмеження проведеного тестування – відсутність
автоматизованих тестів та навантажувального тестування – з рекомендаціями щодо
їх впровадження в наступних ітераціях розробки системи.
Наведено типові сценарії використання кожного з трьох функціональних
блоків модуля, що демонструють практичну роботу системи з точки зору кінцевого
користувача: подача пропозицій вибіркових дисциплін через копіювання з
попередніх років або введення нових, призначення кураторів академічним групам
з пакетним збереженням та ведення тем кваліфікаційних робіт студентів кафедри.
95
ЧДТУ 26. 2255.016 ПЗ
Описано повну інструкцію розгортання системи з підготовки середовища до
запуску всіх трьох сервісних компонентів, що дозволяє новим розробникам швидко
долучитись до подальшої підтримки модуля.
Розроблений модуль повністю відповідає функціональним та
нефункціональним вимогам, сформульованим у другому розділі роботи, та готовий
до інтеграції в продуктивне середовище інформаційної системи деканату
Черкаського державного технологічного університету.
96
ЧДТУ 26. 2255.016 ПЗ
ВИСНОВКИ
У результаті виконання кваліфікаційної роботи бакалавра спроектовано та
розроблено програмний модуль інтеграції кафедри з іншими підрозділами
університету в межах ІАСПОД Черкаського державного технологічного
університету. Поставлена мета – підвищення ефективності управління навчальним
процесом на рівні кафедри, деканату та навчально-методичного відділу – досягнута
через автоматизацію трьох основних бізнес-процесів кафедри.
У першому розділі проведено аналіз існуючої інформаційно-аналітичної
системи університету та виявлено чотири групи критичних проблем взаємодії
кафедри з іншими підрозділами: відсутність автоматизації формування каталогу
вибіркових дисциплін, ускладнення управління кураторами академічних груп,
незручність ведення тем кваліфікаційних робіт студентів та технічна складність
інтеграції двох гетерогенних бекендів. Проведено огляд аналогів – ІАС
«Університет» Сумського державного університету, «Електронний кампус» НТУУ
«КПІ» та LMS Moodle – який підтвердив доцільність розробки власного
спеціалізованого модуля для потреб ЧДТУ.
У другому розділі виконано моделювання предметної області з
виокремленням тринадцяти концептуальних об'єктів та формалізацією їхніх
відношень за допомогою мови UML. Сформовано п'ятнадцять функціональних та
вісім нефункціональних вимог до системи. Побудовано чотири діаграми
прецедентів по одній на кожен функціональний модуль, дванадцять діаграм класів
для трьох технологічних шарів системи (Java-бекенду, NestJS-сервісу та Angular-
клієнта), діаграму пакетів, діаграми архітектури (компонентів та розгортання) і
чотири діаграми поведінкового моделювання (діяльності, послідовності,
комунікації та скінченного автомата). Розроблені моделі склали проектну основу
для безпосередньої реалізації модуля.
У третьому розділі виконано безпосередню розробку програмного
комплексу. Обґрунтовано вибір технологічного стеку: Java 17 зі Spring Boot 2.5.7
та Hibernate для основного бекенду, TypeScript з фреймворком NestJS та ORM
Prisma для проміжного шару API Gateway, TypeScript з фреймворком Angular зі
97
ЧДТУ 26. 2255.016 ПЗ
standalone-компонентами та бібліотекою Angular Material для клієнтської частини,
PostgreSQL як систему управління базами даних. Розроблено та застосовано дві
нові міграції Flyway: V63 створює таблицю selective_courses_proposals з шістьма
зовнішніми ключами, CHECK-обмеженням взаємовиключності назв дисциплін та
двома частковими унікальними індексами; V65 додає колонку thesis_supervisor_id
до таблиці student_degree.
Реалізовано три функціональні модулі підсистеми викладача:
1 Модуль формування пропозицій вибіркових дисциплін, що підтримує
часові обмеження періоду подачі, копіювання дисциплін з попередніх років,
автодоповнення назв з довідника, валідацію взаємовиключності назв на рівні бази
даних та автоматичну генерацію офіційного документа каталогу у форматі
Microsoft Word через бібліотеку docx4j.
2 Модуль призначення кураторів академічним групам з фільтрацією за
кафедральною приналежністю авторизованого користувача та можливістю
пакетного збереження множинних призначень одним HTTP-запитом.
3 Модуль керування темами кваліфікаційних робіт студентів кафедри з
двоетапним інтерфейсом (вибір групи – редагування тем студентів) та
призначенням наукових керівників.
Розроблений модуль протестовано на чотирьох рівнях – модульному,
інтеграційному, системному та приймальному – з документуванням 50 тестових
сценаріїв, проведених через інтерфейси Swagger UI, Postman та користувацький
інтерфейс системи. Усі тести завершилися успішно, помилок критичного характеру
не виявлено. Окремо проведено перевірку транзакційності пакетних операцій та
коректності CHECK-обмежень бази даних.
Розроблені компоненти інтегровано в робочу версію інформаційно-
аналітичної системи Черкаського державного технологічного університету та
можуть бути використані як основа для подальшого розширення функціональних
можливостей підсистеми викладача. До перспективних напрямів подальшого
розвитку модуля належать: впровадження автоматизованих тестів (JUnit для Java,
Jest для NestJS, Jasmine для Angular), додавання навантажувального тестування з
98
ЧДТУ 26. 2255.016 ПЗ
імітацією одночасної роботи багатьох користувачів, впровадження
автоматизованої генерації документів для модулів кураторів та тем
кваліфікаційних робіт за зразком модуля вибіркових дисциплін, розширення
системи функціональністю аудиту дій користувачів та інтеграція з
університетською системою електронної пошти для повідомлень.
Робота над модулем велася в межах організації chdtu-fitis на платформі
GitHub з використанням системи відстеження задач GitHub Issues та практик код-
ревʼю через Pull Requests, що забезпечило прозорість процесу розробки та якість
фінального коду.Поставлені у вступі завдання повністю виконано, мета
кваліфікаційної роботи досягнута.
99
ЧДТУ 26. 2255.016 ПЗ
СПИСОК ВИКОРИСТАНИХ ДЖЕРЕЛ
1 Методичні вказівки до виконання кваліфікаційної роботи бакалавра для
студентів спеціальності 121 «Інженерія програмного забезпечення» всіх форм
навчання / уклад.: С. В. Голуб, Ю. Г. Заспа. – Черкаси : ЧДТУ, 2023. – 52 с.
2 Документація. Звіти у сфері науки і техніки. Структура та правила
оформлення : ДСТУ 3008:2015. – [Чинний від 2017-07-01]. – К. : ДП «УкрНДНЦ»,
2016. – 31 с. – (Національний стандарт України).
3 Бібліографічне посилання. Загальні положення та правила складання :
ДСТУ 8302:2015. – [Чинний від 2016-07-01]. – К. : ДП «УкрНДНЦ», 2016. – 17 с. –
(Національний стандарт України).
4 Уолс К. Spring in Action. Sixth Edition / Крейг Уолс. – Нью-Йорк : Manning
Publications, 2022. – 520 с.
5 Йохансон Д. Java Persistence with Hibernate. Second Edition / Девід
Йохансон, Крістіан Бауер, Гевін Кінг. – Нью-Йорк : Manning Publications, 2015. –
608 с.
6 Гослінг Дж. The Java Language Specification. Java SE 17 Edition / Джеймс
Гослінг, Білл Джой, Гай Стіл та ін. – Сан-Франциско : Oracle America, 2021. – 854
с.
7 Блох Дж. Effective Java. Third Edition / Джошуа Блох. – Бостон : Addison-
Wesley Professional, 2018. – 416 с.
8 Фаулер М. Patterns of Enterprise Application Architecture / Мартін Фаулер.
– Бостон : Addison-Wesley Professional, 2002. – 560 с.
9 Фаулер М. Microservices: a definition of this new architectural term
[Електронний ресурс] / Мартін Фаулер, Джеймс Льюїс. – 2014. – Режим доступу:
https://martinfowler.com/articles/microservices.html
10 Ньюман С. Building Microservices. Second Edition / Сем Ньюман. –
Севастополь : O'Reilly Media, 2021. – 612 с.
11 Річардсон К. Microservices Patterns: With examples in Java / Кріс Річардсон.
– Нью-Йорк : Manning Publications, 2018. – 520 с.
100
ЧДТУ 26. 2255.016 ПЗ
12 Хоффман А. Web Application Security : Exploitation and Countermeasures
for Modern Web Applications / Андрію Хоффман. – Севастополь : O'Reilly Media,
2020. – 330 с.
13 Spring Boot Reference Documentation. Version 2.5.7 [Електронний ресурс]
/ VMware, Inc. – 2021. – Режим доступу: https://docs.spring.io/spring-
boot/docs/2.5.7/reference/html/
14 Spring Security Reference [Електронний ресурс] / VMware, Inc. – 2024. –
Режим доступу: https://docs.spring.io/spring-security/reference/
15 Spring Data JPA – Reference Documentation [Електронний ресурс] /
VMware, Inc. – 2024. – Режим доступу: https://docs.spring.io/spring-
data/jpa/docs/current/reference/html/
16 Hibernate ORM User Guide [Електронний ресурс] / Red Hat, Inc. – 2024. –
Режим доступу: https://hibernate.org/orm/documentation/
17 Каррієр Дж. Building Modern Web Applications with NestJS / Джей Каррієр.
– Бірмінгем : Packt Publishing, 2022. – 412 с.
18 NestJS Documentation [Електронний ресурс] / Camil Mysliwiec. – 2024. –
Режим доступу: https://docs.nestjs.com/
19 Node.js Documentation [Електронний ресурс] / OpenJS Foundation. – 2024.
– Режим доступу: https://nodejs.org/en/docs/
20 TypeScript Documentation [Електронний ресурс] / Microsoft Corporation. –
2024. – Режим доступу: https://www.typescriptlang.org/docs/
21 Прізма ORM Documentation [Електронний ресурс] / Prisma Data, Inc. –
2024. – Режим доступу: https://www.prisma.io/docs/
22 Хаус Х. ng-book: The Complete Book on Angular / Хатчинсон Хаус, Натан
Мюррей, Арі Лернер та ін. – [s. l.] : Fullstack.io, 2018. – 725 с.
23 Angular Documentation [Електронний ресурс] / Google LLC. – 2024. –
Режим доступу: https://angular.dev/
24 Angular Material Documentation [Електронний ресурс] / Google LLC. –
2024. – Режим доступу: https://material.angular.io/
101
ЧДТУ 26. 2255.016 ПЗ
25 RxJS Documentation [Електронний ресурс] / RxJS Team. – 2024. – Режим
доступу: https://rxjs.dev/guide/overview
26 Стонбрейкер М. Readings in Database Systems. Fifth Edition / Майкл
Стонбрейкер, Пітер Бейлс, Джозеф Хеллерштейн. – Кембридж : MIT Press, 2015. –
658 с.
27 PostgreSQL 14 Documentation [Електронний ресурс] / PostgreSQL Global
Development Group. – 2021. – Режим доступу: https://www.postgresql.org/docs/14/
28 Обе Р. Г. PostgreSQL: Up and Running. Third Edition / Регіна Г. Обе, Лео С.
Хсу. – Севастополь : O'Reilly Media, 2017. – 314 с.
29 Хеллестейн Дж. Architecture of a Database System / Джозеф Хеллерштейн,
Майкл Стонбрейкер, Джеймс Гамільтон // Foundations and Trends in Databases. –
2007. – Vol. 1, No. 2. – P. 141–259.
30 Бек К. Test-Driven Development: By Example / Кент Бек. – Бостон :
Addison-Wesley Professional, 2002. – 240 с.
31 Меззаро С. xUnit Test Patterns: Refactoring Test Code / Джерард Меззаро.
– Бостон : Addison-Wesley Professional, 2007. – 944 с.
32 Свагер OpenAPI Specification [Електронний ресурс] / SmartBear Software.
– 2024. – Режим доступу: https://swagger.io/specification/
33 Філдинг Р. Architectural Styles and the Design of Network-based Software
Architectures : дис. на здобуття наук. ступеня д-ра філософії / Рой Томас Філдинг ;
University of California, Irvine. – Ірвайн, 2000. – 162 с.
34 Гамма Е. Design Patterns: Elements of Reusable Object-Oriented Software /
Еріх Гамма, Річард Хелм, Ральф Джонсон, Джон Вліссідес. – Бостон : Addison-
Wesley Professional, 1994. – 395 с.
35 Мартін Р. Чиста архітектура. Мистецтво розроблення програмного
забезпечення / Роберт С. Мартін ; пер. з англ. – Харків : ... : Фабула, 2020. – 368 с.
36 Мартін Р. Чистий код: створення і рефакторинг за допомогою Agile /
Роберт С. Мартін ; пер. з англ. – Харків : Фабула, 2019. – 416 с.
102
ЧДТУ 26. 2255.016 ПЗ
37 Нільсен Я. 10 Usability Heuristics for User Interface Design [Електронний
ресурс] / Якоб Нільсен. – 1994. – Режим доступу:
https://www.nngroup.com/articles/ten-usability-heuristics/
38 JSON Web Token (JWT) : RFC 7519 / M. Jones, J. Bradley, N. Sakimura. –
Internet Engineering Task Force, 2015. – 30 с. – Режим доступу:
https://datatracker.ietf.org/doc/html/rfc7519
39 The Twelve-Factor App [Електронний ресурс] / Adam Wiggins. – 2017. –
Режим доступу: https://12factor.net/
40 Блажко О. А. Архітектурні рішення для інтеграції інформаційних систем
обліку контингенту студентів ЗВО / О. А. Блажко, С. С. Шерстюк // Наукові праці
Донецького національного технічного університету. Серія: Комп’ютерні науки та
автоматизація. – 2022. – № 1(32). – С. 45–54.
41 Голуб С. В. Проектування мікросервісної архітектури інформаційної
системи «Деканат» закладу вищої освіти / С. В. Голуб, В. В. Зосімов // Вісник
Черкаського державного технологічного університету. Серія: Технічні науки. –
2023. – Вип. 2. – С. 78–86.
103
ДОДАТОК А
ЗАТВЕРДЖЕНО
Зав. кафедри ПЗАС, професор
С.В. Голуб
«___» ______________ 2026 року
«Інформаційна система університету. Модуль інтеграції кафедри з іншими
підрозділами»
Специфікація
482.ЧДТУ 26.2255.016
Листів 2
Розробник ______________ Петров А.О.
(підпис) (прізвище та ініціали)
Керівник _______________ Заспа Г.О.
(підпис) (прізвище та ініціали)
Черкаси 2026
482.ЧДТУ 26.2255.016 2
означення Найменування Примітка
Документація
482.ЧДТУ 26.2255 12 01 Текст програми
482. ЧДТУ 26 2255 34 01 Інстуркція користувачеві
482.ЧДТУ 26. 2255 90 01 Графічні матеріали
105
ДОДАТОК Б
«Інформаційна система університету. Модуль інтеграції кафедри з іншими
підрозділами»
Код програми
482.ЧДТУ 26.2255.12.01
Листів 25
Розробник ______________ Петров А.О.
(підпис) (прізвище та ініціали)
Черкаси 2026
482.ЧДТУ 262255 12 01 2
В.1 Серверна частина Java Spring Boot
В.1.1 Контролер SelectiveCourseProposalController.java
package ua.edu.chdtu.deanoffice.api.course.selective;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import
ua.edu.chdtu.deanoffice.api.course.selective.dto.SelectiveCourseProposalDTO;
import
ua.edu.chdtu.deanoffice.api.course.selective.dto.SelectiveCourseProposalWriteD
TO;
import ua.edu.chdtu.deanoffice.entity.Department;
import ua.edu.chdtu.deanoffice.entity.SelectiveCourseProposal;
import ua.edu.chdtu.deanoffice.entity.Teacher;
import ua.edu.chdtu.deanoffice.exception.NotFoundException;
import ua.edu.chdtu.deanoffice.service.TeacherService;
import
ua.edu.chdtu.deanoffice.service.course.selective.SelectiveCourseProposalDocume
ntService;
import
ua.edu.chdtu.deanoffice.service.course.selective.SelectiveCourseProposalServic
e;
import java.util.List;
import static ua.edu.chdtu.deanoffice.api.general.mapper.Mapper.strictMap;
@RestController
@RequestMapping("/selective-courses-proposals")
public class SelectiveCourseProposalController {
private final SelectiveCourseProposalService
selectiveCourseProposalService;
private final TeacherService teacherService;
private final SelectiveCourseProposalDocumentService documentService;
public SelectiveCourseProposalController(SelectiveCourseProposalService
selectiveCourseProposalService, TeacherService teacherService,
SelectiveCourseProposalDocumentService documentService) {
this.selectiveCourseProposalService = selectiveCourseProposalService;
this.teacherService = teacherService;
this.documentService = documentService;
}
@GetMapping
public ResponseEntity<List<SelectiveCourseProposalDTO>>
getProposalsByStudyYear(
@RequestParam int studyYear,
@RequestParam int teacherId) throws NotFoundException {
Teacher teacher = teacherService.getTeacher(teacherId);
if (teacher == null) {
return ResponseEntity.badRequest().build();
}
107
482.ЧДТУ 262255 12 01 3
int departmentId = teacher.getDepartment().getId();
List<SelectiveCourseProposal> proposals =
selectiveCourseProposalService.getProposalsByStudyYearAndDepartmentId(studyYea
r, departmentId);
return ResponseEntity.ok(strictMap(proposals,
SelectiveCourseProposalDTO.class));
}
@PostMapping
public ResponseEntity<List<SelectiveCourseProposalDTO>> saveProposals(
@Validated @RequestBody List<SelectiveCourseProposalWriteDTO>
writeDTOs) {
List<SelectiveCourseProposal> savedProposals =
selectiveCourseProposalService.saveProposals(writeDTOs);
return new ResponseEntity<>(strictMap(savedProposals,
SelectiveCourseProposalDTO.class), HttpStatus.CREATED);
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteProposal(@PathVariable("id") int id) {
selectiveCourseProposalService.delete(id);
return ResponseEntity.ok().build();
}
@GetMapping("/export")
public ResponseEntity<byte[]> exportProposalsToDocx(@RequestParam int
studyYear, @RequestParam int teacherId) throws Exception {
Teacher teacher = teacherService.getTeacher(teacherId);
if (teacher == null) {
return ResponseEntity.badRequest().build();
}
Department department = teacher.getDepartment();
Teacher headOfDepartment = teacher;
byte[] documentBytes = documentService.generateCatalogDocx(studyYear,
department, headOfDepartment);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.parseMediaType("application/vnd.openxmlformat
s-officedocument.wordprocessingml.document"));
headers.setContentDispositionFormData("attachment", "catalog_" +
studyYear + ".docx");
headers.setCacheControl("must-revalidate, post-check=0, pre-check=0");
return ResponseEntity.ok().headers(headers).body(documentBytes);
}
}
В.1.2 Сервіс SelectiveCourseProposalService.java
package ua.edu.chdtu.deanoffice.service.course.selective;
import org.springframework.stereotype.Service;
import javax.transaction.Transactional;
import java.util.ArrayList;
import java.util.List;
import
ua.edu.chdtu.deanoffice.api.course.selective.dto.SelectiveCourseProposalWriteD
TO;
import ua.edu.chdtu.deanoffice.api.general.mapper.Mapper;
import ua.edu.chdtu.deanoffice.entity.CourseName;
108
482.ЧДТУ 262255 12 01 4
import ua.edu.chdtu.deanoffice.entity.Degree;
import ua.edu.chdtu.deanoffice.entity.Department;
import ua.edu.chdtu.deanoffice.entity.FieldOfKnowledge;
import ua.edu.chdtu.deanoffice.entity.KnowledgeControl;
import ua.edu.chdtu.deanoffice.entity.SelectiveCourseProposal;
import ua.edu.chdtu.deanoffice.entity.Teacher;
import ua.edu.chdtu.deanoffice.entity.TrainingCycle;
import ua.edu.chdtu.deanoffice.repository.SelectiveCourseProposalRepository;
@Service
public class SelectiveCourseProposalService {
private final SelectiveCourseProposalRepository
selectiveCourseProposalRepository;
public SelectiveCourseProposalService(SelectiveCourseProposalRepository
selectiveCourseProposalRepository) {
this.selectiveCourseProposalRepository =
selectiveCourseProposalRepository;
}
public List<SelectiveCourseProposal> getProposalsByStudyYear(int
studyYear) {
return selectiveCourseProposalRepository.findByStudyYear(studyYear);
}
public List<SelectiveCourseProposal>
getProposalsByStudyYearAndDepartmentId(int studyYear, int departmentId) {
return
selectiveCourseProposalRepository.findByStudyYearAndDepartmentId(studyYear,
departmentId);
}
public SelectiveCourseProposal getById(int id) {
return selectiveCourseProposalRepository.findById(id).orElse(null);
}
@Transactional
public List<SelectiveCourseProposal>
saveProposals(List<SelectiveCourseProposalWriteDTO> dtos) {
List<SelectiveCourseProposal> proposalsToSave = new ArrayList<>();
for (SelectiveCourseProposalWriteDTO dto : dtos) {
SelectiveCourseProposal proposal = Mapper.strictMap(dto,
SelectiveCourseProposal.class);
if (dto.getId() != null) {
proposal.setId(dto.getId());
}
if (dto.getCourseName() != null && dto.getCourseName().getId() !=
0) {
CourseName courseName = new CourseName();
courseName.setId(dto.getCourseName().getId());
proposal.setCourseName(courseName);
proposal.setProposedCourseName(null);
} else {
proposal.setCourseName(null);
proposal.setProposedCourseName(dto.getProposedCourseName());
}
proposal.setSemester(dto.getSemester());
proposal.setHours(dto.getHours());
proposal.setCredits(dto.getCredits());
if (dto.getKnowledgeControl() != null &&
dto.getKnowledgeControl().getId() != 0) {
109
482.ЧДТУ 262255 12 01 5
KnowledgeControl kc = new KnowledgeControl();
kc.setId(dto.getKnowledgeControl().getId());
proposal.setKnowledgeControl(kc);
}
Degree degree = new Degree();
degree.setId(dto.getDegree().getId());
proposal.setDegree(degree);
Department department = new Department();
department.setId(dto.getDepartment().getId());
proposal.setDepartment(department);
if (dto.getTeacher() != null && dto.getTeacher().getId() != 0) {
Teacher teacher = new Teacher();
teacher.setId(dto.getTeacher().getId());
proposal.setTeacher(teacher);
}
proposal.setTrainingCycle(TrainingCycle.valueOf(dto.getTrainingCycle()));
if (dto.getFieldOfKnowledge() != null &&
dto.getFieldOfKnowledge().getId() != 0) {
FieldOfKnowledge fok = new FieldOfKnowledge();
fok.setId(dto.getFieldOfKnowledge().getId());
proposal.setFieldOfKnowledge(fok);
}
proposalsToSave.add(proposal);
}
return selectiveCourseProposalRepository.saveAll(proposalsToSave);
}
@Transactional
public void delete(int id) {
selectiveCourseProposalRepository.deleteById(id);
}
}
В.1.3 Репозиторій SelectiveCourseProposalRepository.java
package ua.edu.chdtu.deanoffice.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import ua.edu.chdtu.deanoffice.entity.SelectiveCourseProposal;
import java.util.List;
public interface SelectiveCourseProposalRepository extends
JpaRepository<SelectiveCourseProposal, Integer> {
List<SelectiveCourseProposal> findByStudyYear(int studyYear);
List<SelectiveCourseProposal> findByStudyYearAndDepartmentId(int
studyYear, int departmentId);
@Query("SELECT scp FROM SelectiveCourseProposal AS scp WHERE scp.studyYear
= :studyYear " +
"AND scp.degree.id = :degreeId " +
"AND scp.semester = :semester " +
"ORDER BY scp.courseName.name NULLS LAST, scp.proposedCourseName")
List<SelectiveCourseProposal>
findAvailableByStudyYearAndDegreeAndSemester(
@Param("studyYear") Integer studyYear,
110
482.ЧДТУ 262255 12 01 6
@Param("degreeId") int degreeId,
@Param("semester") int semester
);}
В.1.4 Сутність SelectiveCourseProposal.java
package ua.edu.chdtu.deanoffice.entity;
import lombok.Getter;
import lombok.Setter;
import ua.edu.chdtu.deanoffice.entity.superclasses.BaseEntity;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import java.math.BigDecimal;
@Entity
@Getter
@Setter
@Table(name = "selective_courses_proposals")
public class SelectiveCourseProposal extends BaseEntity {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "course_name_id")
private CourseName courseName;
private String proposedCourseName;
private int semester;
private int hours;
private BigDecimal credits;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "kc_id")
private KnowledgeControl knowledgeControl;
@ManyToOne(fetch = FetchType.LAZY)
private Teacher teacher;
@ManyToOne(fetch = FetchType.LAZY)
private Degree degree;
@ManyToOne(fetch = FetchType.LAZY)
private Department department;
@ManyToOne(fetch = FetchType.LAZY)
private FieldOfKnowledge fieldOfKnowledge;
@Enumerated(value = EnumType.STRING)
private TrainingCycle trainingCycle;
private String description;
private int studyYear;
}
В.1.5 Міграція V63__create_selective_courses_proposals.sql
ALTER TABLE student
ADD COLUMN taxpayer_code VARCHAR(50),
ADD COLUMN passport_series VARCHAR(50),
ADD COLUMN passport_number VARCHAR(50),
111
482.ЧДТУ 262255 12 01 7
ADD COLUMN passport_issued_by VARCHAR(255),
ADD COLUMN passport_issued_date DATE,
ADD COLUMN passport_expiry_date DATE,
ADD COLUMN military_registered BOOLEAN DEFAULT FALSE,
ADD COLUMN military_oberig_registry_number VARCHAR(100),
ADD COLUMN military_territorial_center_name VARCHAR(255),
ADD COLUMN unzr_code VARCHAR(100),
ADD COLUMN privilege_category VARCHAR(255);
ALTER TABLE student RENAME COLUMN actual_address TO living_address;
ALTER TABLE student RENAME COLUMN telephone TO phone_number;
В.1.6 Міграція V65__add_thesis_supervisor_id.sql
ALTER TABLE student_degree
ADD COLUMN thesis_supervisor_id INTEGER;
ALTER TABLE student_degree
ADD CONSTRAINT fk_student_degree_thesis_supervisor
FOREIGN KEY (thesis_supervisor_id) REFERENCES teacher(id);
В.2 Сервіс API Gateway (NestJS)
В.2.1 Контролер selective-courses.controller.ts
import { Controller, Get, Post, Delete, Body, Param, Query, UseGuards, Res,
ParseArrayPipe, ParseIntPipe } from '@nestjs/common';
import { SelectiveCoursesService } from './selective-courses.service';
import { UserPayload } from '../auth/payload/user.payload';
import { CurrentUser } from '../auth/current-user.decorator';
import { SelectiveCourseResponseDto } from '../remote-
api/deanoffice/selective-course/dto/types';
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
import { ApiBearerAuth, ApiTags, ApiOperation, ApiBody } from
'@nestjs/swagger';
import { RolesGuard } from '../auth/roles.guard';
import { UseRoles } from '../auth/roles.decorator';
import { Roles as RoleEnum } from '../config/Roles';
import { Response } from 'express';
import { SelectiveCourseProposalDto } from './dto/selective-course-
proposal.dto';
import { MinYearPipe } from './min-year.pipe';
import { ApiResponse } from '@nestjs/swagger';
import { SubmissionStatusResponseDto } from './dto/submission-status-
response.dto';
@ApiTags('Selective Courses')
@UseGuards(JwtAuthGuard)
@ApiBearerAuth('bearer')
@Controller('selective-courses')
export class SelectiveCoursesController {
constructor(private readonly selectiveCoursesService:
SelectiveCoursesService) {}
@Get()
@ApiOperation({ summary: 'Отримати активні курси' })
async getActive(@CurrentUser() user: UserPayload):
Promise<SelectiveCourseResponseDto> {
return
this.selectiveCoursesService.getActiveByExternalId(user.externalId);
}
@Get('department-years')
@ApiOperation({ summary: 'Отримати унікальні роки історії для кафедри
користувача' })
112
482.ЧДТУ 262255 12 01 8
async getHistoryYears(@CurrentUser() user: UserPayload) {
return this.selectiveCoursesService.getHistoryYears(user.externalId);
}
@Get('department-history')
@ApiOperation({ summary: 'Отримати історію за навчальний рік для кафедри'
})
async getHistory(@Query('studyYear', ParseIntPipe, MinYearPipe) studyYear:
number, @CurrentUser() user: UserPayload) {
return this.selectiveCoursesService.getHistoryByYear(studyYear,
user.externalId);
}
@Get('proposals-submission-status')
@ApiOperation({ summary: 'Перевірити чи відкритий період подання
пропозицій вибіркових курсів' })
@ApiResponse({ status: 200, type: SubmissionStatusResponseDto })
async getProposalsSubmissionStatus(): Promise<SubmissionStatusResponseDto>
{
return this.selectiveCoursesService.getProposalsSubmissionStatus();
}
@Get('proposals')
@ApiOperation({ summary: 'Отримати чернетки за навчальний рік для кафедри'
})
async getProposals(@Query('studyYear', ParseIntPipe, MinYearPipe)
studyYear: number, @CurrentUser() user: UserPayload) {
return this.selectiveCoursesService.getProposals(studyYear,
user.externalId);
}
@Get('hours-and-credits')
@ApiOperation({ summary: 'Отримати нормативи годин та кредитів для
вибіркових дисциплін' })
async getSelectiveCourseHoursAndCredits() {
return
this.selectiveCoursesService.getSelectiveCourseHoursAndCredits();
}
@Post('proposals')
@UseGuards(RolesGuard)
@UseRoles(RoleEnum.HEAD_OF_DEPARTMENT,
RoleEnum.RESPONSIBLE_FOR_SELECTIVE_COURSES)
@ApiOperation({ summary: 'Зберегти масив чернеток' })
@ApiBody({ type: [SelectiveCourseProposalDto] })
async saveProposals(
@Body(new ParseArrayPipe({ items: SelectiveCourseProposalDto }))
proposals: SelectiveCourseProposalDto[],
@CurrentUser() user: UserPayload
) {
return this.selectiveCoursesService.saveProposals(user.externalId,
proposals);
}
@Delete('proposals/:id')
@UseGuards(RolesGuard)
@UseRoles(RoleEnum.HEAD_OF_DEPARTMENT,
RoleEnum.RESPONSIBLE_FOR_SELECTIVE_COURSES)
@ApiOperation({ summary: 'Видалити чернетку' })
async deleteProposal(@Param('id') id: number) {
return this.selectiveCoursesService.deleteProposal(id);
}
@Get('proposals/export')
@ApiOperation({ summary: 'Завантажити каталог чернеток' })
113
482.ЧДТУ 262255 12 01 9
async exportDocument(
@Query('studyYear', ParseIntPipe, MinYearPipe) studyYear: number,
@CurrentUser() user: UserPayload,
@Res() res: Response
) {
const fileBuffer = await
this.selectiveCoursesService.exportDocument(studyYear, user.externalId);
res.set({
'Content-Type': 'application/vnd.openxmlformats-
officedocument.wordprocessingml.document',
'Content-Disposition': `attachment;
filename="catalog_${studyYear}.docx"`,
});
res.send(Buffer.from(fileBuffer));
}
}
В.2.2 Сервіс selective-courses.service.ts
import { Injectable } from '@nestjs/common';
import { RemoteSelectiveCourseRepository } from '../remote-
api/deanoffice/selective-course/remote-selective-course.repository';
import { SelectiveCourseProposalDto } from './dto/selective-course-
proposal.dto';
import { SubmissionStatusResponseDto } from './dto/submission-status-
response.dto';
@Injectable()
export class SelectiveCoursesService {
constructor(
private readonly remoteSelectiveCourseRepo:
RemoteSelectiveCourseRepository,
) {}
async getActiveByExternalId(externalId: number) {
return this.remoteSelectiveCourseRepo.getActiveByUserId(externalId);
}
async getHistoryYears(teacherId: number) {
return this.remoteSelectiveCourseRepo.getHistoryYears(teacherId);
}
async getHistoryByYear(studyYear: number, teacherId: number) {
const history = await
this.remoteSelectiveCourseRepo.getHistoryByYear(studyYear, teacherId);
return this.sortCourses(history);
}
async getProposals(studyYear: number, teacherId: number) {
const proposals = await
this.remoteSelectiveCourseRepo.getProposalsByStudyYear(studyYear, teacherId);
return this.sortCourses(proposals);
}
async getSelectiveCourseHoursAndCredits() {
return this.remoteSelectiveCourseRepo.getSelectiveCourseHoursAndCredits();
}
async deleteProposal(id: number) {
return this.remoteSelectiveCourseRepo.deleteProposal(id);
}
114
482.ЧДТУ 262255 12 01 10
async saveProposals(teacherId: number, dtos: SelectiveCourseProposalDto[]) {
const hoursAndCredits = await
this.remoteSelectiveCourseRepo.getSelectiveCourseHoursAndCredits();
dtos.forEach(dto => {
const degreeId = dto.degree?.id || 1;
const cycle = dto.trainingCycle?.toLowerCase() || 'general';
const degreeKey = degreeId === 1 ? 'bachelor' : degreeId === 3 ?
'master' : 'phd';
const standard = hoursAndCredits[degreeKey]?.[cycle];
if (standard) {
dto.hours = standard.hours;
dto.credits = standard.credits;
}
});
return this.remoteSelectiveCourseRepo.saveProposals(teacherId, dtos);
}
async exportDocument(studyYear: number, teacherId: number) {
return this.remoteSelectiveCourseRepo.exportProposalsDocument(studyYear,
teacherId);
}
async getProposalsSubmissionStatus(): Promise<SubmissionStatusResponseDto> {
return this.remoteSelectiveCourseRepo.getProposalsSubmissionStatus();
}
private sortCourses(courses: any[]) {
return courses.sort((a, b) => {
const degreeA = a.degree?.name || '';
const degreeB = b.degree?.name || '';
if (degreeA !== degreeB) {
return degreeA.localeCompare(degreeB);
}
const semA = a.course?.semester || a.semester || 0;
const semB = b.course?.semester || b.semester || 0;
if (semA !== semB) {
return semA - semB;
}
const nameA = a.course?.courseName?.name || a.proposedCourseName ||
'';
const nameB = b.course?.courseName?.name || b.proposedCourseName ||
'';
return nameA.localeCompare(nameB);
});
}
}
В.2.3 RemoteSelectiveCourseRepository.ts
import { Injectable } from '@nestjs/common';
import { DeanofficeJwtHttpService } from '../../../http-request/jwt-
http.service';
import { SelectiveCourseResponseDto } from './dto/types';
import { SubmissionStatusResponseDto } from '../../../selective-
course/dto/submission-status-response.dto';
@Injectable()
export class RemoteSelectiveCourseRepository {
115
482.ЧДТУ 262255 12 01 11
constructor(private readonly jwtHttpService: DeanofficeJwtHttpService) {}
async getActiveByUserId(userId: number):
Promise<SelectiveCourseResponseDto> {
return this.jwtHttpService.get<SelectiveCourseResponseDto>(
`/selective-courses/teacher/${userId}`,
);
}
async getHistoryYears(teacherId: number): Promise<number[]> {
return this.jwtHttpService.get<number[]>('/selective-courses/years', {
params: { teacherId }
});
}
async getHistoryByYear(studyYear: number, teacherId: number):
Promise<any[]> {
return this.jwtHttpService.get<any[]>('/selective-courses/history', {
params: { studyYear, teacherId }
});
}
async getProposalsByStudyYear(studyYear: number, teacherId: number):
Promise<any[]> {
return this.jwtHttpService.get('/selective-courses-proposals', {
params: { studyYear, teacherId }
});
}
async saveProposals(teacherId: number, proposalsPayload: any[]):
Promise<any[]> {
return this.jwtHttpService.post('/selective-courses-proposals',
proposalsPayload, {
params: { teacherId }
});
}
async deleteProposal(id: number): Promise<void> {
return this.jwtHttpService.delete(`/selective-courses-
proposals/${id}`);
}
async exportProposalsDocument(studyYear: number, teacherId: number):
Promise<any> {
return this.jwtHttpService.get('/selective-courses-proposals/export',
{
params: { studyYear, teacherId },
responseType: 'arraybuffer'
});
}
async getProposalsSubmissionStatus(): Promise<SubmissionStatusResponseDto>
{
return
this.jwtHttpService.get<SubmissionStatusResponseDto>('/proposals-submission-
status');
}
async getSelectiveCourseHoursAndCredits(): Promise<any> {
return this.jwtHttpService.get('/selective-courses/hours-and-
credits');
}
}
116
482.ЧДТУ 262255 12 01 12
В.2.4 Контролер curator-groups.controller.ts
import { Controller, Get, Body, Patch, HttpCode, Query } from
'@nestjs/common';
import { CuratorGroupsService } from './curator-groups.service';
import { ApiBearerAuth, ApiBody } from '@nestjs/swagger';
import { UseGuards } from '@nestjs/common';
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
import { CurrentUser } from '../auth/current-user.decorator';
import type { UserPayload } from '../auth/payload/user.payload';
import { GroupCuratorUpdateDto } from './dto/group-curator-update.dto';
import { Roles as RoleEnum } from '../config/Roles';
import { UseRoles } from '../auth/roles.decorator';
import { RolesGuard } from '../auth/roles.guard';
@UseGuards(JwtAuthGuard)
@ApiBearerAuth('bearer')
@Controller('student-groups')
export class CuratorGroupsController {
constructor(private readonly curatorGroupsService: CuratorGroupsService)
{}
@Get()
// @UseGuards(RolesGuard)
// @UseRoles(RoleEnum.HEAD_OF_DEPARTMENT,
RoleEnum.RESPONSIBLE_FOR_SELECTIVE_COURSES)
getGroups(@CurrentUser() user: UserPayload) {
return this.curatorGroupsService.getDepartmentGroups(user.externalId);
}
@Get('for-curator')
getCuratorGroups(@CurrentUser() user: UserPayload) {
return this.curatorGroupsService.getCuratorGroups(user.externalId);
}
@Patch()
@HttpCode(200)
@UseGuards(RolesGuard)
@UseRoles(RoleEnum.HEAD_OF_DEPARTMENT,
RoleEnum.RESPONSIBLE_FOR_SELECTIVE_COURSES)
@ApiBody({ type: [GroupCuratorUpdateDto] })
updateGroupCurators(@Body() updates: GroupCuratorUpdateDto[]) {
return this.curatorGroupsService.updateGroupCurators(updates);
}
}
В.2.5 Сервіс curator-groups.service.ts
import { Injectable } from '@nestjs/common';
import { RemoteCuratorGroupRepository } from '../remote-
api/deanoffice/curator-groups/remote-curator-group.repository';
import { plainToInstance } from 'class-transformer';
import { CuratorGroupDto } from '../curator-groups/dto/curator-group.dto';
import { GroupCuratorUpdateDto } from './dto/group-curator-update.dto';
@Injectable()
export class CuratorGroupsService {
constructor(private readonly remoteCuratorGroupRepository:
RemoteCuratorGroupRepository) {}
async getCuratorGroups(curatorId: number) {
const curatorGroups = await
this.remoteCuratorGroupRepository.getCuratorGroups(curatorId);
return plainToInstance(CuratorGroupDto, curatorGroups);
}
117
482.ЧДТУ 262255 12 01 13
async getDepartmentGroups(teacherId: number) {
return
this.remoteCuratorGroupRepository.getDepartmentGroups(teacherId);
}
async updateGroupCurators(updates: GroupCuratorUpdateDto[]) {
return this.remoteCuratorGroupRepository.updateGroupCurators(updates);
}
}
В.2.6 Схема Prisma (schema.prisma)
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id Int @id @default(autoincrement())
username String @unique @db.VarChar(30)
password String @db.VarChar(80)
externalId Int @unique
roles Role[] @relation("UserRoles")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("users")
}
model Role {
id Int @id @default(autoincrement())
name String @unique @db.VarChar(40)
users User[] @relation("UserRoles")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("roles")}
В.3 Клієнтська частина Angular
В.3.1 Компонент create-course.component.ts
import { Component, inject, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { MatDialog, MatDialogModule } from '@angular/material/dialog';
import { MatExpansionModule } from '@angular/material/expansion';
import { MatCardModule } from '@angular/material/card';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { forkJoin } from 'rxjs';
import { CourseFormDialogComponent } from '../course-form-dialog/course-form-
dialog';
import { DictionariesService, SimpleOption, TeacherOption } from
'../../../../shared/services/dictionaries';
import { SelectiveCoursesService } from '../../services/selective-courses';
import { SelectiveCourseWriteDto } from '../../models/selective-course.model';
118
482.ЧДТУ 262255 12 01 14
import { UserService } from '../../../../shared/services/user';
interface HistoryYearGroup {
year: number;
isLoading: boolean;
courses: any[] | null;
}
@Component({
selector: 'app-create-course',
standalone: true,
imports: [
CommonModule, FormsModule, MatExpansionModule, MatDialogModule,
MatCardModule, MatButtonModule, MatIconModule, MatSnackBarModule,
MatProgressSpinnerModule
],
templateUrl: './create-course.html',
styleUrl: './create-course.css'
})
export class CreateCourse implements OnInit {
private dialog = inject(MatDialog);
private dictionariesService = inject(DictionariesService);
private selectiveCoursesService = inject(SelectiveCoursesService);
private snackBar = inject(MatSnackBar);
private userService = inject(UserService);
defaultStudyYear = new Date().getFullYear() + 1;
courseNames: SimpleOption[] = [];
teachers: TeacherOption[] = [];
degrees: SimpleOption[] = [];
departments: SimpleOption[] = [];
proposals: any[] = [];
originalProposals: any[] = [];
historyCourses: HistoryYearGroup[] = [];
hoursAndCreditsSummary = '';
currentDeptId: number | null = null;
ngOnInit() {
this.loadDictionaries();
this.initHistoryYears();
}
private loadDictionaries() {
this.userService.getCurrentUserDepartment().subscribe({
next: (user) => {
this.currentDeptId = user.id;
forkJoin({
courses: this.dictionariesService.getCourseNames(),
teachers: this.dictionariesService.getDepartmentTeachers(),
yearData: this.dictionariesService.getCurrentYear(),
degrees: this.dictionariesService.getDegrees(),
hoursAndCredits:
this.selectiveCoursesService.getSelectiveCourseHoursAndCredits(),
dept: this.dictionariesService.getDepartmentById(this.currentDeptId)
}).subscribe({
next: (data) => {
this.courseNames = data.courses;
this.teachers = data.teachers;
this.degrees = data.degrees;
this.defaultStudyYear = data.yearData.currYear + 1;
this.buildHoursAndCreditsSummary(data.hoursAndCredits);
119
482.ЧДТУ 262255 12 01 15
this.departments = [data.dept];
this.loadProposals(this.defaultStudyYear);
},
error: () => this.showError('Помилка завантаження довідників')
});
},
error: () => this.showError('Помилка завантаження даних користувача')
});
}
private loadProposals(year: number) {
this.selectiveCoursesService.getProposals(year).subscribe({
next: (res) => {
this.proposals = res.map(p => ({
id: p.id,
courseNameId: p.courseName?.id || p.proposedCourseName,
semester: p.semester,
hours: p.hours,
credits: p.credits,
controlTypeId: p.knowledgeControl?.id,
teacherId: p.teacher?.id,
degreeId: p.degree?.id,
departmentId: p.department?.id,
fieldOfKnowledgeId: p.trainingCycle === 'GENERAL' ? null :
(p.fieldsOfKnowledge &&
p.fieldsOfKnowledge.length > 0
? p.fieldsOfKnowledge[0].id
: (p.fieldOfKnowledge?.id || null)),
trainingCycle: p.trainingCycle,
description: p.description,
studyYear: p.studyYear || year
}));
this.originalProposals = this.proposals.map(p => ({ ...p }));
},
error: () => this.showError('Не вдалося завантажити список нових
дисциплін')
});
}
private buildHoursAndCreditsSummary(config: any) {
if (!config || !config.bachelor) {
this.hoursAndCreditsSummary = 'Для блоку загальних дисциплін
бакалаврського рівня — 90 годин (3 кредити), для всіх інших — 120 годин (4
кредити)';
return;
}
const bachGeneralHours = config.bachelor.general?.hours;
const bachGeneralCredits = config.bachelor.general?.credits;
const otherHours = config.bachelor.professional?.hours;
const otherCredits = config.bachelor.professional?.credits;
this.hoursAndCreditsSummary = `Для блоку загальних дисциплін
бакалаврського рівня — ${bachGeneralHours} годин (${bachGeneralCredits}
кредити), для всіх інших — ${otherHours} годин (${otherCredits} кредити)`;
}
private initHistoryYears() {
this.selectiveCoursesService.getHistoryYears().subscribe({
next: (years) => {
this.historyCourses = years.map(year => ({
year: year,
isLoading: false,
courses: null
120
482.ЧДТУ 262255 12 01 16
}));
},
error: () => this.showError('Не вдалося завантажити доступні роки
історії')
});
}
loadCoursesForYear(year: number) {
const historyGroup = this.historyCourses.find(h => h.year === year);
if (!historyGroup || historyGroup.courses !== null ||
historyGroup.isLoading) return;
historyGroup.isLoading = true;
this.selectiveCoursesService.getHistoryByYear(year).subscribe({
next: (courses) => {
const mappedCourses = courses.map(p => ({
id: p.id,
courseNameId: p.course?.courseName?.id,
courseNameStr: p.course?.courseName?.name || p.proposedCourseName ||
'',
semester: p.course?.semester,
hours: p.course?.hours || 120,
credits: p.course?.credits || 4.0,
controlTypeId: p.course?.knowledgeControl?.id || 2,
teacherId: p.teacher?.id,
degreeId: p.degree?.id,
departmentId: p.department?.id,
fieldOfKnowledgeId: p.trainingCycle === 'GENERAL' ? null :
(p.fieldsOfKnowledge &&
p.fieldsOfKnowledge.length > 0
? p.fieldsOfKnowledge[0].id
: (p.fieldOfKnowledge?.id || null)),
trainingCycle: p.trainingCycle,
description: p.description,
studyYear: p.studyYear || year
}));
historyGroup.courses = mappedCourses;
historyGroup.isLoading = false;
},
error: () => {
historyGroup.isLoading = false;
this.showError(`Не вдалося завантажити історію за ${year} рік`);
}
});
}
openDialog(courseData?: any, isCopy = false, index?: number) {
let dataToPass = courseData ? { ...courseData, isCopy } : {};
if (isCopy || !courseData) {
dataToPass.studyYear = this.defaultStudyYear;
}
const deptId = courseData?.departmentId || this.currentDeptId;
if (!deptId) {
this.showError('Кафедра не визначена!');
return;
}
dataToPass.departmentId = deptId;
dataToPass.departmentOptions = this.departments;
121
482.ЧДТУ 262255 12 01 17
const dialogRef = this.dialog.open(CourseFormDialogComponent, {
width: '750px',
disableClose: true,
data: dataToPass,
autoFocus: false
});
dialogRef.afterClosed().subscribe(result => {
if (result) {
const proposalsToCheck = (!isCopy && index !== undefined)
? this.proposals.filter((_, i) => i !== index)
: this.proposals;
const isDuplicate = proposalsToCheck.some(p => {
const existingNameText =
this.getCourseName(p.courseNameId).trim().toLowerCase();
const newNameText =
this.getCourseName(result.courseNameId).trim().toLowerCase();
return (existingNameText === newNameText) && (p.semester ===
result.semester);
});
if (isDuplicate) {
this.showError('Помилка: дисципліна з такою назвою вже існує в цьому
семестрі!');
return;
}
if (isCopy || index === undefined) {
result.id = null;
if (!result.studyYear) {
result.studyYear = this.defaultStudyYear;
}
this.proposals.push(result);
} else {
this.proposals[index] = result;
}
}
});
}
removeProposal(index: number) {
const rowId = this.proposals[index].id;
if (rowId) {
this.selectiveCoursesService.deleteProposal(rowId).subscribe(() => {
this.proposals.splice(index, 1);
this.showSuccess('Дисципліну видалено');
});
} else {
this.proposals.splice(index, 1);
}
}
saveAll() {
if (this.proposals.length === 0) return;
const changedProposals = this.proposals.filter(row => {
if (!row.id) {
console.log('Це нова дисципліна (немає id):', row);
return true;
}
const original = this.originalProposals.find(p => p.id === row.id);
if (!original) return true;
122
482.ЧДТУ 262255 12 01 18
const isChanged = row.courseNameId != original.courseNameId ||
row.semester != original.semester ||
row.hours != original.hours ||
row.credits != original.credits ||
row.teacherId != original.teacherId ||
row.departmentId != original.departmentId ||
row.fieldOfKnowledgeId != original.fieldOfKnowledgeId ||
row.trainingCycle != original.trainingCycle ||
row.description != original.description ||
row.studyYear != original.studyYear ||
row.degreeId != original.degreeId;
return isChanged;
});
if (changedProposals.length === 0) {
this.showWarning('Немає змін для збереження');
return;
}
const payloadForBackend: SelectiveCourseWriteDto[] =
changedProposals.map(row => {
const isNewName = typeof row.courseNameId === 'string';
const payload: any = {
id: row.id,
courseName: isNewName ? null : { id: Number(row.courseNameId) },
proposedCourseName: isNewName ? row.courseNameId : null,
semester: Number(row.semester),
hours: Number(row.hours),
credits: Number(row.credits),
knowledgeControl: { id: Number(row.controlTypeId) },
teacher: row.teacherId ? { id: Number(row.teacherId) } : undefined,
degree: { id: Number(row.degreeId) },
department: { id: Number(row.departmentId) },
trainingCycle: row.trainingCycle,
description: row.description,
studyYear: row.studyYear || this.defaultStudyYear,
};
if (row.fieldOfKnowledgeId && row.trainingCycle !== 'GENERAL') {
payload.fieldOfKnowledge = { id: Number(row.fieldOfKnowledgeId) };
}
return payload;
});
this.selectiveCoursesService.saveProposals(payloadForBackend).subscribe({
next: () => {
this.showSuccess('Дані успішно збережені!');
this.loadProposals(this.defaultStudyYear);
},
error: () => this.showError('Помилка при збереженні')
});
}
getCourseName(idOrName: number | string): string {
if (typeof idOrName === 'string') {
return idOrName;
}
return this.courseNames.find(c => c.id === idOrName)?.name || 'Невідома
дисципліна';
}
123
482.ЧДТУ 262255 12 01 19
getTeacherName(id: number): string {
return this.teachers.find(t => t.id === id)?.fullName || 'Не призначено';
}
getDegreeName(id: number): string {
return this.degrees.find(d => d.id === id)?.name || 'Невідомо';
}
private showSuccess(msg: string) {
this.snackBar.open(msg, 'OK', { duration: 3000, panelClass: ['success-
snackbar'] });
}
private showError(msg: string) {
this.snackBar.open(msg, 'Закрити', { duration: 5000, panelClass: ['error-
snackbar'] });
}
private showWarning(msg: string) {
this.snackBar.open(msg, 'OK', { duration: 3000, panelClass: ['warning-
snackbar'] });
}
downloadDocument() {
this.selectiveCoursesService.exportCatalogDocument(this.defaultStudyYear).subs
cribe({
next: (blob: Blob) => {
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `Каталог_вибіркових_${this.defaultStudyYear}.docx`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
},
error: () => this.showError('Помилка при завантаженні документа.
Перевірте консоль.')
});
}
}
В.3.2 Компонент course-form-dialog.component.ts
import { Component, Inject, OnInit, inject } from '@angular/core';
import { CommonModule, AsyncPipe } from '@angular/common';
import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from
'@angular/forms';
import { MatDialogRef, MAT_DIALOG_DATA, MatDialogModule } from
'@angular/material/dialog';
import { MatButtonModule } from '@angular/material/button';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { MatSelectModule } from '@angular/material/select';
import { MatAutocompleteModule } from '@angular/material/autocomplete';
import { Observable, forkJoin } from 'rxjs';
import { map, debounceTime, startWith } from 'rxjs/operators';
import { DictionariesService, SimpleOption, TeacherOption } from
'../../../../shared/services/dictionaries';
@Component({
124
482.ЧДТУ 262255 12 01 20
selector: 'app-course-form-dialog',
standalone: true,
imports: [
CommonModule, ReactiveFormsModule, MatDialogModule, MatButtonModule,
MatFormFieldModule, MatInputModule, MatSelectModule,
MatAutocompleteModule, AsyncPipe
],
templateUrl: './course-form-dialog.html',
styleUrl: './course-form-dialog.css'
})
export class CourseFormDialogComponent implements OnInit {
private fb = inject(FormBuilder);
private dictionariesService = inject(DictionariesService);
courseForm!: FormGroup;
courseNames: SimpleOption[] = [];
teachers: TeacherOption[] = [];
degrees: SimpleOption[] = [];
departments: SimpleOption[] = [];
fieldsOfKnowledge: SimpleOption[] = [];
cycles = [
{ value: 'GENERAL', viewValue: 'Загальна (General)' },
{ value: 'PROFESSIONAL', viewValue: 'Професійна (Professional)' }
];
semesters = [1, 2, 3, 4, 5, 6, 7, 8];
formattedYear: string = '';
filteredCourses!: Observable<SimpleOption[]>;
constructor(
public dialogRef: MatDialogRef<CourseFormDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: any
) {}
ngOnInit() {
this.initForm();
this.setupListeners();
this.loadDictionaries();
}
private initForm() {
const defaultYear = this.data?.studyYear || (new Date().getFullYear() +
1);
this.formattedYear = `${defaultYear}-${defaultYear + 1}`;
const initialCycle = this.data?.trainingCycle || 'GENERAL';
const initialDeptId = this.data?.departmentId || null;
this.courseForm = this.fb.group({
id: [this.data?.id || null],
studyYear: [{value: defaultYear, disabled: true}, Validators.required],
courseNameId: [this.data?.courseNameId || this.data?.proposedCourseName
|| '', Validators.required],
semester: [this.data?.semester || '', Validators.required],
controlTypeId: [{ value: 2, disabled: true }, Validators.required],
teacherId: [this.data?.teacherId || '', Validators.required],
degreeId: [this.data?.degreeId || 1, Validators.required],
departmentId: [{value: initialDeptId, disabled: true},
Validators.required],
fieldOfKnowledgeId: [
{
value: initialCycle === 'GENERAL' ? null :
(this.data?.fieldOfKnowledgeId || null),
disabled: initialCycle === 'GENERAL'
125
482.ЧДТУ 262255 12 01 21
},
Validators.required
],
trainingCycle: [this.data?.trainingCycle || 'GENERAL',
Validators.required],
description: [this.data?.description || '', Validators.required],
});
}
private loadDictionaries() {
forkJoin({
courses: this.dictionariesService.getCourseNames(),
teachers: this.dictionariesService.getDepartmentTeachers(),
degrees: this.dictionariesService.getDegrees()
}).subscribe(data => {
this.courseNames = data.courses;
this.teachers = data.teachers;
this.degrees = data.degrees.filter(degree => degree.name !==
'Спеціаліст');
this.departments = this.data?.departmentOptions || [];
this.setupFilters();
if (this.data && (this.data.id || this.data.isCopy ||
this.data.teacherId || this.data.proposedCourseName)) {
const teacherExists = this.teachers.some(t => t.id ===
this.data.teacherId);
this.courseForm.patchValue({
courseNameId: this.data.courseNameId ||
this.data.proposedCourseName,
teacherId: teacherExists ? this.data.teacherId : ''
});
}
if (this.courseForm.get('departmentId')?.value) {
this.loadFieldsOfKnowledge(this.courseForm.get('departmentId')?.value);
}
});
}
private setupFilters() {
this.filteredCourses =
this.courseForm.get('courseNameId')!.valueChanges.pipe(
debounceTime(300),
startWith(this.courseForm.get('courseNameId')!.value || ''),
map(val => this.filterCourses(val))
);
}
private setupListeners() {
this.courseForm.get('departmentId')?.valueChanges.subscribe(deptId => {
this.loadFieldsOfKnowledge(deptId);
});
this.courseForm.get('trainingCycle')!.valueChanges.subscribe(cycle => {
const fokCtrl = this.courseForm.get('fieldOfKnowledgeId');
if (cycle === 'GENERAL') {
fokCtrl!.setValue(null);
fokCtrl!.disable();
} else {
fokCtrl!.enable();
}
});
126
482.ЧДТУ 262255 12 01 22
}
private loadFieldsOfKnowledge(deptId: number) {
if (deptId) {
this.dictionariesService.getFieldsOfKnowledgeByDepartment(deptId).subscribe(fi
elds => {
this.fieldsOfKnowledge = fields;
const currentCycle = this.courseForm.get('trainingCycle')?.value;
const currentFieldId =
this.courseForm.get('fieldOfKnowledgeId')?.value;
if (currentCycle !== 'GENERAL') {
if (fields.length === 1) {
this.courseForm.patchValue({ fieldOfKnowledgeId: fields[0].id }, {
emitEvent: false });
} else if (!fields.some(f => f.id === currentFieldId)) {
this.courseForm.patchValue({ fieldOfKnowledgeId: null }, {
emitEvent: false });
}
}
});
} else {
this.fieldsOfKnowledge = [];
this.courseForm.patchValue({ fieldOfKnowledgeId: null }, { emitEvent:
false });
}
}
private filterCourses(val: any): SimpleOption[] {
if (!val) return this.courseNames.slice();
const searchStr = typeof val === 'string' ? val :
this.getCourseNameById(val);
return this.courseNames.filter(c =>
c.name.toLowerCase().includes(searchStr.toLowerCase()));
}
getCourseNameById = (value: any): string => {
if (!value) return '';
if (typeof value === 'string') return value;
return this.courseNames.find(c => c.id === value)?.name || '';
};
getDepartmentNameById = (value: any): string => {
if (!value) return '';
if (typeof value === 'string') return value;
return this.departments.find(d => d.id === value)?.name || '';
};
getDepartmentName(): string {
if (this.departments && this.departments.length > 0) {
return this.departments[0].name;
}
return 'Не визначено';
}
onSubmit() {
if (this.courseForm.valid) {
const formValue = this.courseForm.getRawValue();
this.dialogRef.close(formValue);
}
}
}
127
482.ЧДТУ 262255 12 01 23
В.3.3 Компонент assign-curators.component.ts
import { Component, OnInit, inject } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button';
import { MatSelectModule } from '@angular/material/select';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar';
import { forkJoin } from 'rxjs';
import { finalize } from 'rxjs/operators';
import { GroupService } from '../../services/group';
import { DictionariesService, TeacherOption } from
'../../../../shared/services/dictionaries';
import { StudentGroup } from '../../models/student-group';
@Component({
selector: 'app-group-curators',
standalone: true,
imports: [
CommonModule,
FormsModule,
MatButtonModule,
MatSelectModule,
MatFormFieldModule,
MatProgressSpinnerModule,
MatSnackBarModule
],
templateUrl: './assign-curators.html',
styleUrls: ['./assign-curators.css']
})
export class GroupCuratorsComponent implements OnInit {
groups: StudentGroup[] = [];
teachers: TeacherOption[] = [];
changes: Map<number, number> = new Map();
isLoading = false;
private groupService = inject(GroupService);
private dictionariesService = inject(DictionariesService);
private snackBar = inject(MatSnackBar);
ngOnInit(): void {
this.loadData();
}
loadData() {
this.isLoading = true;
forkJoin({
groups: this.groupService.getGroups(),
teachers: this.dictionariesService.getDepartmentTeachers()
})
.pipe(
finalize(() => this.isLoading = false)
)
.subscribe({
next: ({ groups, teachers }) => {
this.groups = groups;
this.teachers = teachers.sort((a, b) =>
(a.fullName || '').localeCompare(b.fullName || '')
);
},
error: (err) => {
128
482.ЧДТУ 262255 12 01 24
console.error('Помилка завантаження:', err);
this.showError('Не вдалося завантажити дані');
}
});
}
onCuratorChange(group: StudentGroup, newCuratorId: number) {
this.changes.set(group.id, newCuratorId);
}
save() {
if (this.changes.size === 0) return;
this.isLoading = true;
const updates: { groupId: number, curatorId: number }[] = [];
this.changes.forEach((curatorId, groupId) => {
updates.push({ groupId, curatorId });
});
this.groupService.updateGroupCurators(updates)
.pipe(
finalize(() => this.isLoading = false)
)
.subscribe({
next: () => {
this.showSuccess('Зміни успішно збережено!');
this.changes.clear();
this.loadData();
},
error: (err) => {
console.error(err);
this.showError('Помилка при збереженні змін');
}
});
}
private showSuccess(message: string) {
this.snackBar.open(message, 'OK', {
duration: 3000,
horizontalPosition: 'right',
verticalPosition: 'top',
panelClass: ['success-snackbar']
});
}
private showError(message: string) {
this.snackBar.open(message, 'Закрити', {
duration: 5000,
horizontalPosition: 'right',
verticalPosition: 'top',
panelClass: ['error-snackbar']
});
}
}
В.3.4 сервіс dictionary.ts
import { Injectable, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { environment } from '../../../environments/environment';
export interface SimpleOption { id: number; name: string; }
129
482.ЧДТУ 262255 12 01 25
export interface TeacherOption { id: number; fullName: string; departmentId?:
number; }
export interface FieldOption { id: number; code: string; name: string; }
@Injectable({
providedIn: 'root'
})
export class DictionariesService {
private http = inject(HttpClient);
// Адреса бекенду
private apiUrl = `${environment.apiUrl}/dictionaries`;
getCourseNames(): Observable<SimpleOption[]> {
return this.http.get<SimpleOption[]>(`${this.apiUrl}/course-names`);
}
getDepartmentTeachers(): Observable<TeacherOption[]> {
return this.http.get<TeacherOption[]>(`${this.apiUrl}/department-teachers`);
}
getDepartments(): Observable<SimpleOption[]> {
return this.http.get<SimpleOption[]>(`${this.apiUrl}/departments`);
}
getDepartmentById(departmentId: number): Observable<SimpleOption> {
return
this.http.get<SimpleOption>(`${this.apiUrl}/departments/${departmentId}`);
}
getDegrees(): Observable<SimpleOption[]> {
return this.http.get<SimpleOption[]>(`${this.apiUrl}/degrees`);
}
getFieldsOfKnowledge(): Observable<FieldOption[]> {
return this.http.get<FieldOption[]>(`${this.apiUrl}/fields-of-knowledge`);
}
getCurrentYear(): Observable<{ currYear: number }> {
return this.http.get<{ currYear: number }>(`${this.apiUrl}/current-year`);
}
getFieldsOfKnowledgeByDepartment(departmentId: number):
Observable<SimpleOption[]> {
return this.http.get<SimpleOption[]>(`${this.apiUrl}/fields-of-
knowledge/department/${departmentId}`);
}
}
130
ДОДАТОК В
«Інформаційна система університету. Модуль інтеграції кафедри з іншими
підрозділами»
Інструкція користувачеві
482.ЧДТУ 26.2255.34.01
Листів 7
Розробник ______________ Петров А.О.
(підпис) (прізвище та ініціали)
Черкаси 2026
482.ЧДТУ 26 2255 34 01 2
В.1 Загальні відомості
Програмний модуль інтеграції кафедри є складовою частиною ІАСПОД
Черкаського державного технологічного університету та призначений для
автоматизації адміністративних процесів кафедри. Інструкція описує роботу з
трьома функціональними модулями системи: подання пропозицій вибіркових
дисциплін, призначення кураторів академічним групам та ведення тем
кваліфікаційних робіт студентів.
Доступ до системи мають користувачі з ролями завідувача кафедри та
відповідального за вибіркові дисципліни. Перелік доступних модулів залежить
від призначеної користувачеві ролі.
Системні вимоги для роботи з клієнтською частиною:
– сучасний веб-браузер (Google Chrome рекомендовано);
– стабільне підключення до мережі університету;
– обліковий запис у підсистемі викладача з відповідними ролями.
В.2 Вхід до системи
Для початку роботи необхідно відкрити у браузері адресу клієнтського
застосунку підсистеми викладача. Відкриється сторінка авторизації, наведена на
рисунку В.1.
Рисунок В.1 – Сторінка входу до системи
132
482.ЧДТУ 26 2255 34 01 3
Послідовність дій для входу:
1 У полі «Логін» ввести логін, виданий адміністратором системи;
2 У полі «Пароль» ввести пароль;
3 Натиснути кнопку «Увійти».
Кнопка «Увійти» залишається неактивною доти, доки не заповнені обидва
поля. У разі введення некоректних даних система виведе повідомлення про
помилку авторизації. Після успішного входу користувач автоматично
перенаправляється на головну сторінку, а в бічному меню зліва відображаються
доступні відповідно до його ролі модулі.
В.3 Робота з модулем вибіркових дисциплін
Для переходу до модуля необхідно обрати пункт «Подати вибіркові» у
бічному меню. Відкриється головна сторінка модуля, наведена на рисунку В.2.
Рисунок В.2 – Головна сторінка модуля вибіркових дисциплін
На сторінці відображається історія раніше поданих пропозицій кафедри,
згрупована за навчальними роками. Біля кожного року вказано кількість
затверджених дисциплін. Для перегляду пропозицій конкретного року слід
натиснути на відповідний рядок — секція розкриється та покаже перелік
дисциплін.
133
482.ЧДТУ 26 2255 34 01 4
В.3.1 Копіювання дисципліни з попереднього року
Якщо потрібна дисципліна вже подавалася в попередні роки, її можна
швидко скопіювати. Для цього:
1 Розкрити секцію потрібного року.
2 Натиснути кнопку «+» біля обраної дисципліни.
3 У діалоговому вікні (рисунок В.3) перевірити та за потреби скорегувати
дані: назву, семестр, викладача, опис.
4 Натиснути кнопку «Додати копію».
Рисунок В.3 – Діалогове вікно копіювання дисципліни
Поля «Навчальний рік», «Години», «Кредити», «Контроль» та «Кафедра»
заповнюються автоматично та недоступні для редагування, оскільки
визначаються нормативами університету. Поле «Назва дисципліни» підтримує
автодоповнення з довідника наявних дисциплін; за потреби можна ввести нову
назву.
В.3.2 Створення нової пропозиції
Для подання дисципліни, якої немає в попередніх роках:
1 Натиснути кнопку «Подати нову вибіркову».
2 У діалоговому вікні заповнити всі обов'язкові поля.
3 Натиснути кнопку «Додати».
134
482.ЧДТУ 26 2255 34 01 5
В.3.3 Збереження та генерація каталогу
Усі додані дисципліни відображаються в нижній частині сторінки в секції
«Нові дисципліни» у вигляді карток (рисунок В.4). Кожну картку можна
відредагувати (іконка олівця) або видалити (іконка кошика).
Рисунок В.4 – Секція «Нові дисципліни»
Для збереження пропозицій на сервері слід натиснути кнопку «Зберегти
нові дисципліни». Для завантаження готового документа каталогу у форматі
Microsoft Word слід натиснути кнопку «Завантажити каталог» — файл
автоматично завантажиться на комп'ютер користувача.
Важливо: редагування та подання пропозицій можливі лише протягом
відкритого періоду подачі. Поза межами цього періоду елементи керування
блокуються, проте раніше подані пропозиції залишаються доступними для
перегляду.
В.4 Робота з модулем кураторів
Для переходу до модуля необхідно обрати пункт «Куратори» у бічному
меню. Відкриється сторінка призначення кураторів, наведена на рисунку В.5.
135
482.ЧДТУ 26 2255 34 01 6
Рисунок В.5 – Сторінка призначення кураторів
На сторінці відображається таблиця з академічними групами кафедри. Для
кожної групи передбачено поле вибору куратора. Послідовність призначення
куратора:
1 Натиснути на поле «Куратор» навпроти потрібної групи;
2 Зі списку обрати викладача (у списку відображаються лише викладачі
поточної кафедри);
3 За потреби повторити для інших груп;
4 Натиснути кнопку «Зберегти зміни».
Кнопка «Зберегти зміни» стає активною лише після внесення хоча б однієї
зміни. Усі зміни зберігаються одночасно одним запитом. Після успішного
збереження система виведе підтверджувальне повідомлення.
В.5 Робота з модулем тем кваліфікаційних робіт
Для переходу до модуля необхідно обрати пункт «Теми дипломних робіт»
у бічному меню. Відкриється сторінка ведення тем, наведена на рисунку В.6.
136
482.ЧДТУ 26 2255 34 01 7
Рисунок В.6 – Сторінка тем кваліфікаційних робіт
Послідовність роботи:
1 У випадаючому списку «Оберіть групу» обрати потрібну академічну
групу.
2 Дочекатися автоматичного завантаження таблиці студентів групи.
3 Для кожного студента заповнити поля «Тема (UA)» та «Тема (EN)».
4 У полі «Керівник» обрати наукового керівника зі списку викладачів
кафедри.
5 Натиснути кнопку «Зберегти всі».
Заповнювати теми можна як для всіх студентів групи одразу, так і для
окремих. Усі введені теми зберігаються одночасно одним запитом.
В.6 Завершення роботи
Для безпечного завершення роботи з системою необхідно натиснути
кнопку виходу, розташовану у верхньому правому куті інтерфейсу. Після виходу
сесія користувача завершується, і для повторного доступу до системи потрібно
буде знову пройти авторизацію.
У разі тривалої бездіяльності сесія завершується автоматично — при цьому
система перенаправить користувача на сторінку входу, де потрібно буде
авторизуватися повторно.
137
ДОДАТОК Г
«Інформаційна система університету. Модуль інтеграції кафедри з іншими
підрозділами»
Графічні матеріали
482.ЧДТУ 26.2255.90.01
Листів 15
Розробник ______________ Петров А.О.
(підпис) (прізвище та ініціали)
Черкаси 2026
482.ЧДТУ 26. 2255 90 01 2
Рисунок Г.1 – Титульний слайд
Рисунок Г.2 – Мета та завдання
139
482.ЧДТУ 26. 2255 90 01 3
Рисунок Г.3 – Аналіз предметної області
Рисунок Г.4 – Актуальність роботи
140
482.ЧДТУ 26. 2255 90 01 4
Рисунок Г.5 – Аналіз існуючих програмних засобів.
Рисунок Г.6 – Аналіз способів виріщення задачі
141
482.ЧДТУ 26. 2255 90 01 5
Рисунок Г.7 Постановка задачі
Рисунок Г.8 – Методика проектування
142
482.ЧДТУ 26. 2255 90 01 6
Рисунок Г.9 – Результати аналізу вимог
Рисунок Г.10 – Архітектура системи
143
482.ЧДТУ 26. 2255 90 01 7
Рисунок Г.11 – Вимоги до системи
Рисунок Г.12 – Діаграма прецендентів
144
482.ЧДТУ 26. 2255 90 01 8
Рисунок Г.13 – Логічна структура
Рисунок Г.14 – Діаграма пакетів
145
482.ЧДТУ 26. 2255 90 01 9
Рисунок Г.15 -Поведінкове моделювання
Рисунок Г.16 – Поведінкове моделювання
146
482.ЧДТУ 26. 2255 90 01 10
Рисунки Г.17 – Технологічний стек
Рисунки Г.18 – Структурна та функціональна схема
147
482.ЧДТУ 26. 2255 90 01 11
Рисунки Г.19 – Логічна схема системи
Рисунки Г.20 – Розробка бази даних
148
482.ЧДТУ 26. 2255 90 01 12
Рисунки Г.21 – Інтеофейс користувача
Рисунки Г.22 – Модуле та інтеграційне тестування
149
482.ЧДТУ 26. 2255 90 01 13
Рисунки Г.23 – Системне та приймальне тестування
Рисунки Г.24 – Приклади впровадження(1)
150
482.ЧДТУ 26. 2255 90 01 14
Рисунки Г.25 – Приклади впроваждження
Рисунки Г.26 – Висновки
151
482.ЧДТУ 26. 2255 90 01 15
Рисунки Г.27 – Подяка
Рисунки Г.28 – Фінальний слайд
152