Please use this identifier to cite or link to this item:
https://er.chdtu.edu.ua/handle/ChSTU/8218| Title: | Технологічні особливості розробки програмного забезпечення комунікативних платформ |
| Authors: | Немченко, Вадим В'ячеславович Золотоверхий, Андрій Ярославович |
| Keywords: | РОЗРОБКА ПРОГРАМНОГО ЗАБЕЗПЕЧЕННЯ;КОМУНІКАТИВНА ПЛАТФОРМА;СТЕК;MERN;MongoDB;EXPRESS.JS;REACT.JS;NODE.JS;ПРОДУКТИВНІСТЬ;МАСШТАБОВАНІСТЬ;SOFTWARE DEVELOPMENT;COMMUNICATION PLATFORM;MERN STACK;MongoDB;EXPRESS.JS;REACT.JS;NODE.JS;PERFORMANCE;SCALABILITY |
| Issue Date: | 9-Dec-2024 |
| Abstract: | АНОТАЦІЯ
Золотоверхий Андрій Ярославович студент спеціальності 121 «Інженерія програмного забезпечення». Представлено кваліфікаційну роботу магістра на тему – «Технологічні особливості розробки програмного забезпечення комунікативних платформ» в Черкаському державному технологічному університеті у місті Черкаси у 2024 році.
Кваліфікаційна робота магістра присвячена дослідженню технологічних особливостей розробки комунікативних платформ із використанням сучасного стеку MERN, що включає MongoDB, Express.js, React.js і Node.js. У роботі обґрунтовано вибір технологій, проаналізовано існуючі рішення у цій сфері, розроблено архітектуру системи та функціональні модулі, а також виконано тестування розробленого програмного забезпечення. Результатом дослідження є реалізація функціональної комунікативної платформи, яка відповідає сучасним вимогам продуктивності, безпеки, зручності використання та масштабованості. Проведені експериментальні дослідження підтвердили ефективність використаного стеку технологій та відповідність функціоналу платформі заявленим вимогам. Розроблене програмне забезпечення впроваджено у тестове середовище, що демонструє його готовність до реального використання. ANNOTATION Andrii Zolotoverkyi, a student of the 121 "Software Engineering" specialty, presents a master's qualification work on the topic "Technological Aspects of Software Development for Communication Platforms" at Cherkasy State Technological University in Cherkasy in 2024. The master's qualification work is dedicated to researching the technological aspects of developing communication platforms using the modern MERN stack, which includes MongoDB, Express.js, React.js, and Node.js. The study substantiates the choice of technologies, analyzes existing solutions in this field, designs the system architecture and functional modules, and conducts testing of the developed software. The research outcome is the implementation of a functional communication platform that meets modern requirements for performance, security, usability, and scalability. Experimental studies confirmed the efficiency of the chosen technology stack and the compliance of the platform's functionality with the stated requirements. The developed software has been implemented in a test environment, demonstrating its readiness for real-world application. |
| URI: | https://er.chdtu.edu.ua/handle/ChSTU/8218 |
| Appears in Collections: | 121 Інженерія програмного забезпечення (Інженерія програмного забезпечення) |
Files in This Item:
| File | Description | Size | Format | |
|---|---|---|---|---|
| Кваліфікаційна робота магістра Золлтоверхий Андрій Ярославович.pdf Restricted Access | 6.65 MB | Adobe PDF | View/Open Request a copy |
Items in DSpace are protected by copyright, with all rights reserved, unless otherwise indicated.
Extracted text
МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ
ЧЕРКАСЬКИЙ ДЕРЖАВНИЙ ТЕХНОЛОГІЧНИЙ УНІВЕРСИТЕТ
Факультет інформаційних технологій і систем
Кафедра програмного забезпечення автоматизованих систем
ПОЯСНЮВАЛЬНА ЗАПИСКА
до кваліфікаційної роботи
«магістра»
освітній рівень
на тему: Технологічні особливості розробки програмного забезпечення
комунікативних платформ
Магістранта Золотоверхий А. Я.
(прізвище та ініціали)
Керівник Немченко В. В.
(прізвище та ініціали)
Рецензент Ключка К. М.
(прізвище та ініціали)
Черкаси 2024
Черкаський державний технологічний університет
повне найменування вищого навчального закладу
Факультет інформаційних технологій і систем
Кафедра програмного забезпечення автоматизованих систем
Освітній рівень магістр
Спеціальність 121 «Інженерія програмного забезпечення»
Освітня програма Інженерія програмного забезпечення
ЗАТВЕРДЖУЮ
Зав. кафедри ПЗАС, професор
С. Голуб
«___» _______________ 2024 року
З А В Д А Н Н Я
НА КВАЛІФІКАЦІЙНУ РОБОТУ СТУДЕНТУ
Золотоверхий Андрій Яросалвович
(прізвище, ім’я, по батькові)
1. Тему проекту (роботи) Технологічні особливості розробки програмного забезпечення
комунікативних платформ
Керівник проекту (роботи) Немченко Вадим В'ячеславович к.т.н. доцент
(прізвище, ім’я , по батькові, науковий ступінь, вчене звання)
Затверджені наказом Черкаського державного технологічного університету від «07 жовтня»
2024 року № 299/04
2.Строк подання студентом проекту (роботи) 09.12.2024
3. Вхідні дані до проекту (роботи) 1) Платформа x86-64, 2) Мова програмування JavaScript
4. Зміст розрахунково-пояснювальної записки (перелік питань, які потрібно розробити)
Розділ 1. Існуючі методи та засоби розв’язання поставлених завдань
Розділ 2. Теоретичні та експериментальні дослідження
Розділ 3. Впровадження результатів дослідження у практику проектування програмного
забезпечення інформаційних систем
Розділ 4. Розробка та тестування програмного забезпечення
Висновки;
Список використаних джерел;
Додатки А, Додатки Б, Додатки В.
5. Перелік графічного матеріалу (з точним зазначенням обов’язкових робіт проекту);
Додатки Г - Графічний матеріал.
6. Консультанти розділів роботи
Прізвище, ініціали та посади Підпис, дата
Розділ
консультанта Завдання видав Завдання прийняв
1
2
3
4
7. Дата видачі завдання вересень 2024 р.
КАЛЕНДАРНИЙ ПЛАН
Строк виконання
№ етапів
Назва етапів випускної роботи Примітки
п/п кваліфікаційної
роботи
1 Постановка задачі 09.09.2024 виконано
2 Підготовка завдання 12.09.2024 виконано
3 Погодження завдання 18.09.2024 виконано
4 Затвердження завдання 27.09.2024 виконано
Основна стадія
1 Підбір матеріалів 30.09.2024 виконано
2 Аналіз шляхів вирішення поставленої задачі 03.10.2024 виконано
3 Розрахунок основних параметрів роботи 08.10.2024 виконано
4 Вибір кінцевого варіанту проектного рішення 17.10.2024 виконано
5 Оформлення первісної редакції роботи 23.10.2024 виконано
Заключна стадія
1 Узгодження прийнятих проектних рішень з 08.11.2024 виконано
керівником
2 Оформлення пояснювальної записки роботи в 28.11.2024 виконано
кінцевій редакції
3 Попередній захист роботи 05.12.2024 виконано
4 Затвердження роботи 06.12.2024 виконано
5 Рецензування роботи 09.12.2024 виконано
6 Захист роботи 12.12.204
Студент ___________ Золотоверхий А.Я.
(підпис) (прізвище та ініціали)
Керівник роботи ______________ Немченко В.В.
(підпис) (прізвище та ініціали)
АНОТАЦІЯ
Золотоверхий Андрій Ярославович студент спеціальності 121 «Інженерія
програмного забезпечення». Представлено кваліфікаційну роботу магістра на
тему – «Технологічні особливості розробки програмного забезпечення
комунікативних платформ» в Черкаському державному технологічному
університеті у місті Черкаси у 2024 році.
Кваліфікаційна робота магістра присвячена дослідженню технологічних
особливостей розробки комунікативних платформ із використанням сучасного
стеку MERN, що включає MongoDB, Express.js, React.js і Node.js. У роботі
обґрунтовано вибір технологій, проаналізовано існуючі рішення у цій сфері,
розроблено архітектуру системи та функціональні модулі, а також виконано
тестування розробленого програмного забезпечення. Результатом дослідження
є реалізація функціональної комунікативної платформи, яка відповідає
сучасним вимогам продуктивності, безпеки, зручності використання та
масштабованості. Проведені експериментальні дослідження підтвердили
ефективність використаного стеку технологій та відповідність функціоналу
платформі заявленим вимогам. Розроблене програмне забезпечення
впроваджено у тестове середовище, що демонструє його готовність до
реального використання.
Ключові слова: РОЗРОБКА ПРОГРАМНОГО ЗАБЕЗПЕЧЕННЯ,
КОМУНІКАТИВНА ПЛАТФОРМА, СТЕК MERN, MongoDB, EXPRESS.JS,
REACT.JS, NODE.JS, ПРОДУКТИВНІСТЬ, МАСШТАБОВАНІСТЬ.
ANNOTATION
Andrii Zolotoverkyi, a student of the 121 "Software Engineering" specialty,
presents a master's qualification work on the topic "Technological Aspects of
Software Development for Communication Platforms" at Cherkasy State
Technological University in Cherkasy in 2024.
The master's qualification work is dedicated to researching the technological
aspects of developing communication platforms using the modern MERN stack,
which includes MongoDB, Express.js, React.js, and Node.js. The study substantiates
the choice of technologies, analyzes existing solutions in this field, designs the
system architecture and functional modules, and conducts testing of the developed
software. The research outcome is the implementation of a functional communication
platform that meets modern requirements for performance, security, usability, and
scalability. Experimental studies confirmed the efficiency of the chosen technology
stack and the compliance of the platform's functionality with the stated requirements.
The developed software has been implemented in a test environment, demonstrating
its readiness for real-world application.
Keywords: SOFTWARE DEVELOPMENT, COMMUNICATION
PLATFORM, MERN STACK, MongoDB, EXPRESS.JS, REACT.JS, NODE.JS,
PERFORMANCE, SCALABILITY.
ЗМІСТ
ВСТУП……………………………………………………………………………….6
РОЗДІЛ 1 ІСНУЮЧІ МЕТОДИ ТА ЗАСОБИ РОЗВ’ЯЗАННЯ ПОСТАВЛЕНИХ
ЗАВДАНЬ...…………………… …………………………………………………….9
1.1 Аналіз сучасних наукових підходів до розробки комунікативних
платформ…….............................................................................................…………9
1.2 Огляд існуючих рішень та технологій……………………………………..10
1.3 Проблеми та перспективи розробки з використанням MERN
……………………………………………………………………………………….14
Висновки до розділу 1……………………………………………………………...17
РОЗДІЛ 2 ТЕОРЕТИЧНІ ТА ЕКСПЕРИМЕНТАЛЬНІ ДОСЛІДЖЕННЯ……...18
2.1 Формалізація задачі дослідження…………………………………………..18
2.2 Теоретичне обґрунтування вибору стеку MERN………………………….20
2.2.1 React як ключовий компонент стеку MERN: порівняння з Angular....23
2.2.2 MongoDB як основа гнучкості та масштабованості в стеку MERN:
порівняння з реляційними базами даних .......................................................... 26
2.2.3 Node.js та Express.js: основа продуктивності та гнучкості серверної
частини в стеку MERN ....................................................................................... 27
2.2 Експериментальні дослідження…………………………………………….29
Висновки до розділу 2………………………………………………………......37
РОЗДІЛ 3 ВПРОВАДЖЕННЯ РЕЗУЛЬТАТІВ ДОСЛІДЖЕННЯ У ПРАКТИКУ
ПРОЄКТУВАННЯ ПРОГРАМНОГО ЗАБЕЗПЕЧЕННЯ ІНФОРМАЦІЙНИХ
СИСТЕМ…………………………………………………………………………….38
3.1 Моделювання предметної області ................................................................... 38
3.1.1 Предметна область моделювання. Модель предметної області.
Словник предметної області .............................................................................. 38
3.1.2 Елементи моделювання предметної області ........................................... 40
3.1.3 Робоча область моделювання ................................................................... 44
3.2 Формування та аналіз вимог ............................................................................ 47
ЧДТУ 241917.005 ПЗ
Зм Лис № Докум. Підпис Дата
.Р озтр об Золотоверхий «Технологічні особливост і розробки програмного Л іт. Лист Листів
К. ерівни НА
е.Ом.ч енко В.В забезпечення комунікативних платформ»
к Ф ІТІС, К афедра ПЗАС,
Н .конт П івень О.Б. (Пояснювальна записка)
М ПЗ-23 04
р З
.а тв . Голуб С.В.
А
3.2.1 Формування вимог до програмного забезпечення. Первинні і детальні
вимоги. Вимоги замовника і розробника. Функціональні та
нефункціональні вимоги ..................................................................................... 47
3.2.2 Формування вимог за допомогою діаграми прецедентів ....................... 50
3.3 Проектування логічної структури програмного комплексу ......................... 52
3.3.1 Діаграми класів ........................................................................................... 52
3.3.2 Діаграми пакетів ......................................................................................... 56
3.4 Архітектурне проектування ............................................................................. 57
3.4.1 Діаграма компонентів ................................................................................ 57
3.4.2 Розгортання програмної системи на апаратних засобах. Діаграма
розгортання .......................................................................................................... 60
3.5 Моделювання поведінки системи ........................................................................ 61
3.5.1 Діаграма діяльності .................................................................................... 61
3.5.2 Діаграма послідовності .............................................................................. 63
3.5.3 Діаграма комунікації .................................................................................. 66
3.5.4 Діаграма скінченного автомату ................................................................ 67
Висновки до розділу 3………………………………………………………...72
РОЗДІЛ 4 РОЗРОБКА ПРОГРАМНОГО ЗАБЕЗПЕЧЕННЯ…………………….73
4.1 Розробка програмного комплексу…………………………………………..73
4.1.1 Обґрунтування вибору засобів реалізації ................................................ 73
4.1.2 Опис структурної (функціональної) схеми ............................................. 74
4.1.3 Опис логічної схеми системи .................................................................... 76
4.1.4 Розробка бази даних ................................................................................... 78
4.1.5 Розробка інтерфейсу користувача ............................................................ 80
4.1.6 Опис розробки програмних компонентів ................................................ 83
4.2 Тестування системи………………………………………………………….85
4.2.1 Модульне тестування ................................................................................. 85
ЧДТУ 241917.005 ПЗ
З м. Лист № док. Підпис Дата
4.2.2 Інтеграційне тестування ……………………………………………………...91
4.2.3 Системне тестування…………………………………………………………93
4.2.4 Приймальне тестування ……………………………………………………...95
4.3 Приклади впровадженого програмного комплексу………………………….96
Виснвоки до розділу 4……………………………………………………………...98
ЗАГАЛЬНІ ВИСНОВКИ…………………………………………………………...99
СПИСОК ВИКОРИСТАНИХ ДЖЕРЕЛ…………………………………………101
ДОДАТКИ…………………………………………………………………………104
ЧДТУ 241917.005 ПЗ
З м. Лист № док. Підпис Дата
ЧДТУ 241917.005 ПЗ
ПЕРЕЛІК УМОВНИХ СКОРОЧЕНЬ
- MongoDB, Express.js, React.js, Node.js, стек
MERN
технологій для розробки веб-застосунків’.
- Application Programming Interface (Інтерфейс
API
програмування застосунків)
- Create, Read, Update, Delete (Створення, Читання,
CRUD
Оновлення, Видалення)
UI - User Interface (Інтерфейс користувача)
UX - User Experience (Досвід користувача)
- JavaScript Object Notation (Нотація об'єктів
JSON
JavaScript)
- JSON Web Token (Веб-токен у форматі JSON)
JWT
- Representational State Transfer (Передача стану
REST
представлення)
NoSQL - Not Only SQL (Не тільки SQL)
- Document Object Model (Об'єктна модель
DOM
документа)
XSS - Cross-Site Scripting, міжсайтовий скриптинг.
- Cross-Site Request Forgery, міжсайтове підроблення
CSRF
запитів.
5
ЧДТУ 241917.005 ПЗ
ВСТУП
Актуальність теми , такі як форуми, чати та соціальні мережі, стали
невід’ємною частиною цифрової комунікації. Їх розробка належить до сфери
інженерії програмного забезпечення, яка спрямована на створення ефективних,
масштабованих і зручних для користувачів систем. Розробка таких платформ
вимагає використання сучасних технологій, що забезпечують високу
продуктивність, масштабованість і зручність для розробників. Стек MERN
(MongoDB, Express.js, React, Node.js) має численні переваги над іншими
технологічними стеками, зокрема завдяки повній JavaScript-екосистемі, швидкому
прототипуванню та можливостям реалізації сучасного інтерфейсу користувача. У
контексті інженерії програмного забезпечення використання MERN сприяє
оптимізації процесів розробки, забезпечує інтегрованість технологій і дозволяє
створювати рішення, які відповідають сучасним стандартам. Тема дослідження є
актуальною через зростаючий попит на такі рішення та необхідність
удосконалення підходів до їх проєктування й реалізації.
Зв’язок роботи з науковими програмами, планами, темами.
Робота виконується в рамках досліджень, спрямованих на вдосконалення
процесів розробки програмного забезпечення в галузі інформаційних технологій.
Вона відповідає діяльності кафедри програмного забезпечення автоматизованих
систем, зокрема дослідженням, пов’язаним із впровадженням сучасних веб-
технологій у створення інтерактивних платформ. Дослідження зосереджуються на
інноваційних підходах до розробки програмного забезпечення, що відповідають
сучасним тенденціям та вимогам ринку.
Мета роботи. Метою роботи є дослідження технологічних особливостей
розробки комунікативних платформ із використанням стеку MERN, а також
проєктування і створення функціональної комунікативної платформи (форуму).
Для досягнення мети поставлено такі завдання:
− провести аналіз існуючих рішень для розробки комунікативних
платформ;
6
ЧДТУ 241917.005 ПЗ
− дослідити особливості стеку MERN порівняно з іншими популярними
технологічними стеками;
− розробити архітектуру комунікативної платформи на основі стеку
MERN.
− реалізувати функціональну комунікативну платформу;
− оцінити ефективність використання стеку MERN у розробці платформи.
Об'єктом дослідження є процеси проєктування та впровадження
комунікативних платформ.
Предмет дослідження – це технологічні особливості використання стеку
MERN при розробці комунікативних платформ.
Методи досліджень. У роботі застосовуються наступні методи:
− порівняльний аналіз — для оцінки переваг стеку MERN над іншими
технологічними рішеннями;
− моделювання — при проєктуванні архітектури платформи;
− експериментальний метод — для реалізації та тестування розробленої
платформи;
− емпіричний аналіз — для оцінки продуктивності та масштабованості.
Наукова новизна отриманих результатів. Удосконалено підхід до
інтеграції компонентів стеку MERN за рахунок оптимізації взаємодії між
MongoDB, Express.js, React.js і Node.js, що дозволило створити
високопродуктивне та масштабоване програмне забезпечення. Удосконалено
використання React.js для забезпечення інтерактивності інтерфейсу користувача
за рахунок впровадження сучасних бібліотек і підходів до управління станом, що
дозволило підвищити зручність і швидкість роботи з платформою.
Практичне значення отриманих результатів. Розроблене програмне
забезпечення комунікативної платформи може бути використане для створення
форумів, інтерактивних спільнот та інших подібних сервісів. Впровадження
7
ЧДТУ 241917.005 ПЗ
результатів дослідження дозволяє вирішувати задачу структурної ідентифікації
шляхом інтеграції компонентів стеку MERN (MongoDB, Express.js, React.js,
Node.js), забезпечуючи високу продуктивність, масштабованість і зручність для
користувачів.
Результати дослідження можуть слугувати основою для впровадження стеку
MERN в інших програмних проєктах, таких як освітні платформи, корпоративні
системи комунікації або громадські організації. Створена комунікативна
платформа готова до використання в тестовому середовищі з перспективою
подальшого впровадження в реальних умовах.
Особистий внесок автора. Усі наукові результати, представлені в роботі,
отримані автором самостійно. Розроблено архітектуру платформи, реалізовано її
прототип, а також проведено порівняльний аналіз стеку MERN з іншими
технологічними рішеннями. Розроблена комунікативна платформа є авторською
реалізацією, включаючи її тестування та оцінку продуктивності.
8
ЧДТУ 241917.005 ПЗ
РОЗДІЛ 1 ІСНУЮЧІ МЕТОДИ ТА ЗАСОБИ РОЗВ’ЯЗАННЯ
ПОСТАВЛЕНИХ ЗАВДАНЬ
1.1. Аналіз сучасних наукових підходів до розробки комунікативних
платформ
Аналіз комунікативних платформ як об’єкта дослідження передбачає
виділення основних функцій, які вони виконують у цифровому суспільстві. Ці
платформи спрямовані на забезпечення інтерактивної взаємодії користувачів
через обмін повідомленнями, управління контентом, створення обговорень і
надання інструментів для модерації. Для досягнення цих цілей платформи
повинні відповідати вимогам масштабованості, продуктивності, зручності
використання й безпеки.
Під час розгляду платформи було ідентифіковано основні підсистеми, які
забезпечують її функціонування. Фронтенд-система виконує завдання
інтерактивної взаємодії з користувачем та реалізації динамічного інтерфейсу.
Бекенд-система відповідає за обробку бізнес-логіки, управління запитами та
взаємодію з базою даних. Зберігання даних, таких як користувацький контент і
повідомлення, реалізується через базу даних. Безпека всієї системи досягається за
допомогою технологій, які забезпечують надійну автентифікацію та авторизацію.
Вивчення властивостей кожної підсистеми показало, що фронтенд-система,
побудована на React.js, дозволяє створювати адаптивний та динамічний
користувацький досвід завдяки віртуальному DOM і багаторазовим компонентам.
Бекенд-система на основі Node.js та Express.js забезпечує високу продуктивність і
підтримку асинхронних операцій, що особливо важливо для масштабованих
рішень. MongoDB надає гнучкість у роботі з неструктурованими даними,
дозволяючи ефективно зберігати та обробляти великий обсяг інформації. Система
безпеки використовує JSON Web Token для забезпечення надійного захисту даних
і безпечного доступу до ресурсів.
Зв’язки між підсистемами реалізуються через API, що дозволяє фронтенду
взаємодіяти з бекендом для обміну даними, зберігання яких здійснюється у базі
9
ЧДТУ 241917.005 ПЗ
даних. Система безпеки контролює ці взаємодії, захищаючи від
несанкціонованого доступу.
Проведений аналіз дозволив виявити, як властивості кожної підсистеми
впливають на ефективність усієї системи. Наприклад, оптимізація бази даних
MongoDB сприяє підвищенню швидкості обробки запитів, а інтеграція React.js із
Node.js забезпечує зручність і швидкодію користувацького інтерфейсу. Таке
розділення функціональності та глибоке розуміння взаємодії підсистем дозволяє
розробляти сучасні платформи, що відповідають вимогам продуктивності,
масштабованості та безпеки. Це підтверджує важливість застосування сучасних
технологій, таких як стек MERN, у створенні платформ для цифрового
суспільства.
1.2 Огляд існуючих рішень та технологій
Сучасні комунікативні платформи базуються на широкому спектрі
технологій, які забезпечують їхню функціональність, продуктивність і
масштабованість. У процесі їх розробки застосовуються методи інженерії
програмного забезпечення, такі як модульний підхід, об’єктно-орієнтоване
проектування та використання архітектурних шаблонів. Ці методи дозволяють
забезпечити структурованість коду, полегшити інтеграцію компонентів і
спростити подальшу підтримку. Аналізуючи комунікативні платформи, можна
виділити декілька ключових технологічних рішень, які відображають сучасний
стан галузі та використовуються в рамках інженерії програмного забезпечення.
Одним із найбільш універсальних і популярних рішень є використання
стеків MERN і MEAN, які поєднують усі необхідні компоненти для розробки
сучасних веб-платформ. MERN базується на JavaScript на всіх рівнях архітектури,
що спрощує процес розробки та дозволяє скоротити витрати часу на інтеграцію
компонентів. Цей стек включає MongoDB, що дозволяє зберігати великі обсяги
неструктурованих даних, Node.js для ефективної серверної обробки запитів, React
як основний інструмент для створення динамічних інтерфейсів і Express.js для
побудови серверних додатків (рис. 1.1) [1]. Відсутність потреби у перемиканні
10
ЧДТУ 241917.005 ПЗ
між мовами програмування є ключовою перевагою цього стеку.
Рисунок 1.1 – Схема роботи стеку MERN
MEAN (рис. 1.2) є альтернативою MERN, замінюючи React на Angular.
Angular, як повноцінний фреймворк, забезпечує більшу структурованість і
пропонує потужні інструменти для управління станом додатків [2]. Проте він має
вищу складність навчання для новачків, що може стати викликом для
малодосвідчених команд розробників. Попри це, MEAN часто обирається для
корпоративних рішень, де важливі стабільність і строгість архітектури.
Рисунок 1.2 – Cхема роботи стеку MEAN
Класичний стек LAMP (рис. 1.3), який включає Linux, Apache, MySQL та
PHP, залишається поширеним вибором для менш складних веб-додатків. Його
головною перевагою є простота налаштування та великий вибір готових рішень,
зокрема у вигляді систем управління контентом, таких як WordPress [3]. Однак,
через обмеження в продуктивності та складність масштабування, LAMP
11
ЧДТУ 241917.005 ПЗ
поступається сучасним стекам, особливо в розробці високоінтерактивних
платформ.
Рисунок 1.3 – Схема робити стеку LAMP
Django у поєднанні з React представляє собою потужний інструмент для
створення складних багатофункціональних платформ (рис 1.4). Django, як
фреймворк на Python, забезпечує високу продуктивність і гнучкість у роботі з
великими масивами даних, тоді як React додає динамічності інтерфейсу. Це
рішення ідеально підходить для проєктів, які вимагають високого рівня безпеки та
гнучкості, але потребує значних знань Python та складності інтеграції.
Ruby on Rails, хоча і менш поширений порівняно з іншими рішеннями,
часто використовується для створення дискусійних платформ. Простота його
використання та великий вибір інструментів для швидкого розгортання додатків
роблять його привабливим вибором для стартапів. Однак, складність
масштабування залишається його суттєвим недоліком.
Рисунок 1.4 – Схема роботи сткуу Django+React
12
ЧДТУ 241917.005 ПЗ
Таблиця 1.1
Порівняння затребуваних стеків технологій
Технологічний Основне
Переваги Недоліки
стек використання
MERN Повна екосистема на Складність Стартапи,
JavaScript, швидке масштабування інтерактивні
прототипування, MongoDB веб-додатки
інтерактивність
MEAN Angular як фреймворк із Вища Корпоративні
потужними складність рішення, великі
інструментами, навчання системи
уніфікована екосистема порівняно з
React
LAMP Простота налаштування, Обмежена Блоги,
велика кількість готових продуктивність стандартні веб-
рішень , складність сайти
масштабування
Django+React Потужність Python у Складність Складні
бекенді, висока інтеграції, багатофункціон
продуктивність та потреба у альні
безпека глибоких платформи
знаннях Python
Ruby on Rails Простота у Вища Інтернет-
використанні, підтримка складність платформи
інтерактивних функцій масштабування
, потреба у
специфічних
знаннях
13
ЧДТУ 241917.005 ПЗ
1.3. Проблеми та перспективи розробки з використанням MERN
Розробка комунікативних платформ з використанням стеку MERN
(MongoDB, Express.js, React, Node.js) відкриває численні можливості для
створення високопродуктивних і масштабованих систем. Попри те, що
використання MERN може супроводжуватися певними недоліками, більшість із
них легко вирішуються завдяки правильно підібраним інструментам і підходам до
розробки. У цьому підрозділі розглядаються основні аспекти роботи з MERN,
зокрема потенційні виклики та перспективи.
Одним із основних аспектів, що потребує уваги, є інтеграція компонентів
стеку. Node.js, MongoDB, React та Express.js мають свої унікальні особливості, які
при правильному налаштуванні дозволяють створювати високоефективні
платформи [1]. Наприклад, асинхронна природа Node.js вимагає розуміння
механізмів обробки запитів, але одночасно надає розробникам можливість
створювати системи з високою пропускною здатністю. Використання готових
бібліотек та фреймворків значно спрощує цей процес.
MongoDB, завдяки своїй структурі NoSQL, ідеально підходить для роботи з
неструктурованими даними [4]. Хоча іноді можуть виникати питання щодо її
масштабованості, більшість із них вирішується шляхом правильного
налаштування індексів і розподілених кластерів. Це дозволяє забезпечити
стабільну роботу навіть за умов значного навантаження на систему.
React пропонує розробникам інструменти для створення адаптивних і
інтерактивних інтерфейсів. Управління станом програми за допомогою таких
бібліотек, як Redux або Context API, може здатися складним для початківців.
Однак доступність великої кількості навчальних ресурсів та готових рішень
значно полегшує цей процес. Завдяки своїй гнучкості React дозволяє адаптуватися
до різноманітних вимог користувачів і швидко вносити зміни до інтерфейсу.
Безпека є одним із ключових аспектів при розробці платформ на MERN.
Хоча система базується на JavaScript, що може створювати додаткові ризики, такі
як XSS або CSRF, застосування сучасних механізмів захисту, включаючи
використання JWT для автентифікації, дозволяє ефективно знижувати ці ризики.
14
ЧДТУ 241917.005 ПЗ
Багато розробників інтегрують готові бібліотеки, які автоматизують ці процеси,
що додатково спрощує роботу.
Попри певні недоліки, MERN відкриває широкі можливості для створення
сучасних комунікативних платформ. Завдяки використанню JavaScript на всіх
рівнях системи, MERN забезпечує швидкість і узгодженість у розробці. Це
зменшує кількість помилок та час, необхідний для навчання нових членів
команди.
Node.js забезпечує стабільну роботу платформи навіть за високих
навантажень. Його асинхронна природа дозволяє ефективно обробляти запити
користувачів у реальному часі [5]. Це особливо важливо для чатів, форумів та
інших платформ, які вимагають миттєвого оновлення інформації.
MongoDB демонструє високу продуктивність у роботі з даними, що
постійно змінюються. Її гнучкість і можливості масштабування дозволяють
адаптуватися до зростаючих потреб платформи. Розробники можуть швидко
додавати нові функції та інтегрувати інші технології для покращення роботи
системи.
React забезпечує високу інтерактивність користувацького інтерфейсу.
Завдяки концепції компонентів можна легко оновлювати або додавати нові
елементи без значного впливу на загальну архітектуру системи. Це спрощує
підтримку та розвиток платформи.
Інтеграція MERN із сучасними технологіями відкриває нові горизонти для
розвитку. Технології машинного навчання можуть бути використані для
персоналізації контенту, автоматизації модерації та аналізу поведінки
користувачів, що робить платформи більш функціональними та зручними.
Сьогодні багато стартапів і великих компаній обирають MERN для
створення своїх продуктів. Одним із таких прикладів є інтерактивні освітні
платформи, які інтегрують функції відеоконференцій, обміну повідомленнями та
управління навчальним процесом. MERN дозволяє цим системам залишатися
продуктивними навіть за значного зростання аудиторії.
Ще одним прикладом є корпоративні комунікаційні системи, які поєднують
15
ЧДТУ 241917.005 ПЗ
функції спільної роботи, управління проєктами та спілкування. Використання
MERN забезпечує швидку адаптацію до змінних потреб бізнесу та дозволяє
швидко впроваджувати нові функції.
Таким чином, MERN є перспективним вибором для розробки
комунікативних платформ. Виклики, які можуть виникати під час використання
цього стеку, є цілком розв'язуваними за умови правильного підходу до
проектування та розробки. Його продуктивність, гнучкість і інтерактивність
дозволяють створювати сучасні рішення, які відповідають потребам користувачів.
Подальший розвиток і інтеграція з іншими технологіями роблять MERN ще
привабливішим для використання в різноманітних проєктах.
16
ЧДТУ 241917.005 ПЗ
Висновки до розділу 1
У першому розділі було проведено аналіз сучасних методів і технологій, які
застосовуються в рамках інженерії програмного забезпечення для розробки
комунікативних платформ, із акцентом на використання стеку MERN (MongoDB,
Express.js, React, Node.js). Інженерія програмного забезпечення як наукова та
практична дисципліна забезпечує системний підхід до створення таких платформ,
застосовуючи сучасні методи проектування, реалізації, тестування та інтеграції.
Комунікативні платформи висувають високі вимоги до продуктивності,
масштабованості, інтерактивності та безпеки. Методи інженерії програмного
забезпечення, такі як використання клієнт-серверної архітектури, мікросервісного
підходу та автоматизації розробки, сприяють підвищенню ефективності реалізації
цих вимог. У цьому контексті стек MERN виступає як оптимальний інструмент
для розробки завдяки єдиній JavaScript-екосистемі, що забезпечує узгодженість
між фронтендом і бекендом, а також спрощує процес інтеграції компонентів.
Попри певні обмеження, такі як необхідність оптимізації MongoDB для
великих навантажень, стек MERN дозволяє легко впроваджувати інтерактивні
інтерфейси та забезпечує гнучкість у реалізації функціональності. Інші стеки,
зокрема MEAN, LAMP та Django + React, демонструють свої переваги, однак
поступаються MERN у швидкості розробки та інтерактивності.
Таким чином, аналіз показує, що використання MERN у межах інженерії
програмного забезпечення дозволяє не лише створювати сучасні комунікативні
платформи, але й забезпечувати їхню відповідність зростаючим вимогам
користувачів. Інтеграція цього стеку з інноваційними методами інженерії
програмного забезпечення відкриває нові можливості для оптимізації процесу
розробки та підтримки програмних систем.
17
ЧДТУ 241917.005 ПЗ
2 ТЕОРЕТИЧНІ ТА ЕКСПЕРИМЕНТАЛЬНІ ДОСЛІДЖЕННЯ
2.1 Формалізація задачі дослідження
Розв’язання задачі ідентифікації полягає у визначенні ключових
компонентів комунікативної платформи, їх функціональної ролі, зв’язків між
ними та умов оптимальної взаємодії.
Дано: платформа, яка повинна забезпечувати високу продуктивність,
інтерактивність, масштабованість і безпеку. Обраний стек технологій MERN
(MongoDB, Express.js, React.js, Node.js), що включає фронтенд-бібліотеку React.js
для побудови інтерфейсу користувача, серверну частину на Node.js та Express.js, а
також базу даних MongoDB для зберігання даних.
Було побудовано математичну модель системи у вигляді орієнтованого граф
S, де вузли представляють компоненти (React.js, Node.js, MongoDB, Express.js), а
зв’язки між ними описують взаємодію, наприклад, запити API або передачу
даних. У ході дослідження акцент зроблено на мінімізації затримок передачі
даних між компонентами, оптимізації їх продуктивності та забезпеченні
цілісності інформації.
.
де:
С = {c1, c2,… cn} – множина компонентів системи,
R = {rij | ci, cj C} – множина зв’язків між компонентами.
Кожен зв’язок визначає залежність від , наприклад, запит даних від
React до Express або збереження інформації в MongoDB.
Математично, матриця суміжності системи виглядає так:
де , якщо зв’язок між та існує, і — якщо його немає.
18
ЧДТУ 241917.005 ПЗ
Задача оптимізації передбачає мінімізацію затримки передачі даних між
компонентами, забезпечуючи високу пропускну здатність .
Де – мінімальний рівень пропускної здатності,
n – кількість затримок,
Tij – час затримки,
– мінімальний рівень пропускної здатності
MongoDB використовується для зберігання документів у форматі JSON.
Задача структурування даних формалізується так:
— множина документів, які зберігаються в базі даних. Кожен документ
описано атрибутами:
– і-тий документ,
, , — ключі.
Операції над документами описуються як функції:
− Insert(d) — додавання нового документа,
− Update(d,a) — оновлення атрибутів документа,
− Find(q) — пошук документів, що відповідають запиту q.
Горизонтальне масштабування в MongoDB забезпечується розподілом
даних між кількома серверами:
Критерієм оптимальності є рівномірний розподіл:
19
ЧДТУ 241917.005 ПЗ
що мінімізує затримки при виконанні запитів.
У рамках вирішення задачі структурної ідентифікації було математично
описано зв’язки між компонентами та умови їх оптимальної взаємодії. Це
створило основу для подальшої реалізації функціональної та надійної системи,
яка відповідає сучасним вимогам користувачів і забезпечує її готовність до
впровадження.
2.2 Теоретичне обґрунтування вибору стеку MERN
Суть дослідження полягає в ідентифікації оптимального підходу до
розробки комунікативних платформ із використанням сучасного стеку технологій
MERN (MongoDB, Express.js, React, Node.js). Постановка задачі ідентифікації
охоплює аналіз компонентів системи, визначення їхньої ролі в забезпеченні
продуктивності, масштабованості та інтерактивності платформи, а також
формування оптимальної архітектури для їхньої взаємодії. Основною метою є
розробка інтегрованої системи, що дозволяє ефективно обробляти дані,
забезпечувати надійну роботу серверної частини та створювати зручний
інтерфейс користувача.
Гіпотеза припускає, що використання MERN-стеку (MongoDB, Express.js,
React.js, Node.js) для розробки комунікативних платформ забезпечує більш високу
продуктивність, гнучкість і масштабованість у порівнянні з традиційними стеками
технологій, завдяки ефективній взаємодії компонентів, швидкості обробки даних
та можливості адаптації під сучасні вимоги користувачів і розробників.
MongoDB це документно-орієнтована NoSQL база даних, яка зберігає дані
у форматі JSON [4]. Вона дозволяє зберігати неструктуровані дані, що є
ключовим фактором для комунікативних платформ, де структура даних може
швидко змінюватися. Наприклад, повідомлення користувачів, вкладення, метадані
та логі активності зберігаються у вигляді документів, які легко масштабувати та
редагувати.
MongoDB також підтримує горизонтальне масштабування, що є важливим
для платформ із великою кількістю користувачів. Це досягається за рахунок
20
ЧДТУ 241917.005 ПЗ
розподілення бази даних між кількома серверами (шардінг). Крім того, MongoDB
дозволяє виконувати складні операції, такі як агрегація даних, без значного
навантаження на сервер. Це робить її ідеальним вибором для платформ із
високими вимогами до продуктивності.
У порівнянні з реляційними базами даних, такими як MySQL, MongoDB
значно гнучкіша. Вона не потребує створення жорстких схем і дозволяє
динамічно змінювати структуру даних. Це важливо для комунікативних
платформ, які постійно розвиваються, додаючи нові функції та типи даних.
Express.js - це веб-фреймворк для Node.js, який спрощує створення
серверної частини додатка. Він забезпечує обробку HTTP-запитів, маршрутизацію
та інтеграцію з іншими компонентами, такими як бази даних чи сторонні API [6].
Express.js є легким і швидким, що дозволяє розробникам зосередитися на бізнес-
логіці додатка.
Однією з ключових переваг Express.js є його гнучкість. Він підтримує
середовища будь-якої складності, від простих REST API до складних
мікросервісних архітектур [6]. У поєднанні з MongoDB Express.js дозволяє
швидко створювати серверну логіку для обробки даних, що надходять із
клієнтської частини.
У порівнянні з іншими фреймворками, такими як Django (Python) або
Laravel (PHP), Express.js має мінімалістичну структуру. Це означає, що розробник
має більше контролю над архітектурою додатка. Такий підхід дозволяє
створювати системи, які максимально відповідають вимогам проєкту.
React - це бібліотека для створення інтерфейсів користувача, розроблена
Facebook. Вона базується на концепції компонентів, які дозволяють розробникам
створювати багаторазово використовувані частини інтерфейсу. React підтримує
віртуальний DOM (Document Object Model), що значно підвищує продуктивність
додатка [7]. Це особливо важливо для комунікативних платформ, де інтерфейс
постійно оновлюється в реальному часі.
Завдяки React можна створювати односторінкові додатки (SPA), які
забезпечують швидку навігацію без необхідності перезавантаження сторінок. Це
21
ЧДТУ 241917.005 ПЗ
робить платформу більш зручною для користувачів. Крім того, React підтримує
інтеграцію з багатьма сторонніми бібліотеками та фреймворками, що дозволяє
легко розширювати функціональність платформи.
У порівнянні з іншими бібліотеками, такими як Angular або Vue.js, React є
більш гнучким і легким у вивченні. Angular, наприклад, вимагає використання
TypeScript і має більший обсяг правил і стандартів, що може бути складним для
невеликих команд. Vue.js пропонує простий API, але поступається React у
масштабованості та екосистемі.
Node.js - середовище виконання JavaScript, яке дозволяє використовувати
цю мову на сервері. Його ключова особливість подієво-орієнтована модель, яка
забезпечує обробку тисяч одночасних з'єднань із мінімальними витратами
ресурсів [5]. Це робить Node.js ідеальним для платформ із високим трафіком,
таких як чати чи форуми.
Node.js підтримує численні модулі та бібліотеки через систему npm (Node
Package Manager). Це спрощує розробку та скорочує час на реалізацію нових
функцій. У поєднанні з Express.js Node.js забезпечує стабільну роботу серверної
частини навіть за умов високих навантажень.
У порівнянні з іншими серверними середовищами, такими як PHP чи Ruby,
Node.js має значно вищу продуктивність. PHP, наприклад, базується на
багатопоточній моделі, яка споживає більше ресурсів. Ruby on Rails пропонує
багатий набір інструментів, але поступається Node.js у масштабованості та
швидкості виконання.
Головною перевагою MERN є безшовна інтеграція всіх його компонентів.
React взаємодіє з Express.js через REST API, що забезпечує швидкий обмін
даними між клієнтом і сервером [1]. MongoDB слугує надійним сховищем для
даних, а Node.js гарантує їхню обробку в реальному часі. Така архітектура
дозволяє розробляти складні системи з мінімальними витратами на налаштування
та інтеграцію.
Нижче наведено порівняльну таблицю порівнянь для обґрунтування вибору
22
ЧДТУ 241917.005 ПЗ
стеку MERN:
Таблиця 2.1
Порівняльна таблиця
Параметр MERN MEAN LAMP
Мова JavaScript (усі JavaScript (усі PHP (бекенд),
програмування компоненти) компоненти) SQL (база даних)
База даних MongoDB MongoDB MySQL
(NoSQL, (NoSQL, (реляційна)
документно- документно-
орієнтована) орієнтована)
Фреймворк React Angular Відсутній
фронтенду
Фреймворк Express.js Express.js PHP
бекенду
Продуктивність Висока Висока, але Середня (через
(асинхронна важчий фронтенд багатопоточність)
обробка)
Масштабованість Висока Висока Низька
Інтерактивність Висока Висока Низька
Складність Висока Висока Низька
навчання
2.2.1 React як ключовий компонент стеку MERN: порівняння з Angular
23
ЧДТУ 241917.005 ПЗ
Одним із центральних компонентів стеку MERN є React, який відповідає за
створення користувацького інтерфейсу (UI). React — це бібліотека, орієнтована
на створення динамічних, інтерактивних веб-додатків. Його ключовою
особливістю є використання компонентного підходу, який дозволяє
структурувати інтерфейс на незалежні, багаторазові блоки. У контексті вибору
MERN, React демонструє низку переваг, особливо при порівнянні з Angular, що є
основним фронтенд-компонентом у стеку MEAN.
React забезпечує значно більшу гнучкість у виборі супутніх бібліотек і
підходів, ніж Angular. У стеку MERN розробники можуть вільно обирати
інструменти для управління станом (наприклад, Redux або Context API),
маршрутизації (React Router), стилізації компонентів тощо. Angular, будучи
фреймворком у MEAN, пропонує всеосяжне середовище зі вбудованими
інструментами, які часто перевантажують проєкт і обмежують розробників у
виборі технологій.
Гнучкість React є ключовим фактором для комунікативних платформ, де
інтерактивність і користувацький досвід мають вирішальне значення [7].
Наприклад, у React можна легко інтегрувати сторонні бібліотеки для реалізації
складних функцій, таких як реальний час чату або рекомендаційні системи, що є
складнішим у Angular через суворість його архітектури.
Однією з основних переваг React у стеку MERN є його продуктивність.
React використовує віртуальний DOM, який мінімізує кількість операцій,
необхідних для оновлення інтерфейсу. Це дозволяє значно зменшити затримки та
підвищити швидкість роботи додатка. У комунікативних платформах, де
користувачі постійно взаємодіють із системою (публікують повідомлення,
змінюють налаштування тощо), висока продуктивність інтерфейсу є критичною.
Angular, який працює з реальним DOM, потребує більше ресурсів для
обробки змін. Це призводить до додаткових затримок, особливо у
високонавантажених додатках. Хоча Angular пропонує механізми оптимізації, такі
як змінні зони (zones) і детекція змін (change detection), вони є складнішими для
налаштування і вимагають додаткових ресурсів розробників.
24
ЧДТУ 241917.005 ПЗ
React базується на концепції компонентів, які є незалежними і можуть бути
багаторазово використані. Це дозволяє значно спростити розробку й
обслуговування додатка. У стеку MERN компоненти React легко інтегруються із
серверною частиною на Node.js через REST API або GraphQL. Це забезпечує
швидкий і надійний обмін даними між клієнтською та серверною частинами.
Angular також підтримує компонентний підхід, але його реалізація є
складнішою через обов'язкову інтеграцію компонентів із директивами,
шаблонами та модулями. У результаті, розробка навіть простих компонентів в
Angular потребує більше часу і зусиль. У комунікативних платформах, де
інтерфейс постійно змінюється й оновлюється, гнучкість React має вирішальне
значення.
React, як частина MERN, забезпечує просту і ефективну інтеграцію з
серверною частиною, реалізованою на Express.js і Node.js. Через REST API або
GraphQL React може швидко отримувати дані з MongoDB і відображати їх на
інтерфейсі користувача. Така взаємодія забезпечує високу продуктивність і
дозволяє легко масштабувати додаток.
Angular, як частина MEAN, також підтримує взаємодію із сервером, але
вимагає використання більш складної структури запитів і інтерфейсів. У
результаті, інтеграція Angular з серверною частиною може займати більше часу та
ресурсів, що є недоліком у порівнянні з React. React має низьку криву навчання,
що робить його доступним для новачків. Усі основні концепції, такі як
компоненти, стан і пропси, можна швидко освоїти навіть без досвіду у фронтенд-
розробці. Крім того, React має велику кількість навчальних матеріалів,
включаючи офіційну документацію, курси та приклади.
Angular, навпаки, має крутішу криву навчання через використання
TypeScript, директив, модулів і специфічних стандартів. Ці особливості можуть
стати викликом для розробників, які не мають досвіду роботи з фреймворками. У
проєктах, де потрібно швидке навчання нових членів команди, React є кращим
вибором.
React, як частина MERN, забезпечує високу масштабованість завдяки своїй
25
ЧДТУ 241917.005 ПЗ
гнучкій архітектурі та можливості інтеграції з іншими бібліотеками. Це дозволяє
легко розширювати функціональність комунікативних платформ у міру зростання
їхньої аудиторії.
Angular також підтримує масштабованість, але його суворі стандарти та
складна архітектура можуть обмежувати можливості розробників. Крім того,
часті оновлення Angular можуть вимагати значних змін у проєкті, що створює
додаткове навантаження на команду.
2.2.2 MongoDB як основа гнучкості та масштабованості в стеку MERN:
порівняння з реляційними базами даних
MongoDB є основною базою даних у стеку MERN, яка забезпечує гнучке та
масштабоване зберігання даних. Її документно-орієнтована структура та
можливість працювати з неструктурованими даними роблять її ідеальним
вибором для сучасних комунікативних платформ, що вимагають високої
продуктивності та адаптивності. У контексті MERN MongoDB забезпечує
ефективну взаємодію із серверною частиною на Node.js через драйвери, що
підтримують асинхронну обробку запитів [4]. Для порівняння, реляційні бази
даних, такі як MySQL, також широко використовуються, але мають ряд
обмежень, які ускладнюють роботу зі складними та змінними структурами даних.
MongoDB використовує NoSQL підхід, який дозволяє зберігати дані у
вигляді JSON-подібних документів. Це забезпечує велику гнучкість, оскільки
розробникам не потрібно створювати суворі схеми, як у реляційних базах даних.
Для комунікативних платформ, де структура даних може змінюватися (наприклад,
додавання нових типів повідомлень, категорій чи метаданих), MongoDB
забезпечує швидке та безболісне оновлення моделі даних.
MySQL, навпаки, вимагає визначення жорстких схем і таблиць, що
ускладнює процес змін у структурі даних. Наприклад, додавання нового поля в
таблицю може вимагати часу, а також може вплинути на продуктивність системи.
MongoDB підтримує горизонтальне масштабування (шардінг), що дозволяє
розподіляти дані між кількома серверами. Це забезпечує стабільну роботу
системи навіть за умов зростання обсягів даних і кількості користувачів. У
26
ЧДТУ 241917.005 ПЗ
комунікативних платформах це особливо важливо, оскільки вони генерують
великий обсяг даних, таких як повідомлення, файли, логи та метадані.
MongoDB ідеально інтегрується з Node.js завдяки офіційним драйверам, які
підтримують асинхронну обробку запитів. Це забезпечує швидку передачу даних
між сервером і базою даних без блокування процесів. У стеку MERN це дозволяє
реалізовувати складні функції, такі як реальний час спілкування або
рекомендаційні системи, з мінімальними затримками.
MySQL також підтримує інтеграцію з Node.js через бібліотеки, такі як
Sequelize чи mysql2. Проте, через реляційну структуру, обробка складних запитів
може створювати затримки, що ускладнює реалізацію інтерактивних функцій у
реальному часі.
MySQL, як реляційна база даних, краще підходить для вертикального
масштабування, що обмежує її продуктивність при роботі з великими обсягами
даних. Наприклад, виконання складних JOIN-запитів у MySQL може значно
уповільнити систему, особливо якщо дані розподілені між кількома таблицями.
MongoDB пропонує вбудовані механізми для шифрування даних, створення
резервних копій і відновлення системи. Вона також підтримує механізми
керування доступом на рівні колекцій і документів, що забезпечує високий рівень
безпеки.
MySQL також має потужні інструменти для резервного копіювання та
керування доступом, але її механізми складніші у налаштуванні для
масштабованих систем. У проєктах, де безпека та швидкість резервного
копіювання мають вирішальне значення, MongoDB пропонує більш прості й
ефективні рішення.
2.2.3 Node.js та Express.js: основа продуктивності та гнучкості серверної
частини в стеку MERN
Express.js і Node.js є ключовими компонентами серверної частини стеку
MERN. Вони забезпечують продуктивну, гнучку та масштабовану основу для
обробки запитів і взаємодії з базою даних MongoDB. Node.js, як середовище
27
ЧДТУ 241917.005 ПЗ
виконання JavaScript на сервері, і Express.js, як легкий веб-фреймворк, створюють
синергію, яка дозволяє будувати ефективні серверні рішення. Для порівняння,
традиційні серверні середовища, такі як PHP (використовуваний у стеку LAMP),
також мають свої переваги, але поступаються в ключових аспектах, таких як
швидкість і асинхронність.
Node.js використовує подієво-орієнтовану, асинхронну архітектуру, яка
дозволяє обробляти тисячі запитів одночасно, не блокуючи основний потік
виконання [5]. Це досягається за допомогою механізму event loop, який мінімізує
затримки навіть при високих навантаженнях.
PHP, як традиційне серверне середовище, використовує багатопоточну
модель. Кожен новий запит створює окремий потік або процес, що споживає
більше ресурсів сервера. У системах із високою кількістю одночасних
користувачів це може спричинити значне уповільнення.
У стеку MERN Node.js забезпечує чудову продуктивність для
комунікативних платформ, таких як чати, форуми та стрічки новин, де потрібна
швидка обробка запитів у реальному часі.
Express.js є мінімалістичним веб-фреймворком для Node.js, який спрощує
створення серверної логіки. Він надає інструменти для обробки HTTP-запитів,
маршрутизації, інтеграції з базами даних і обробки помилок. У порівнянні з
іншими серверними фреймворками, такими як Laravel (PHP), Express.js пропонує
більше гнучкості, дозволяючи розробникам обирати інструменти залежно від
потреб проєкту.
Наприклад, у комунікативних платформах маршрути можуть бути
налаштовані для створення API, які легко масштабувати та інтегрувати з
клієнтською частиною React. Laravel, хоч і пропонує багатий функціонал, має
більш складну архітектуру, яка може бути зайвою для простих додатків.
Node.js забезпечує високу продуктивність завдяки неблокуючим операціям
вводу-виводу. Це означає, що сервер може одночасно обробляти кілька запитів
без очікування завершення кожного. Express.js, будучи легким фреймворком,
додає мінімальне навантаження на сервер, що дозволяє зосередитися на бізнес-
28
ЧДТУ 241917.005 ПЗ
логіці.
Для порівняння, сервери на основі PHP і Apache, як у LAMP, мають більшу
затримку при обробці запитів через блокуючу модель вводу-виводу. Це стає
особливо помітним при роботі з великими обсягами даних або високим трафіком.
Масштабованість Node.js і Express.js також переважає. Вони підтримують
як вертикальне, так і горизонтальне масштабування, що робить їх придатними для
великих систем із динамічними потребами.
Node.js і Express.js мають велику й активну спільноту, що забезпечує доступ
до численних навчальних матеріалів, бібліотек і прикладів. Регулярні оновлення
та підтримка дозволяють швидко адаптувати нові функції й підходи.
PHP, будучи старішою технологією, також має широку спільноту, але її
інноваційний розвиток дещо повільніший порівняно з Node.js.
Express.js і Node.js забезпечують плавну інтеграцію з MongoDB через
офіційні драйвери. Це дозволяє створювати REST API або GraphQL для швидкого
обміну даними між сервером і базою даних. Така інтеграція полегшує реалізацію
функцій у реальному часі, таких як відстеження нових повідомлень або оновлення
статусів користувачів.
PHP також підтримує інтеграцію з базами даних, такими як MySQL, але
реалізація складних операцій, як-от робота з великими вкладеними структурами
даних, потребує більше ресурсів і часу.
2.2 Експериментальні дослідження
Мета експериментальних досліджень полягала у визначенні ефективності
стеку MERN (MongoDB, Express.js, React, Node.js) у розробці комунікативних
платформ через порівняння з альтернативними технологічними стеками MEAN
(MongoDB, Express.js, Angular, Node.js) та LAMP (Linux, Apache, MySQL, PHP).
Основна увага приділялася швидкості відповіді сервера, споживанню оперативної
пам’яті та масштабованості платформ.
Для досягнення мети, для кожного дробного факторного експерименту було
розроблено план дослідження.
29
ЧДТУ 241917.005 ПЗ
Було створено три прототипи комунікативних платформ на основі стеків
MERN, MEAN та LAMP. Кожен прототип реалізовував базовий набір
функціональних можливостей: реєстрацію користувачів, створення категорій і
тем, публікацію повідомлень, завантаження файлів і модерацію контенту. Для
забезпечення однакових умов усі прототипи розгорталися на сервері з такими
характеристиками: Intel Core i7 9700k, 16 ГБ оперативної пам’яті DDR4.
Для кожного експериментального етапу дослідження проводились
вимірювання ключових параметрів, таких як час відповіді серверів, кількість
спожитої пам’яті, рівень обробки запитів без помилок та стійкість до пікових
навантажень. Результати були представлені у вигляді графіків, що порівнюють
продуктивність стеків MERN, MEAN і LAMP.
Перший експериментальний етап дослідження включав стрес-тести для
оцінки швидкості обробки запитів сервером при одночасному навантаженні 500,
1000 та 2000 користувачів.
Таблиця 2.2
Таблиця факторів і рівнів першого експерименту
Фактор Рівень 1 Рівень 2 Рівень 3
Технологічний
MERN MEAN LAMP
стек
Кількість
500 1000 2000
користувачів
Експеримент показав, що середній час відповіді для MERN-стеку становив
150 мс при 500 користувачах, 220 мс при 1000 користувачах та 350 мс при 2000
користувачах. Для MEAN-стеку ці показники склали відповідно 180 мс, 280 мс та
420 мс, тоді як LAMP-стек демонстрував 230 мс, 350 мс та 510 мс (рис 2.1).
30
ЧДТУ 241917.005 ПЗ
Рисунок 2.1 - Порівняння середнього часу відповіді (мс) при різній кількості
користувачів
Другий етап дослідження був спрямований на оцінку споживання ресурсів
кожним з розглянутих стеків.
Таблиця 2.3
Таблиця факторів і рівнів другого експерименту
Фактор Рівень 1 Рівень 2
Технологічний
MERN MEAN
стек
Кількість
1000 2000
користувачів
Було виміряно середню кількість використаної оперативної пам’яті під час
роботи з 1000 та 2000 одночасними користувачами. MERN-стек показав
споживання на рівні 700 МБ оперативної пам'яті при 1000 користувачах та 1,2 ГБ
при 2000 користувачах. MEAN-стек вимагав близько 800 МБ та 1,4 ГБ відповідно,
тоді як LAMP-стек споживав більше 1 ГБ оперативної пам’яті при 1000
31
ЧДТУ 241917.005 ПЗ
користувачах і досягав 1,8 ГБ при збільшенні навантаження до 2000 користувачів
(рис 2.2).
Рисунок 2.2 - Порівняння використання оперативної пам'яті (МБ) при різній
кількості користувачів
Третім етапом стало тестування масштабованості платформи.
Таблиця 2.4
Таблиця факторів і рівнів третього експерименту
Фактор Рівень 1 Рівень 2
Технологічний
MERN LAMP
стек
Кількість
2000 3000
користувачів
Використання горизонтального масштабування для серверів на базі Node.js
32
ЧДТУ 241917.005 ПЗ
дозволило зменшити середній час відповіді на 15% при збільшенні кількості
користувачів до 3000. MEAN-стек показав подібні результати, але з меншою
ефективністю, оскільки Angular потребує більше ресурсів для рендерингу
складних інтерфейсів. LAMP-стек виявився менш адаптованим до
масштабування, що призвело до значного зростання часу відповіді при високих
навантаженнях (рис 2.3).
Рисунок 2.3 - Вплив масштабування на час відповіді при збільшенні
кількості користувачів
Четвертим етапом стало тестування стійкості до високочастотних записів.
Таблиця 2.5
Таблиця факторів і рівнів четевертого експерименту
Фактор Рівень 1 Рівень 2
Тип запитів GET, POST PUT, DELETE
Технологічний MERN, MEAN,
MERN, MEAN, LAMP
стек LAMP
33
ЧДТУ 241917.005 ПЗ
Система була протестована на обробку високочастотних запитів. Кожна
платформа отримувала 10 000 HTTP-запитів протягом 1 хвилини з різним
розподілом типів запитів (70% GET, 20% POST, 10% PUT/DELETE). Для кожного
стеку були виміряні наступні параметри: час відповіді на запити, відсоток
успішно оброблених запитів, відсоток помилок сервера (HTTP 500).
В результаті експерименту, MERN продемонстрував середній час відповіді
120 мс на запит і обробив 98,5% запитів без помилок. Помилки серверної частини
склали лише 1,5%, що пов’язано з високою оптимізацією Node.js та MongoDB.
MEAN мав середній час відповіді 160 мс і успішно обробив 96,8% запитів.
Виникли складнощі з Angular, який уповільнив генерацію інтерфейсу для POST-
запитів. LAMP мав найбільший час відповіді 240 мс, успішно обробив 92%
запитів. Основною причиною помилок було навантаження на Apache і MySQL
при великій кількості одночасних операцій (рис 2.4).
Рисунок 2.4 – Продуктивність стеків у тесті на високочастотні запити
34
ЧДТУ 241917.005 ПЗ
Останній етап – це проведення експериментального дослідження
навантаження при роботі з великими файлами.
Таблиця 2.6
Таблиця факторів і рівнів п’ятого експерименту
Фактор Рівень 1 Рівень 2 Рівень 3
Розмір файлу 10 МБ 50 МБ 100 МБ
Технологічний
MERN MEAN LAMP
стек
Метою стала оцінка продуктивності стеків MERN, MEAN і LAMP при
обробці великих файлів (наприклад, завантаження вкладень, обробка зображень
тощо), які часто зустрічаються на комунікативних платформах.
Система тестувалася на завантаженні та збереженні файлів розміром 10 МБ,
50 МБ і 100 МБ у базу даних або хмарне сховище. Кожен стек використовував
наступну інфраструктуру:
− MERN: Збереження файлів у AWS S3 через серверну частину на Node.js
і MongoDB для зберігання метаданих;
− MEAN: Використання AWS S3 із серверною частиною Angular і
MongoDB;
− LAMP: Збереження файлів у файловій системі сервера через PHP і
MySQL для зберігання метаданих.
Кожен тест включав 100 операцій завантаження, під час яких вимірювалися:
середній час обробки кожної операції, використання оперативної пам’яті
сервером, Стабільність при піковому навантаженні (100 одночасних завантажень).
В результаті,
Середній час обробки файлів (мс):
− MERN: 500 мс для 10 МБ, 1200 мс для 50 МБ, 2500 мс для 100 МБ;
35
ЧДТУ 241917.005 ПЗ
− MEAN: 700 мс для 10 МБ, 1500 мс для 50 МБ, 3200 мс для 100 МБ;
− LAMP: 850 мс для 10 МБ, 1800 мс для 50 МБ, 4000 мс для 100 МБ.
Використання оперативної пам’яті:
− MERN: стабільне, в середньому 1.2 ГБ при навантаженні;
− MEAN: значні коливання, до 1.5 ГБ при пікових запитах;
− LAMP: високе навантаження — до 2.0 ГБ.
Стабільність при піковому навантаженні:
− MERN: 98% запитів успішно виконані;
− MEAN: 94% запитів успішно виконані;
− LAMP: 88% запитів успішно виконані, затримки до 5000 мс на піку.
MERN показав найкращі результати завдяки асинхронній обробці запитів у
Node.js та використанню AWS S3 для збереження файлів. MEAN виявився менш
стабільним через підвищене навантаження на Angular. LAMP мав найгірші
показники через обмеження PHP та файлової системи сервера (рис 2.5).
Рисунок 2.5 – Час обробки файлів різного розміру
36
ЧДТУ 241917.005 ПЗ
Висновки до розділу 2
Дослідження, проведені в межах другого розділу, спрямовані на вивчення
ефективності використання стеку MERN для створення комунікативних
платформ. Було здійснено формалізацію задачі дослідження, яка включає аналіз
взаємодії компонентів системи, структурну ідентифікацію та оптимізацію їхньої
роботи. У процесі теоретичного обґрунтування підтверджено переваги MERN
порівняно з іншими технологічними стеками, такими як MEAN та LAMP, завдяки
високій продуктивності, гнучкості та інтерактивності.
Експериментальна частина дослідження включала створення прототипів
платформ і тестування їхньої роботи за ключовими параметрами, такими як час
відповіді, споживання ресурсів, масштабованість і стійкість до навантажень.
Результати експериментів продемонстрували переваги стеку MERN у реальних
умовах використання, що підтверджує його доцільність для розробки сучасних
комунікативних платформ.
Отримані результати слугують основою для подальшої реалізації
програмного комплексу та підтверджують високу ефективність обраного
технологічного підходу.
37
ЧДТУ 241917.005 ПЗ
3 ВПРОВАДЖЕННЯ РЕЗУЛЬТАТІВ ДОСЛІДЖЕННЯ У ПРАКТИКУ
ПРОЄКТУВАННЯ ПРОГРАМНОГО ЗАБЕЗПЕЧЕННЯ ІНФОРМАЦІЙНИХ
СИСТЕМ
3.1 Моделювання предметної області
Предметна область моделювання охоплює взаємодію користувачів із
комунікативною платформою, яка забезпечує створення та обговорення тем,
обмін повідомленнями, прикріплення файлів, а також інструменти модерації й
адміністрування. Основною метою є надання користувачам можливості
ефективної комунікації в рамках організованого інформаційного середовища, де
кожен елемент системи працює узгоджено для підтримки функціональності.
3.1.1 Предметна область моделювання. Модель предметної області. Словник
предметної області
Cистема включає три основні рівні: клієнтський, серверний і рівень
зберігання даних. Клієнтська частина реалізована на React і відповідає за
створення інтуїтивно зрозумілого інтерфейсу. Серверна частина базується на
Node.js із використанням Express.js для обробки запитів і взаємодії з базою даних
MongoDB. Ключовим аспектом є інтеграція цих компонентів для досягнення
високої продуктивності, масштабованості та зручності використання.
Модель предметної області включає основні сутності системи, їхню
структуру та взаємозв’язки. Користувачі є центральним елементом платформи.
Вони взаємодіють із системою через облікові записи, створюють контент і
обговорюють його, тоді як адміністратори виконують функції модерації. Категорії
та теми організовують контент. Категорії об'єднують теми, які створюють
користувачі для обговорення різних питань. Тема об’єднує повідомлення,
створені користувачами. Повідомлення є основним типом контенту, який включає
текстові чи мультимедійні дані, з можливістю прикріплення файлів. Файли
дозволяють користувачам обмінюватися документами, зображеннями та іншими
видами даних. Модерація забезпечує контроль якості контенту. Адміністратори
38
ЧДТУ 241917.005 ПЗ
можуть видаляти небажані повідомлення, блокувати користувачів або реагувати
на звіти про порушення.
Модель предметної області (рис 3.1) також визначає структуру даних, що
зберігаються у системі [8]. MongoDB використовується для зберігання інформації
про користувачів, категорії, теми, повідомлення та прикріплені файли. Наприклад,
дані про повідомлення включають такі атрибути, як ідентифікатор автора, текст,
дата створення та посилання на вкладені файли. Така організація дозволяє швидко
отримувати дані та забезпечувати їхню доступність для користувачів у режимі
реального часу.
Рисунок 3.1 - Діаграма класів спроектованого ПЗ
39
ЧДТУ 241917.005 ПЗ
Словник предметної області.
Основними термінами є користувач, тема, категорія, повідомлення, файл і
модерація. Користувач визначається як особа, яка взаємодіє з платформою через
обліковий запис. Тема є структурованим блоком обговорень, створеним
користувачем. Повідомлення описується як текстовий або мультимедійний
контент у межах теми. Категорія об’єднує теми за спільною тематикою. Файл є
додатком до повідомлення, що може включати документи, зображення чи інші
типи даних. Модерація включає процес перевірки та управління контентом
адміністратором, спрямований на підтримання якості та відповідності правилам
платформи.
Взаємозв’язки між сутностями забезпечують цілісність функціонування
системи. Користувач створює теми, які містять повідомлення. Повідомлення
можуть включати вкладення у вигляді файлів. Адміністратори мають доступ до
всіх сутностей для модерації та управління, що дозволяє забезпечувати стабільну
роботу платформи й організованість інформації.
Розроблена модель предметної області та словник ключових термінів
формують основу для реалізації функціональності платформи. Вони дозволяють
чітко визначити ключові елементи системи, їхні ролі та взаємозв’язки, що є
необхідним для створення надійного програмного забезпечення. Такий підхід
забезпечує ефективну комунікацію між усіма учасниками проєкту та сприяє
успішному досягненню поставлених цілей.
3.1.2 Елементи моделювання предметної області
Елементи моделювання предметної області формують базу для
проектування та впровадження системи, яка задовольняє всі вимоги користувачів
і забезпечує стабільне функціонування комунікативної платформи [8].
Моделювання включає визначення ключових процесів, об’єктів і їх взаємодії,
зосереджуючись на забезпеченні логічної узгодженості й функціональної повноти
системи. Управління користувачами є центральною частиною будь-якої
комунікативної платформи. У цій системі реалізовано можливість створення,
редагування та видалення облікових записів. Кожен користувач має унікальний
40
ЧДТУ 241917.005 ПЗ
ідентифікатор, набір персональних даних і обмежений доступ до ресурсів
платформи, що регулюється його статусом.
Важливим аспектом є поділ користувачів на звичайних учасників і
адміністраторів. Звичайні користувачі можуть взаємодіяти із системою через
створення контенту, наприклад, тем або повідомлень. Адміністратори виконують
спеціальні завдання, такі як модерація, блокування порушників і управління
категоріями. Це дозволяє підтримувати порядок і забезпечувати відповідність
роботи платформи встановленим правилам.
Контент на платформі організовується через ієрархічну структуру категорій,
тем і повідомлень. Категорії дозволяють групувати теми за певними напрямками,
що полегшує користувачам пошук інформації. Теми є основними осередками
обговорення, де користувачі можуть залишати свої повідомлення, ділитися
думками чи ставити запитання.
Для підтримки організованості контенту використовується система тегів,
яка дозволяє позначати теми ключовими словами. Це спрощує пошук і навігацію,
надаючи користувачам можливість швидко знайти потрібну інформацію за
тематикою.
Повідомлення є основним засобом комунікації на платформі. Кожне
повідомлення містить текст, час публікації та інформацію про автора. Крім того,
повідомлення можуть доповнюватися вкладеннями, такими як файли або
зображення. Це дозволяє користувачам обмінюватися не лише текстовими
даними, а й мультимедійним контентом.
Система управління вкладеннями передбачає зберігання файлів у
централізованому сховищі, що забезпечує доступність і безпеку даних. Вкладення
можуть бути використані для обміну документацією, презентаціями або іншими
матеріалами, що підвищує функціональність платформи.
Модерація забезпечує контроль якості контенту та дотримання
користувачами правил платформи. Процес модерації включає перевірку
повідомлень, видалення небажаного контенту та блокування порушників.
41
ЧДТУ 241917.005 ПЗ
Адміністратори отримують доступ до спеціальних інструментів, які дозволяють
ефективно виконувати ці завдання.
Важливим елементом модерації є механізм звітів про порушення.
Користувачі можуть повідомляти про невідповідний контент, залишаючи скарги.
Ці скарги аналізуються адміністраторами, після чого приймаються відповідні
рішення, наприклад, видалення повідомлення або обмеження доступу до
платформи для порушника.
Інтерактивність платформи забезпечується через механізми сповіщень, які
інформують користувачів про нові події. Сповіщення можуть включати
повідомлення про відповіді на теми, нові повідомлення чи адміністративні дії. Ця
функція підтримує активність користувачів і забезпечує їх своєчасне
інформування про важливі події.
Платформа підтримує організацію обговорень через створення потоків і
діалогів. Потоки дозволяють групувати повідомлення за тематикою,
забезпечуючи структуроване обговорення. Вони є важливими для великих
спільнот, де відбувається паралельне обговорення різних тем.
Елементи моделювання пред метної області охоплюють ключові аспекти
функціональності платформи. Управління користувачами, організація контенту,
підтримка модерації та забезпечення інтерактивності створюють фундамент для
розробки ефективної системи. Усі ці елементи інтегруються в єдину платформу,
яка відповідає сучасним вимогам і забезпечує комфортну взаємодію для
користувачів. Моделювання на цьому рівні закладає основу для успішної
реалізації проєкту.
Таблиця 3.1
Основні графічні символи UML
Графічний символ Назва елемента
Дійова особа (Actor)
42
ЧДТУ 241917.005 ПЗ
Продовження таблиці 3.1
Варіант використання (Use Case)
Коментар (Note)
Клас (Class)
Пакет (Package)
Об’єкт
Компонент (Component)
Головна програма (Main program)
Ресурс (Resource)
Таблиця 3.2
Єднальні елементи UML
Графічний символ Назва елемента
43
ЧДТУ 241917.005 ПЗ
Продовження таблиці 3.2
Односпрямована асоціація (Unidirectional association)
Анотація до пункту (Ancor note to item)
Посилання на об’єкт (Object link)
Посилання на себе (Link to Self)
Пряме повідомлення (Link message)
Зворотне повідомлення (Return message)
3.1.3 Робоча область моделювання
Робоча область моделювання представляє конкретизацію предметної
області для створення функціональних частин платформи. Вона охоплює не лише
опис загальних концепцій, а й визначення технічних аспектів реалізації системи.
Основна увага приділяється інтеграції компонентів, потокам даних і
забезпеченню логічної взаємодії між ними. Робоча область моделювання слугує
фундаментом для переведення теоретичних моделей у практичні рішення, що
будуть застосовуватися в розробці комунікативної платформи.
Робоча область моделювання охоплює три ключові компоненти: клієнтську
частину, серверну частину та базу даних (рис 3.5). Кожен із цих компонентів
виконує чітко визначені завдання, але їхня взаємодія забезпечує цілісність
системи.
Клієнтська частина реалізована за допомогою React і відповідає за
інтерфейс користувача. Вона обробляє запити, отримує дані із серверної частини
44
ЧДТУ 241917.005 ПЗ
та забезпечує зручну взаємодію з функціональністю платформи. Важливою
складовою клієнтської частини є маршрутизація, яка дозволяє користувачам легко
переходити між різними розділами платформи.
Серверна частина, створена на основі Node.js і Express.js, забезпечує
обробку запитів, управління бізнес-логікою й взаємодію з базою даних. Вона
включає механізми аутентифікації, модерації та управління контентом. Серверна
частина також відповідає за захист даних, використовуючи відповідні протоколи
безпеки.
База даних MongoDB зберігає інформацію про користувачів, повідомлення,
файли, звіти та інші ключові сутності. Вона забезпечує гнучкість у роботі з
динамічними структурами даних і дозволяє ефективно масштабувати систему.
Інтеграція компонентів здійснюється через розробку REST API, що
слугують мостом між клієнтською та серверною частинами. Клієнт відправляє
запити до сервера, отримуючи необхідні дані у форматі JSON. Наприклад, запит
на отримання списку тем у категорії надсилається серверу, який звертається до
бази даних, обробляє запит і повертає результати.
Обробка запитів поділяється на кілька рівнів. Серверна частина перевіряє
достовірність запиту, виконує необхідну логіку та повертає відповідь клієнту.
Взаємодія між сервером і базою даних відбувається через офіційні драйвери
MongoDB, які забезпечують швидкість і стабільність операцій.
Потоки даних у системі описують порядок передачі інформації між
компонентами. Наприклад, при створенні нового повідомлення клієнтська
частина надсилає серверу дані тексту, ідентифікатора теми та автора. Сервер
обробляє запит, перевіряє права користувача, додає повідомлення до бази даних і
повертає оновлений список повідомлень клієнту. Цей процес демонструє, як різні
компоненти системи взаємодіють для досягнення поставленої мети.
Робоча область моделювання передбачає заходи для забезпечення цілісності
та консистентності даних. Наприклад, серверна частина виконує перевірки перед
виконанням операцій у базі даних. Ці перевірки включають валідацію введених
даних, перевірку автентичності користувача й контроль доступу до ресурсів.
45
ЧДТУ 241917.005 ПЗ
Рисунок 3.5 - Модель робочої області
Для зменшення ризику втрати даних або конфліктів під час одночасного
доступу декількох користувачів, система використовує транзакції бази даних і
обробку помилок. Це дозволяє зберігати послідовність операцій і відновлювати
стан системи у випадку збоїв.
Масштабованість платформи досягається завдяки використанню сучасних
технологій, таких як MongoDB для горизонтального масштабування бази даних і
Node.js для асинхронної обробки запитів. Це дозволяє системі обробляти велику
46
ЧДТУ 241917.005 ПЗ
кількість користувачів і запитів навіть за умов пікового навантаження.
Система побудована таким чином, щоб легко адаптуватися до зростання
кількості користувачів або обсягу даних. Наприклад, можна розширювати кластер
бази даних або розподіляти навантаження між кількома серверами.
3.2 Формування та аналіз вимог
Формування та аналіз вимог до програмного забезпечення є одним із
ключових етапів розробки системи [9]. Вимоги визначають, які функціональні та
нефункціональні характеристики повинна мати платформа, щоб задовольнити
очікування користувачів, замовників і розробників [9]. У даному підрозділі
розглядаються первинні та детальні вимоги, а також класифікація вимог на
функціональні та нефункціональні, враховуючи інтереси замовників і
розробників.
3.2.1 Формування вимог до програмного забезпечення. Первинні і детальні
вимоги. Вимоги замовника і розробника. Функціональні та нефункціональні
вимоги
Первинні вимоги описують загальні характеристики системи та її цілісну
функціональність. Вони базуються на аналізі потреб замовника та цільової
аудиторії. Основними первинними вимогами до комунікативної платформи є
забезпечення зручної взаємодії між користувачами, створення й управління
контентом, а також інтеграція механізмів модерації та сповіщень.
Платформа повинна надавати можливість створювати облікові записи для
різних категорій користувачів, включаючи звичайних користувачів та
адміністраторів. Інтерфейс користувача повинен бути інтуїтивно зрозумілим і
підтримувати роботу з різними пристроями, зокрема комп’ютерами, планшетами
та смартфонами. Система має забезпечувати швидкий доступ до категорій, тем і
повідомлень, а також підтримувати обмін мультимедійними даними.
Детальні вимоги описують конкретні функції та характеристики, які
47
ЧДТУ 241917.005 ПЗ
повинні бути реалізовані в системі. Вони включають опис основних модулів, їхню
взаємодію та очікувану поведінку. Основними деталізованими вимогами є:
− система користувачів повинна включати механізми реєстрації,
аутентифікації та авторизації. Користувачі мають змогу відновлювати
доступ до облікового запису, змінювати пароль та управляти своїми
персональними даними;
− категорії та теми повинні бути ієрархічно структуровані. Користувачі
можуть створювати теми в межах категорій, додавати до них теги для
полегшення пошуку й фільтрації контенту;
− повідомлення повинні підтримувати текстовий і мультимедійний
формат. Система має забезпечувати можливість додавання вкладень,
таких як документи або зображення;
− для модерації контенту адміністратори повинні мати інструменти для
видалення повідомлень, блокування користувачів і управління
категоріями;
− сповіщення повинні інформувати користувачів про нові відповіді,
створення тем і адміністративні дії;
− платформа повинна включати пошуковий механізм для швидкого
знаходження контенту за ключовими словами, категоріями чи авторам.
Вимоги замовника визначають очікування кінцевих користувачів
платформи та її замовників. Основними вимогами замовників є:
− зручність використання платформи, включаючи простий і логічний
інтерфейс;
− швидкість роботи системи, особливо при роботі з великими обсягами
даних;
− безпека персональних даних і конфіденційність інформації;
− можливість масштабування платформи для підтримки зростання
48
ЧДТУ 241917.005 ПЗ
кількості користувачів і контенту;
− гнучкість системи, що дозволяє легко додавати нові функції чи
змінювати існуючі.
Вимоги розробника включають технічні аспекти, необхідні для реалізації
платформи. Основними вимогами є:
− використання сучасних технологій, таких як стек MERN (MongoDB,
Express.js, React, Node.js);
− забезпечення модульності та багаторазового використання коду;
− оптимізація роботи серверної частини для мінімізації затримок у
відповіді;
− інтеграція з хмарними сервісами для зберігання файлів і масштабування
бази даних;
− документування API для забезпечення взаємодії між клієнтською та
серверною частинами.
Функціональні вимоги визначають основні завдання, які система повинна
виконувати. До них належать:
− реєстрація та вхід до облікового запису;
− створення, редагування та видалення контенту (категорій, тем,
повідомлень);
− пошук і фільтрація інформації;
− завантаження та обмін файлами;
− надсилання сповіщень користувачам.
Нефункціональні вимоги визначають якісні характеристики системи. До
них належать:
− продуктивність: система повинна обробляти не менше 1000 запитів на
49
ЧДТУ 241917.005 ПЗ
секунду;
− масштабованість: система має підтримувати одночасну роботу до 10 000
користувачів;
− безпека: дані користувачів мають бути зашифровані, а доступ до них
обмежений;
− надійність: платформа повинна бути доступною 99.9% часу;
− сумісність: система має підтримувати всі сучасні веб-браузери та
мобільні пристрої.
3.2.2 Формування вимог за допомогою діаграми прецедентів
Розроблені діаграми прецедентів дозволяють чітко визначити
функціональні вимоги системи, а також виявити ролі користувачів та їхні
очікування [10].
На першій діаграмі прецедентів (рис. 3.6), що стосується адміністратора,
визначені основні функції, які дозволяють здійснювати управління контентом,
користувачами та файлами. Адміністратор має такі можливості:
− модерація повідомлень: адміністратор може перевіряти повідомлення
користувачів та приймати рішення щодо їхнього схвалення або
видалення;
− управління користувачами: адміністратор має змогу перевіряти облікові
записи, схвалювати або блокувати доступ користувачів до системи;
− управління вкладеними файлами: адміністратор перевіряє прикріплені
користувачами файли на відповідність правилам платформи та приймає
рішення щодо їхнього схвалення;
− додатково, у діаграмі реалізовано відношення «include», яке демонструє
залежність між перевіркою контенту та подальшими діями, такими як
схвалення або відхилення.
50
ЧДТУ 241917.005 ПЗ
Рисунок 3.6 – Діаграма прецендентів для адміністратора
Друга діаграма прецедентів (рис. 3.7) описує взаємодію звичайного
користувача з платформою. Основні дії користувача включають:
− аутентифікація: користувач може створити обліковий запис або увійти
до системи за допомогою наявних облікових даних;
− управління контентом: користувач може створювати категорії, теми та
повідомлення, а також прикріплювати файли до повідомлень;
− взаємодія з системою: користувач може брати участь у дискусіях,
відповідати на теми та обмінюватися інформацією з іншими учасниками
платформи;
− діаграма відображає відношення «include», яке демонструє, що
створення теми може включати додавання вкладень. Це підкреслює
51
ЧДТУ 241917.005 ПЗ
логічну послідовність дій, які виконує користувач.
Рисунок 3.7 – Діаграма прецендентів для користувача
3.3 Проектування логічної структури програмного комплексу
Проектування логічної структури програмного комплексу включає розробку
моделей взаємодії між компонентами системи, визначення функціональних
модулів та їх ролей у загальній архітектурі. Основна увага приділяється
забезпеченню логічної цілісності, модульності та зручності інтеграції
компонентів, що дозволяє створити ефективну, гнучку та масштабовану систему.
3.3.1 Діаграми класів
Нижче представлено діаграми класів для різних частин системи: фронтенду
та бекенду, які демонструють архітектуру платформи, а також її основні
компоненти [11].
52
ЧДТУ 241917.005 ПЗ
Діаграма класів фронтенду (рис. 3.8) відображає основні елементи, що
забезпечують взаємодію користувача із системою. Основними компонентами є
класи, які відповідають за управління повідомленнями, сповіщеннями, діалогами
та рейтингами. Взаємодія між цими класами забезпечує функціональність
інтерфейсу користувача, включаючи роботу з потоками повідомлень, списками
користувачів і організацію даних у вигляді структурованих папок.
Класи фронтенду організовані таким чином, щоб забезпечити гнучкість і
простоту розширення інтерфейсу. Зокрема, класи Notification і Folder
забезпечують зручну роботу з персональними даними користувача, а класи Thread
та Leaderboard формують інтерактивність та конкурентний аспект платформи.
Рисунок 3.8 – Діаграма класів фронтенду
53
ЧДТУ 241917.005 ПЗ
Діаграма класів (рис. 3.9) бекенду фокусується на управлінні даними та
логікою системи. Основними компонентами є класи, що відповідають за обробку
запитів, модерацію, управління категоріями та збереження інформації в базі
даних. Важливими аспектами бекенду є механізми аутентифікації та авторизації,
реалізовані через класи User і Admin, які забезпечують розподіл ролей та
контроль доступу.
Архітектура бекенду побудована з використанням асоціацій між класами,
таких як зв'язки між Topic, Message та User, що відображають ієрархічну
структуру контенту. Додатково, класи Report та Reaction відповідають за
модерацію і взаємодію між користувачами через механізми оцінки контенту.
Рисунок 3.9 – Діаграма класів бекенду
54
ЧДТУ 241917.005 ПЗ
Взаємодія між фронтендом і бекендом (рис. 3.10) забезпечується через чітко
визначені зв’язки між компонентами. Сервер обробляє запити, надіслані з
фронтенду, та забезпечує передачу необхідних даних. У той самий час, фронтенд
відповідає за відображення результатів цих операцій у зручному для користувача
форматі. Така архітектура дозволяє забезпечити високу продуктивність і
масштабованість системи.
Рисунок 3.10 – Діаграма класів проєктованого ПЗ
55
ЧДТУ 241917.005 ПЗ
3.3.2 Діаграми пакетів
Нижче представлено діаграму пакетів (рис. 3.11), яка відображає
взаємозв’язки між фронтендом, бекендом і базою даних.
Система складається з трьох основних пакетів: клієнтська частина, серверна
частина та база даних. Клієнтська частина відповідає за відображення інтерфейсу
та взаємодію з користувачем. Серверна частина виконує роль обробника запитів,
забезпечуючи виконання бізнес-логіки та доступ до бази даних. База даних є
основним джерелом збереження інформації, забезпечуючи швидке отримання і
збереження даних.
Клієнтська частина взаємодіє з серверною через програмний інтерфейс,
забезпечуючи передачу запитів і отримання відповідей. Серверна частина, у свою
чергу, з’єднується з базою даних, виконуючи операції читання, запису чи
оновлення інформації.
Діаграма відображає потік даних між трьома головними блоками.
Клієнтська частина посилає запити до серверної частини, яка обробляє їх,
використовуючи бізнес-логіку. Серверна частина взаємодіє з базою даних,
виконуючи запити на отримання або збереження даних. У свою чергу, база даних
зберігає структуровану інформацію про користувачів, повідомлення, теми та інші
важливі компоненти платформи.
Кожен пакет містить окремі підсистеми, які спеціалізуються на виконанні
певних завдань. Наприклад, клієнтська частина складається з модулів, що
обробляють API-запити та управляють станом додатку. У серверній частині
знаходяться підсистеми для аутентифікації, бізнес-логіки та доступу до бази
даних.
Діаграма пакетів допомагає зрозуміти, як компоненти системи взаємодіють
між собою, що полегшує процес проектування та тестування [12]. Завдяки чіткій
структурі можна ефективніше планувати інтеграцію компонентів і оцінювати
їхню взаємозалежність. Логічна організація пакетів сприяє кращій
масштабованості системи та її адаптації до нових вимог.
Представлена діаграма пакетів демонструє основну структуру системи.
56
ЧДТУ 241917.005 ПЗ
Рисунок 3.11 – Діаграма пакетів
3.4 Архітектурне проектування
3.4.1 Діаграма компонентів
Було описано структуру системи на основі діаграми компонентів,
зосереджуючись на фронтенді, бекенді та інтеграції з базою даних.
Система складається з трьох основних компонентів: клієнтської частини
(Frontend), серверної частини (Backend) та бази даних (Database). Кожен із цих
компонентів виконує свою функцію, але всі вони інтегруються для створення
цілісної системи.
Фронтенд (рис. 3.12) відповідає за взаємодію з користувачами. Основними
57
ЧДТУ 241917.005 ПЗ
підсистемами є інтерфейс користувача (User Interface), модулі автентифікації
(User Authentication) та компоненти форуму (Forum Components), які
забезпечують перегляд і створення тем та повідомлень. Фронтенд також
використовує API для комунікації з бекендом.
Рис 3.13 - Діаграма компонентів фронтенду
Бекенд (рис. 3.14) обробляє запити клієнта, забезпечуючи автентифікацію,
авторизацію та виконання бізнес-логіки. Компоненти серверної частини
включають сервер API (API Server), контролери для роботи з користувачами та
повідомленнями (User Controller і Post Controller), а також проміжне програмне
забезпечення (Middleware) для обробки запитів і доступ до бази даних.
База даних зберігає всі дані системи, включаючи інформацію про
користувачів, теми, повідомлення, вкладені файли та модерацію. Вона є джерелом
даних для бекенду, забезпечуючи швидке отримання та збереження інформації.
58
ЧДТУ 241917.005 ПЗ
Рисунок 3.14 – Діаграма компонентів бекенду
Компоненти системи інтегровані через чітко визначені API-запити.
Фронтенд надсилає запити до серверної частини для автентифікації, управління
контентом та отримання даних. Бекенд виконує бізнес-логіку і взаємодіє з базою
даних для зберігання та отримання даних. База даних відповідає за збереження
структурованої інформації, забезпечуючи швидкий доступ до неї.
Діаграма (рис 3.15) також демонструє можливість кешування даних між
бекендом і базою даних для покращення продуктивності. Це забезпечує більш
швидку обробку повторюваних запитів і зменшення навантаження на сервер.
Рисунок 3.15 – Діаграма компонентів проєктованого ПЗ
3.4.2 Розгортання програмної системи на апаратних засобах. Діаграма
59
ЧДТУ 241917.005 ПЗ
розгортання
Було описано розгортання системи на апаратних засобах, а також
представлено діаграму розгортання (рис. 3.16), яка відображає логічне
розміщення компонентів.
Система розгортається у хмарному середовищі для забезпечення
масштабованості, доступності та безпеки. Інфраструктура складається з трьох
основних рівнів: клієнтський рівень, серверний рівень і рівень зберігання даних.
На клієнтському рівні розташований веб-браузер або мобільний додаток,
який забезпечує взаємодію користувача із системою. Серверний рівень включає
сервери, які обробляють API-запити, виконують бізнес-логіку та забезпечують
доступ до бази даних.
Діаграма розгортання демонструє, як програмні компоненти взаємодіють
між собою на фізичних та логічних рівнях [13]. Клієнтський рівень представляє
користувача, який взаємодіє з платформою через веб-браузер або мобільний
додаток. Серверний рівень обробляє запити клієнта, виконує аутентифікацію
через модуль авторизації та реалізує бізнес-логіку. База даних забезпечує надійне
зберігання структурованих даних, таких як інформація про користувачів,
повідомлення та теми.
Рисунок 3.16 – Діаграма розгортання програмної системи
60
ЧДТУ 241917.005 ПЗ
3.5 Моделювання поведінки системи
Моделювання поведінки системи передбачає побудову діаграм, які
ілюструють динамічну взаємодію між компонентами, користувачами та
зовнішніми системами. Це дозволяє детально відобразити робочі процеси, логіку
виконання операцій та переходи між станами, забезпечуючи точність реалізації
функціоналу системи відповідно до вимог.
3.5.1 Діаграма діяльності
Нижче представлено діаграми діяльності для основних функцій платформи,
таких як реєстрація користувачів, створення тем і модерації повідомлень.
Діаграма діяльності, яка відображає процес реєстрації користувача (рис.
3.17), починається з відкриття сторінки реєстрації. Користувач заповнює
необхідні дані та надсилає заявку на реєстрацію. Якщо потрібне підтвердження
адміністратора, заявка переходить у стан перегляду. Адміністратор може
затвердити або відхилити обліковий запис. У разі затвердження користувач
отримує підтвердження електронною поштою. Якщо підтвердження
адміністратора не потрібне, система автоматично активує обліковий запис.
Рисунок 3.17 – Діаграма діяльності реєстрації користувача
61
ЧДТУ 241917.005 ПЗ
Діаграма діяльності, яка моделює модерацію повідомлень (рис. 3.18),
починається з надсилання повідомлення користувачем. Повідомлення переходить
у стан "очікує модерації", а адміністратор отримує сповіщення про необхідність
перевірки. Адміністратор перевіряє повідомлення на наявність порушень. Якщо
порушення відсутні, повідомлення стає видимим для інших користувачів. У разі
виявлення порушень адміністратор відхиляє повідомлення, а користувач отримує
сповіщення про причину відмови.
Рисунок 3.18 – Діаграма діяльності модерації повідомлень
Діаграма діяльності, яка описує створення теми (рис. 3.19), починається з
вибору користувачем категорії форуму. Далі користувач заповнює назву теми та її
зміст, після чого надсилає заявку на публікацію. Якщо адміністратор повинен
переглянути тему, вона переходить у стан модерації. Адміністратор затверджує
62
ЧДТУ 241917.005 ПЗ
або відхиляє тему, після чого вона публікується або видаляється. У випадку, якщо
модерація не потрібна, тема публікується автоматично.
Рисунок 3.19 – Діаграма діяльності створення теми
3.5.2 Діаграма послідовності
Було представлено три основних сценарії роботи системи: реєстрація
користувачів, створення тем та модерація повідомлень.
Процес реєстрації користувачів (рис. 3.20) починається із заповнення форми
на сторінці реєстрації. Після відправки даних вони зберігаються у базі даних зі
статусом "очікує підтвердження". Адміністратор отримує сповіщення про нову
63
ЧДТУ 241917.005 ПЗ
реєстрацію та переглядає заявку. Якщо заявка схвалена, система активує
обліковий запис і надсилає користувачу електронний лист із підтвердженням. У
разі відхилення користувач отримує повідомлення про відмову.
Рисунок 3.20 – Діаграма послідовності реєстрації користувача
Після вибору категорії форуму користувач вводить назву теми та її зміст.
Потім заявка на створення теми надсилається в базу даних із відповідним
статусом. Адміністратор отримує сповіщення про необхідність модерації та
перевіряє зміст теми. Якщо тема схвалена, статус оновлюється, і тема стає
доступною для інших користувачів. У разі відхилення користувач отримує
повідомлення про це.
64
ЧДТУ 241917.005 ПЗ
Рисунок 3.21 – Діаграма послідовності створення теми
Користувач надсилає повідомлення (рис 3.22), яке зберігається в базі даних
у статусі "очікує модерації". Адміністратор отримує сповіщення та перевіряє
зміст повідомлення. Якщо порушень немає, повідомлення стає видимим для
інших користувачів. У разі виявлення порушень повідомлення відхиляється, а
користувач отримує відповідне сповіщення.
Рисунок 3.22 – Діаграма послідовності модерації повідомлення
65
ЧДТУ 241917.005 ПЗ
3.5.3 Діаграма комунікації
Розроблено діаграму комунікації та розглянуто сценарій, пов’язаний із
пошуком та фільтрацією контенту на платформі.
Користувач взаємодіє з інтерфейсом, вводячи пошуковий запит або
встановлюючи фільтри для пошуку контенту (рис 3.23). Інтерфейс передає дані
серверу через API. Сервер обробляє запит, застосовуючи бізнес-логіку для
пошуку релевантного контенту в базі даних. База даних повертає результати, які
сервер форматує та передає назад інтерфейсу. Інтерфейс відображає результати
пошуку користувачу.
Рисунок 3.23 – Діаграма комунікації пошуку та фільтрації контенту
Основні взаємодії:
Користувач вводить запит або налаштовує фільтри через інтерфейс:
− інтерфейс надсилає API-запит на сервер для обробки пошуку;
− сервер передає запит до бази даних для виконання операції пошуку;
− база даних повертає список результатів, що відповідають заданим
критеріям;
− сервер форматує дані та надсилає їх назад до інтерфейсу;
− інтерфейс відображає результати пошуку користувачу.
3.5.4 Діаграма скінченного автомату
Розглянуто декілька ключових сценаріїв, які демонструють використання
діаграм скінченного автомату у проектуванні комунікаційної платформи.
Процес активації та блокування користувача (рис. 3.24).
66
ЧДТУ 241917.005 ПЗ
Рисунок 3.24 – Діаграмма скінченного автомату активації та блокування
користувача
У цьому сценарії користувач проходить через кілька станів: реєстрація,
очікування підтвердження, активація, блокування, видалення. Кожен стан має
відповідний набір дій, таких як підтвердження адміністратором або запит
користувача на видалення облікового запису. Переходи між станами залежать від
взаємодії користувача з адміністратором або автоматичних подій у системі.
Система підтримує кілька станів теми (рис. 3.25): створення, активна,
закрита, архівована. Тема переходить між станами через дії адміністратора,
наприклад, закриття чи архівування. Це забезпечує модерацію контенту та
організоване зберігання тем.
67
ЧДТУ 241917.005 ПЗ
Рисунок 3.25 – Діаграма скінченного автомату теми
Повідомлення, створене користувачем, проходить через стан "очікує
модерації", перш ніж стати активним. Адміністратор може або схвалити, або
відхилити повідомлення. Якщо повідомлення редагується користувачем, воно
повертається у стан "очікує модерації", доки не буде схвалене знову (рис 3.26).
68
ЧДТУ 241917.005 ПЗ
Рисунок 3.26 – Діаграма скінченного автомату повідомлення
Стан завантаження файлів включає створення файлу, очікування модерації,
схвалення чи відхилення. Система забезпечує перевірку вмісту файлів
адміністраторами перед їхнім розповсюдженням (рис 3.27).
69
ЧДТУ 241917.005 ПЗ
Рисунок 3.27 – Діаграма скінченного автомату завантаження файлів
Система забезпечує взаємодію між користувачами через повідомлення, які
можуть мати стан "надіслане", "прочитане" або "видалене". Користувачі та
отримувачі мають можливість змінювати стан повідомлень, що дозволяє гнучке
управління комунікацією (рис. 3.28).
70
ЧДТУ 241917.005 ПЗ
Рисунок 3.28 – Діаграма скінченного автомату управління повідомленнями
71
ЧДТУ 241917.005 ПЗ
Висновки до розділу 3
Було реалізовано комплексний підхід до проєктування програмного
забезпечення комунікативної платформи, що базується на результатах
теоретичних та експериментальних досліджень. Було створено моделі предметної
та робочої областей, сформовано чіткі вимоги до функціональних і
нефункціональних аспектів системи, а також розроблено ключові діаграми, які
дозволяють деталізувати процеси розробки, взаємодії та розгортання системи.
Проєктування системи було підтримано використанням діаграм класів,
компонентів, пакетів, діяльності, послідовності, комунікації та скінченних
автоматів. Це дозволило забезпечити структурований підхід до організації як
фронтенд-, так і бекенд-компонентів системи. Усі моделі враховували особливості
сучасного стеку MERN, що забезпечило максимальну продуктивність,
масштабованість та інтеграцію.
Використання діаграм діяльності та послідовності дало змогу детально
змоделювати сценарії використання системи, забезпечивши їх узгодженість із
вимогами замовника та розробника. Діаграми комунікації та скінченних автоматів
дозволили ілюструвати зв’язки між об’єктами та стани, у яких вони можуть
перебувати, що полегшує відстеження життєвого циклу ключових елементів
платформи.
Усі елементи, представлені в цьому розділі, спрямовані на підвищення
ефективності проєктування інформаційної системи, її відповідності
функціональним вимогам, а також забезпечення масштабованості та гнучкості у
подальшому впровадженні. Представлені результати підтверджують можливість
практичного використання створених моделей та підходів у реальних проєктах
розробки програмного забезпечення. Це є свідченням успішного застосування
наукових методів у контексті розв’язання прикладних задач програмування.
72
ЧДТУ 241917.005 ПЗ
4 РОЗРОБКА ПРОГРАМНОГО ЗАБЕЗПЕЧЕННЯ
4.1 Розробка програмного комплексу
Розробка програмного комплексу базується на реалізації функціональності
комунікативної платформи з використанням сучасного MERN-стеку (MongoDB,
Express.js, React.js, Node.js). Основною метою є створення системи, яка забезпечує
продуктивну взаємодію користувачів через інтуїтивно зрозумілий інтерфейс,
швидке оброблення даних і надійний захист інформації.
4.1.1 Обґрунтування вибору засобів реалізації
Основу розробки системи складає стек MERN (MongoDB, Express.js,
React.js, Node.js), який було обрано з огляду на його численні переваги. MongoDB
є NoSQL-базою даних, що забезпечує гнучкість у роботі зі структурами даних, які
постійно змінюються [1]. Це особливо важливо для комунікативної платформи, де
структура контенту може змінюватися залежно від потреб користувачів.
Express.js, у свою чергу, забезпечує просту та ефективну розробку серверної
логіки, дозволяючи зосередитися на функціональних аспектах платформи, а не на
деталях реалізації HTTP-запитів. React.js є сучасним інструментом для створення
динамічних і швидких інтерфейсів користувача, що значно покращує
користувацький досвід. Node.js, як середовище виконання JavaScript на сервері,
дозволяє використовувати одну мову програмування як для фронтенду, так і для
бекенду, спрощуючи розробку та підтримку системи.
MongoDB було обрано як основу для зберігання даних через її здатність
працювати з неструктурованими та напівструктурованими даними, що ідеально
підходить для комунікативної платформи. Її масштабованість і підтримка
горизонтального шардінгу дозволяють забезпечити стабільну роботу системи
навіть за значного навантаження. Крім того, MongoDB пропонує вбудовані
інструменти для роботи з реплікацією та резервним копіюванням, що підвищує
надійність зберігання даних.
Node.js було обрано для реалізації серверної частини через його
73
ЧДТУ 241917.005 ПЗ
продуктивність та можливість обробляти великі обсяги одночасних запитів.
Використання Node.js забезпечує низькі затримки завдяки неблокуючій моделі
вводу-виводу, що робить його ідеальним вибором для систем реального часу,
таких як комунікативні платформи [5].
Express.js є оптимальним фреймворком для створення серверної логіки
завдяки своїй мінімалістичній архітектурі та гнучкості. Це дозволяє легко
інтегрувати сторонні модулі, такі як бібліотеки для аутентифікації, логування та
обробки запитів API.
React.js, як бібліотека для створення інтерфейсу користувача, дозволяє
реалізувати динамічні веб-сторінки з використанням компоненто-орієнтованого
підходу. Це спрощує розробку, забезпечуючи модульність та повторне
використання компонентів.
Для забезпечення безперервного розгортання та тестування було обрано
сучасні хмарні сервіси, які дозволяють швидко налаштувати сервери та бази
даних. Інструменти Git та GitHub забезпечують ефективну командну роботу та
управління версіями, що є критичним для великих проєктів.
4.1.2 Опис структурної (функціональної) схеми
Розглянуто структурну схему комунікативної платформи (рис 4.1),
створеної на основі стеку MERN, яка відображає ключові елементи системи [14],
їхні функції та зв’язки між ними.
Система побудована за трирівневою архітектурою, яка включає клієнтський
рівень, серверний рівень і рівень бази даних. Кожен рівень виконує свої унікальні
функції, забезпечуючи цілісну роботу платформи.
Клієнтський рівень відповідає за взаємодію з користувачами, надаючи їм
доступ до функціональності системи через веб-інтерфейс. Інтерфейс реалізовано
на основі React.js, що дозволяє створювати інтерактивні, адаптивні та швидкі
додатки. Усі дії, такі як реєстрація, створення тем, публікація повідомлень,
здійснюються через клієнтський інтерфейс, який тісно інтегрований із сервером
через API-запити.
Серверний рівень є центральною частиною системи, яка забезпечує обробку
74
ЧДТУ 241917.005 ПЗ
запитів, управління бізнес-логікою та взаємодію з базою даних. Цей рівень
реалізовано за допомогою Node.js і Express.js, що дозволяє досягти високої
продуктивності та гнучкості. Сервер виконує функції аутентифікації
користувачів, перевірки прав доступу, обробки запитів на отримання чи зміну
даних, а також передачі результатів клієнтському інтерфейсу. Важливою
частиною серверного рівня є модерація контенту, яка дозволяє адміністраторам
перевіряти, редагувати або видаляти публікації, управляти обліковими записами
користувачів та іншими ресурсами.
Рівень бази даних забезпечує зберігання та управління всією інформацією,
необхідною для роботи системи. У проекті використовується MongoDB, що
дозволяє працювати з великими обсягами неструктурованих даних. Інформація
про користувачів, теми, повідомлення та файли організована у вигляді колекцій,
що забезпечує гнучкість структури даних та ефективність їхнього доступу.
Взаємодія між компонентами системи організована так, щоб забезпечити
чіткий розподіл обов'язків і ефективність роботи. Користувач ініціює запити через
інтерфейс, які передаються серверу для обробки. Сервер виконує необхідні дії,
взаємодіючи з базою даних, і повертає результати на клієнтський рівень для
відображення користувачу. Така організація сприяє масштабованості системи, її
адаптивності до змін та високій швидкодії.
Рисунок 4.1 – Структурна-функціональна схема основних компонентів
75
ЧДТУ 241917.005 ПЗ
4.1.3 Опис логічної схеми системи
Логічна схема системи базується на архітектурному шаблоні "Клієнт-
сервер" із використанням моделі розділення відповідальності через сучасні
компоненти стеку MERN (рис 4.2). Цей архітектурний підхід забезпечує
модульність, масштабованість, гнучкість і високу продуктивність системи [15].
Кожен шар системи відповідає за чітко визначену частину функціональності, що
дозволяє незалежно розробляти, тестувати та масштабувати окремі компоненти.
Архітектурний шаблон "Клієнт-сервер" передбачає чітке розділення між
клієнтською та серверною частинами [15]. Клієнт, реалізований на основі React.js,
виконує функції відображення інтерфейсу, обробки взаємодії користувача та
надсилання запитів до серверної частини. Серверна частина, реалізована за
допомогою Node.js та Express.js, забезпечує обробку запитів, виконання бізнес-
логіки, перевірку доступу та взаємодію з базою даних, що представлена
MongoDB.
У рамках шаблону використовується модель "трирівнева архітектура", яка
розділяє систему на три основні рівні: представлення, бізнес-логіка та дані. Рівень
представлення охоплює користувацький інтерфейс, де здійснюється взаємодія з
користувачем. Рівень бізнес-логіки виконує функції обробки даних, реалізації
процесів та перевірки прав доступу. Рівень даних зберігає та обробляє
інформацію, необхідну для роботи системи.
Ключовим елементом архітектурного підходу є REST API, яке слугує
посередником між клієнтською та серверною частинами. API дозволяє
реалізувати гнучку інтеграцію компонентів, забезпечуючи стандартизований
спосіб обміну даними між ними. Це спрощує розширення функціональності
системи та її інтеграцію з іншими платформами.
Логічна схема системи також включає модульність, яка забезпечує
розділення системи на функціональні модулі, кожен із яких виконує окрему
задачу. Наприклад, модуль аутентифікації відповідає за реєстрацію та вхід
користувачів, модуль контенту обробляє теми, повідомлення та файли, а модуль
адміністративного управління надає можливості для модерації та керування
76
ЧДТУ 241917.005 ПЗ
системою.
Використання архітектурного шаблону "Клієнт-сервер" із застосуванням
стеку MERN дозволяє досягти високого рівня адаптивності та масштабованості.
Це забезпечує ефективну обробку великої кількості одночасних запитів, спрощує
підтримку системи та сприяє її швидкому розширенню у відповідь на зміну вимог
або зростання навантаження.
Узагальнюючи, обрана архітектура поєднує в собі сучасні технології,
оптимальні підходи до розробки та перевірені шаблони проектування, що
забезпечують надійність, продуктивність і гнучкість системи. Логічна схема,
побудована на цій архітектурі, є основою для подальшого успішного
впровадження та підтримки комунікативної платформи.
Рисунок 4.2 – Логічна схема проєкту
77
ЧДТУ 241917.005 ПЗ
4.1.4 Розробка бази даних
На основі аналізу предметної області було створено логічну модель бази
даних, яка відображає всі основні сутності та їх взаємозв’язки.
База даних проекту побудована за допомогою NoSQL-сховища MongoDB,
яке забезпечує високу продуктивність, гнучкість та масштабованість.
Використання документно-орієнтованого підходу дозволяє легко змінювати
структуру даних без значних витрат на реорганізацію схеми.
Основними сутностями бази даних є:
− користувачі: Містять інформацію про профіль, історію авторизації,
статуси блокування та налаштування;
− тематика: Категорії та теми форуму, які групують контент;
− повідомлення: Основний контент, який створюється користувачами у
відповідь на теми;
− файли: Вкладення, що додаються до повідомлень або тем;
− сповіщення: Інформують користувачів про події в системі;
− модерація: Звіти про порушення та статуси перевірки.
Користувачі є центральною сутністю, оскільки саме вони взаємодіють із
системою. Вони створюють теми, публікують повідомлення, завантажують файли
та отримують сповіщення. Для забезпечення безпеки та аналітики даних система
зберігає історію авторизацій кожного користувача, а також фіксує випадки
блокування. Теми організовують контент платформи та містять основну
інформацію, таку як назва, текст та автор. Повідомлення слугують засобом
комунікації, зв’язуючи теми та користувачів. Вони можуть мати вкладення у
вигляді файлів, які також мають власну структуру.
Система передбачає можливість надсилання сповіщень користувачам для
інформування про важливі події. Окрему роль відіграють звіти про порушення,
які сприяють модерації контенту. Усі сутності мають чіткі зв’язки між собою.
Наприклад, повідомлення пов’язані з темами, а звіти – з конкретними
78
ЧДТУ 241917.005 ПЗ
повідомленнями.
Обраний формат бази даних MongoDB дозволяє ефективно працювати з
неструктурованими даними, що робить її ідеальною для цієї платформи.
Гнучкість MongoDB дозволяє легко масштабувати систему, адаптуватися до змін
у структурі даних та обробляти великі обсяги запитів без втрати продуктивності
[4]. Взаємозв’язки між сутностями визначені таким чином, щоб забезпечити
цілісність і ефективність роботи всієї системи (рис 4.3).
Рисунок 4.3 – Діаграма-модель «сутність-зв'язок»
79
ЧДТУ 241917.005 ПЗ
4.1.5 Розробка інтерфейсу користувача
Основним завданням при реалізації інтерфейсу було створення сучасного,
адаптивного та динамічного середовища, яке відповідає технічним вимогам
платформи (рис 4.4 – 4.7).
Інтерфейс користувача побудовано на основі React.js, який дозволяє
реалізовувати компонентно-орієнтовану архітектуру [7]. Кожна функціональна
частина інтерфейсу реалізована у вигляді незалежного компонента, що спрощує
підтримку, повторне використання та масштабування. Наприклад, компоненти
для роботи з формами (реєстрація, авторизація), списками тем, повідомленнями та
панеллю адміністратора мають чітко визначені межі відповідальності.
Однією з ключових технічних особливостей є використання бібліотеки
React Router для управління навігацією. Ця бібліотека дозволяє реалізувати
маршрутизацію на клієнтському рівні без перезавантаження сторінок,
забезпечуючи плавність переходів між розділами платформи. Для обробки форм
та керування станом використовуються React Hook Form і Context API, які
спрощують роботу з даними, забезпечують їхню валідність та інтеграцію з
сервером.
Динамічність інтерфейсу досягається за допомогою інтерактивних
елементів, таких як модальні вікна, випадаючі списки та анімовані переходи. Для
цього використовуються бібліотеки Material-UI та React Transition Group, які
надають інструменти для створення сучасного дизайну та плавної взаємодії.
Усі взаємодії з сервером реалізовані через API-запити. Axios
використовується як бібліотека для роботи з HTTP-запитами, що дозволяє
обробляти відповіді серверу, включаючи помилки, та забезпечувати відповідний
зворотний зв'язок для користувача. Наприклад, якщо запит на авторизацію
завершується невдачею, система показує відповідне повідомлення.
Адаптивність інтерфейсу забезпечується використанням CSS Grid та
Flexbox, що дозволяє коректно відображати контент на різних пристроях.
Breakpoints, визначені в стилях, гарантують, що інтерфейс залишатиметься
зручним на екранах від смартфонів до широкоформатних моніторів.
80
ЧДТУ 241917.005 ПЗ
Для забезпечення безпеки інтерфейсу впроваджено механізми захисту від
XSS-атак та CSRF-загроз. Наприклад, усі введені користувачами дані проходять
попередню обробку та валідність перед надсиланням на сервер.
Інтерфейс підтримує багатомовність, що реалізовано за допомогою
бібліотеки i18next. Це дозволяє користувачам обирати мову інтерфейсу та
автоматично відображати контент відповідно до їхніх уподобань.
Технічна складова розробки інтерфейсу користувача орієнтована на
продуктивність, адаптивність та зручність підтримки. Використання сучасних
бібліотек і технологій дозволила створити швидкий, інтерактивний і безпечний
інтерфейс, який задовольняє потреби користувачів і відповідає сучасним
стандартам веб-розробки.
Рисунок 4.4 – Користувацький інтерфейс треду
81
ЧДТУ 241917.005 ПЗ
Рисунок 4.5 – Користувацький інтерфейс системи сповіщень
Рисунок 4.6 – Користувацький інтерфейс особистих повідомлень
82
ЧДТУ 241917.005 ПЗ
Рисунок 4.7 - Користувацький інтерфейс створення треду
4.1.6 Опис розробки програмних компонентів
Розробка програмних компонентів системи базується на архітектурному
підході, який розділяє функціональність на незалежні, але взаємодіючі модулі.
83
ЧДТУ 241917.005 ПЗ
Кожен компонент виконує чітко визначену задачу, що дозволяє забезпечити
модульність, повторне використання та спрощення підтримки. Компоненти
системи поділені на клієнтські (frontend) та серверні (backend), кожен із яких
розроблений із використанням сучасних технологій.
Серверна частина системи реалізована на платформі Node.js із
використанням фреймворку Express.js. Основні компоненти серверної частини
включають API, модуль бізнес-логіки, модуль аутентифікації та модерації.
API-компонент відповідає за обробку HTTP-запитів, що надходять від
клієнтської частини. Кожен маршрут API реалізує певний функціонал, такий як
авторизація, робота з темами, обробка повідомлень або завантаження файлів.
Наприклад, маршрут POST /login виконує перевірку облікових даних користувача
через модуль аутентифікації та повертає токен доступу.
Модуль бізнес-логіки забезпечує виконання основних процесів системи,
таких як створення тем, перевірка прав доступу, управління повідомленнями та
сповіщеннями. Цей компонент взаємодіє з базою даних через спеціальні сервіси,
які абстрагують запити до MongoDB. Наприклад, при створенні нової теми бізнес-
логіка викликає сервіс зберігання, який записує дані до відповідної колекції в базі
даних.
Модуль аутентифікації реалізує механізм перевірки облікових даних,
генерації токенів доступу (JWT) та забезпечує захист ресурсів [16]. Він
інтегрується з компонентом бізнес-логіки для перевірки прав доступу
користувачів.
Модуль модерації відповідає за обробку скарг, блокування користувачів та
керування контентом. Наприклад, при надходженні звіту про порушення цей
модуль створює запис у базі даних, інформує адміністратора та забезпечує
інструменти для вирішення ситуації.
Клієнтська частина побудована за допомогою React.js. Вона складається з
окремих компонентів, кожен з яких відповідає за конкретний елемент інтерфейсу.
Компонентно-орієнтована архітектура дозволяє легко змінювати дизайн і
функціональність окремих частин системи.
84
ЧДТУ 241917.005 ПЗ
Компоненти форми забезпечують взаємодію з користувачами для збору
даних, таких як авторизація, реєстрація або створення нових тем. Вони
інтегровані з валідаторами, які перевіряють введені дані перед надсиланням їх на
сервер.
Компоненти відображення контенту відповідають за рендеринг списків тем,
повідомлень і вкладень. Вони використовують стан додатка, керований через
Context API або Redux, для забезпечення синхронізації між різними частинами
інтерфейсу.
Модуль управління повідомленнями надає інструменти для створення,
редагування та видалення контенту. Цей компонент взаємодіє із сервером через
Axios, забезпечуючи плавну інтеграцію між клієнтом і бекендом.
Модуль сповіщень дозволяє відображати повідомлення про важливі події в
системі. Він реалізований через WebSocket-з’єднання, що забезпечує роботу в
реальному часі.
Всі програмні компоненти системи пов’язані між собою через API.
Клієнтські компоненти надсилають запити на сервер, де обробка запитів
виконується бізнес-логікою. Серверні компоненти взаємодіють із базою даних
через драйвер MongoDB, забезпечуючи швидкий доступ до даних. Це розділення
обов’язків дозволяє підтримувати чіткість структури системи та забезпечує її
надійність і масштабованість.
4.2 Тестування системи
Тестування системи охоплює перевірку функціональності, інтеграції,
продуктивності та відповідності заявленим вимогам. Проведено модульне
тестування окремих компонентів, інтеграційне тестування для перевірки взаємодії
між ними, системне тестування, яке оцінює стабільність роботи всієї платформи, а
також приймальне тестування. Тестування підтвердило коректність реалізації
функцій, безпеку даних і готовність системи до реального використання.
4.2.1 Модульне тестування
Модульне тестування є важливим етапом забезпечення якості програмного
85
ЧДТУ 241917.005 ПЗ
забезпечення. Воно спрямоване на перевірку роботи окремих модулів системи в
ізольованому середовищі [17]. У межах тестування кожен модуль перевіряється
на відповідність функціональним вимогам та коректну обробку як нормальних,
так і граничних випадків. Це дозволяє виявити помилки на ранніх етапах
розробки, спрощуючи подальшу інтеграцію компонентів і знижуючи ризик
виникнення системних збоїв.
У системі, що розробляється, модульне тестування зосереджено на
серверній частині, де реалізовано основну бізнес-логіку, а також на утилітарних
функціях. Для реалізації тестів використовувалися бібліотеки Mocha[18] та
Chai[19], які забезпечують зручний інструментарій для написання тестів і
перевірки очікуваних результатів. У тестах використовувалися мок-об'єкти та
шпигуни (spies) для симуляції поведінки компонентів, що дозволило зосередитися
на перевірці внутрішньої логіки кожного модуля.
Нижче наведу декілька проведених модульних тестувань.
Тестування authController.js. Тести для методів register та login перевіряють
коректність роботи з базою даних, обробку помилок та генерування токенів
доступу (рис 4.8).
const { expect } = require('chai');
const sinon = require('sinon');
const { register, login } = require('../controllers/authController');
const User = require('../models/User');
describe('authController', () => {
describe('register', () => {
it('should register a new user and return access token', async () => {
const req = {
body: {
username: 'testuser',
email: '[email protected]',
password: 'password123'
86
ЧДТУ 241917.005 ПЗ
}
};
const res = {
json: sinon.spy()
};
const next = sinon.spy();
sinon.stub(User.prototype, 'save').resolves({ _id: 'userId' });
await register(req, res, next);
expect(res.json.calledOnce).to.be.true;
User.prototype.save.restore();
});
});
describe('login', () => {
it('should login user and return access token', async () => {
const req = {
body: {
username: 'testuser',
password: 'password123'
}
};
const res = {
json: sinon.spy()
};
const next = sinon.spy();
sinon.stub(User, 'findOne').resolves({
isValidPassword: () => true,
_id: 'userId'
});
await login(req, res, next);
87
ЧДТУ 241917.005 ПЗ
expect(res.json.calledOnce).to.be.true;
User.findOne.restore();
});
Рисунок 4.8 – Результат тестування authController.js
Тестування generalController.js Методи контролера, такі як getStats,
перевіряють правильність формування відповідей і взаємодію з базою даних (рис
4.9).
const { expect } = require('chai');
const sinon = require('sinon');
const { getStats } = require('../controllers/generalController');
const User = require('../models/User');
const Board = require('../models/Board');
describe('generalController', () => {
describe('getStats', () => {
it('should return statistics', async () => {
const req = {};
const res = {
json: sinon.spy()
};
const next = sinon.spy();
sinon.stub(User, 'countDocuments').resolves(10);
88
ЧДТУ 241917.005 ПЗ
sinon.stub(Board, 'countDocuments').resolves(5);
await getStats(req, res, next);
expect(res.json.calledOnce).to.be.true;
expect(res.json.firstCall.args[0]).to.deep.include.members([
{ _id: 1, title: 'Users', count: 10 },
{ _id: 2, title: 'Boards', count: 5 }
]);
User.countDocuments.restore();
Board.countDocuments.restore();
});
});
});
Рисунок 4.9 – Результат тестування generalController.js
Тестування утилітарних функцій. Утилітарні функції перевіряються на
коректність обробки вхідних даних та повернення результатів (рис 4.10).
const { expect } = require('chai');
const { counter, formatBytes } = require('../utils/Utils');
describe('Utils', () => {
describe('counter', () => {
it('should format numbers correctly', () => {
expect(counter(500)).to.equal(500);
89
ЧДТУ 241917.005 ПЗ
expect(counter(1500)).to.equal('1.5K');
expect(counter(1e6)).to.equal('1.0M');
});
});
describe('formatBytes', () => {
it('should format bytes correctly', () => {
expect(formatBytes(1024)).to.equal('1 Kb');
expect(formatBytes(1048576)).to.equal('1 Mb');
});
});
});
Рисунок 4.10 – Результат тестування Utils.js
Результати модульного тетстування представлено в таблиці 4.1.
Таблиця 4.1
Результати модульного тестування
Модуль Тестована Очікуваний результат Результат
функція тесту
authController.js Логін Користувач успішно Успішно
користувача авторизується
authController.js Реєстрація Новий користувач Успішно
користувача створений
90
ЧДТУ 241917.005 ПЗ
Продовження таблиці 4.1
forumController.js Створення Тему створено у базі Успішно
теми даних
messagesController. Надсилання Повідомлення Успішно
js повідомлення збережено у базі
profileController.js Оновлення Дані профілю оновлено Успішно
профілю
користувача
uploadsController.js Завантаження Файл успішно Успішно
файлу збережено на сервері
generalController.js Отримання Дані успішно Успішно
списку даних повертаються
Utils.js Валідація Дані валідовані без Успішно
даних помилок
4.2.2 Інтеграційне тестування
Інтеграційне тестування стало ключовим етапом перевірки системи, під час
якого перевіряється взаємодія між окремими компонентами. Цей вид тестування
дозволив переконатися, що модулі, які успішно пройшли модульне тестування,
коректно функціонують у складі цілісної системи. Особлива увага приділялася
перевірці обміну даними між клієнтською та серверною частинами, а також між
сервером та базою даних.
Для інтеграційного тестування платформи, розробленої на основі стеку
MERN, було створено середовище, яке максимально відображає реальні умови
використання. Це включає розгортання серверної частини на локальному сервері,
підключення до тестової бази даних MongoDB та емуляцію роботи клієнтської
частини через автоматизовані запити. Таке середовище дозволило тестувати не
тільки функціональність окремих частин системи, але й відповідність результатів
запитів вимогам, які ставляться до кожного компоненту.
91
ЧДТУ 241917.005 ПЗ
Однією з головних задач інтеграційного тестування була перевірка
коректності роботи API. Це включає оцінку того, наскільки чітко сервер обробляє
запити, забезпечує відповідність структур даних, переданих між клієнтом і
сервером, та виконує необхідні перевірки даних, зокрема валідацію,
аутентифікацію та авторизацію. Запити, що надходять на сервер, тестуються на
відповідність до встановлених стандартів, таких як HTTP-коди відповіді,
структура JSON-відповідей та коректність обробки помилкових даних.
Особлива увага приділялася тестуванню сценаріїв, які передбачають
взаємодію між кількома модулями серверної частини. Для забезпечення
аутентифікації користувачів перевірялася взаємодія між модулем авторизації та
бізнес-логікою. При цьому особливий акцент приділено перевірці роботи з
токенами доступу, які є основою безпеки системи. Сервер має коректно
створювати, перевіряти та відкликати токени в реальному часі, забезпечуючи
доступ тільки до дозволених ресурсів.
Важливим етапом інтеграційного тестування була перевірка взаємодії
серверної частини з базою даних. Тестувалися як операції створення, читання,
оновлення та видалення (CRUD), так і робота з великими обсягами даних.
Наприклад, для перевірки роботи пошуку в базі даних створювався великий набір
тестових записів, що дозволяє оцінити швидкодію запитів, коректність обробки
фільтрів і сортування.
Інтеграційне тестування також охопило сценарії, пов'язані з паралельною
обробкою запитів, перевіркою обмежень доступу до ресурсів та стійкістю системи
до високих навантажень. Наприклад, тестувалися сценарії одночасного створення
кількох тем або повідомлень кількома користувачами. Це дозволило перевірити,
чи коректно система обробляє конкурентні запити, уникаючи колізій і
забезпечуючи цілісність даних.
Результати інтеграційного тестування показали, що компоненти системи
взаємодіють відповідно до заданих вимог (таблиця 4.2). Запити API обробляються
коректно, дані в базі зберігаються та оновлюються без помилок, а клієнтська
частина успішно взаємодіє із сервером. У процесі тестування були виявлені
92
ЧДТУ 241917.005 ПЗ
незначні помилки, пов'язані з форматом деяких відповідей сервера та валідацією
даних, які були оперативно виправлені.
Завдяки інтеграційному тестуванню вдалося перевірити функціональність
системи у комплексі, що забезпечило її готовність до впровадження та
подальшого тестування у реальних умовах. Це дозволяє гарантувати, що
платформа функціонуватиме стабільно, ефективно обробляючи запити
користувачів та відповідаючи їхнім потребам.
Таблиця 4.2
Результати інтеграційного тестування
Результат
Компонент 1 Компонент 2 Очікуваний результат
тесту
Фронтенд API Дані передаються Успішно
коректно
Фронтенд База даних Дані зберігаються у базі Успішно
API База даних Запит до бази повертає Успішно
коректні дані
API Система Повідомлення успішно Успішно
повідомлень доставлене
4.2.3 Системне тестування
У рамках системного тестування платформи були перевірені всі її
компоненти як у взаємодії, так і в ізольованому середовищі, що дозволило
виявити недоліки на рівні інтеграції функцій, продуктивності та загальної
стабільності системи.
Функціональне тестування було зосереджено на перевірці всіх ключових
сценаріїв використання системи, таких як реєстрація користувачів, створення тем
93
ЧДТУ 241917.005 ПЗ
і повідомлень, завантаження та перегляд файлів, а також управління контентом
адміністраторами. Кожен сценарій був ретельно перевірений на відповідність
очікуваним результатам.
Під час тестування реєстрації користувачів перевірялося, чи створюється
новий запис у базі даних, чи отримує користувач відповідне повідомлення про
успішну реєстрацію, та чи коректно працюють валідаційні механізми. Аналогічно,
при перевірці створення тем і повідомлень тестувалися такі аспекти, як швидкість
обробки запиту, коректність відображення створеного контенту на клієнтському
рівні, та наявність записів у базі даних.
Нефункціональне тестування включало перевірку продуктивності, безпеки
та стійкості системи. Для оцінки продуктивності використовувалися
спеціалізовані інструменти, які емулювали високе навантаження на систему,
зокрема паралельні запити від кількох сотень користувачів. Це дозволило
оцінити, як система поводиться під час пікових навантажень, та визначити
можливі "вузькі місця".
Безпекові перевірки були зосереджені на оцінці стійкості до поширених
загроз, таких як SQL-ін’єкції, атаки типу XSS (міжсайтовий скриптинг) та CSRF
(міжсайтові запити підробки). Система успішно пройшла всі перевірки,
демонструючи здатність захищати дані користувачів і забезпечувати їхню
конфіденційність.
Стійкість системи перевірялася шляхом імітації відключення серверів,
некоректного завершення роботи клієнта та інших несприятливих умов. Усі
критичні функції системи залишилися працездатними після відновлення роботи, а
користувачі не втратили доступу до своїх даних.
Системне тестування показало, що платформа повністю відповідає
функціональним і нефункціональним вимогам. Усі ключові сценарії виконуються
без помилок, а продуктивність системи відповідає заявленим параметрам навіть
під значним навантаженням. Виявлені незначні недоліки, такі як некоректне
відображення окремих елементів інтерфейсу на мобільних пристроях, були
оперативно виправлені.
94
ЧДТУ 241917.005 ПЗ
Система продемонструвала високий рівень безпеки та стійкості,
забезпечуючи захист даних і стабільну роботу за умов реального використання.
Завдяки системному тестуванню вдалося підтвердити готовність платформи до
розгортання в реальному середовищі та використання кінцевими користувачами.
Нижче в таблиці 4.3 наведено результати системного тестування.
Таблиця 4.3
Результати системного тестування
Результат
Функція Очікуваний результат
тесту
Реєстрація користувача Новий обліковий запис створено Успішно
Авторизація Користувач авторизується Успішно
Створення теми обговорення Тему успішно додано Успішно
Завантаження файлу Файл завантажено на сервер Успішно
4.2.4 Приймальне тестування
Приймальне тестування стало завершальним етапом перевірки програмного
забезпечення перед його впровадженням у реальне середовище. Основна мета
цього етапу полягала у визначенні відповідності системи заявленим вимогам
замовника, перевірці її готовності до експлуатації та підтвердженні, що продукт
відповідає очікуванням кінцевих користувачів.
Основною задачею цього етапу є перевірка працездатності всієї системи як
єдиного цілого. Важливо переконатися, що всі компоненти, від бази даних до
клієнтської частини, працюють узгоджено, коректно виконуючи свої завдання.
Особливу увагу приділяється перевірці функціональних і нефункціональних
вимог.
Приймальне тестування проводилося у тестовому середовищі, яке
максимально відображає умови роботи у виробничому середовищі. Всі перевірки
95
ЧДТУ 241917.005 ПЗ
виконувалися за заздалегідь визначеними сценаріями, що охоплюють ключові
функції системи. Наприклад, тестування реєстрації та авторизації перевіряло
коректність створення нового користувача, передачу токенів доступу та
обмеження для невірних даних.
Додатково була виконана перевірка системи на стійкість до потенційних
збоїв, таких як некоректні запити, відсутність підключення до бази даних та інші
сценарії, які могли б вплинути на роботу системи.
Усі основні сценарії використання системи були успішно виконані.
Реєстрація нового користувача, створення тем, додавання повідомлень і
завантаження файлів працюють відповідно до вимог. Тести підтвердили, що
сервер коректно обробляє як стандартні, так і некоректні запити, надаючи
відповідні повідомлення про помилки.
Особлива увага приділялася тестуванню ролей і прав доступу.
Адміністратор мав змогу виконувати дії модерації та управління системою, тоді
як звичайні користувачі мали доступ лише до функцій, що відповідають їхній
ролі.
Приймальне тестування показало, що всі компоненти системи працюють
узгоджено та відповідають специфікаціям. Система стабільно функціонує навіть
за умов високого навантаження або некоректних дій користувачів. Всі заявлені
функції реалізовані відповідно до вимог, а нефункціональні параметри, такі як
швидкість роботи та стійкість до збоїв, відповідають очікуванням (таблиця 4.4).
Таблиця 4.4
Результати приймального тестування
Критерій Очікуваний результат Результат тесту
Зручність інтерфейсу Інтерфейс інтуїтивно зрозумілий Успішно
Продуктивність Час відповіді < 1 секунди Успішно
Безпека Захист даних реалізовано Успішно
Функціональність Функції виконують заявлені дії Успішно
96
ЧДТУ 241917.005 ПЗ
4.3 Приклади впровадженого програмного комплексу
Розроблений програмний комплекс є багатофункціональною
комунікативною платформою, що демонструє високу функціональність,
продуктивність і зручність для кінцевих користувачів. Система побудована з
використанням сучасних технологій і підходів до розробки, що забезпечує її
надійність і масштабованість.
Користувачі можуть створювати облікові записи, авторизуватися та брати
участь у обговоренні, створюючи нові теми, додаючи коментарі та файли.
Інтерфейс платформи є адаптивним, що дозволяє зручно працювати з нею як на
настільних комп’ютерах, так і на мобільних пристроях. Під час реєстрації система
перевіряє коректність введених даних і гарантує унікальність облікових записів.
Авторизація базується на токенах доступу, що забезпечує надійний захист даних.
Управління контентом реалізовано через категорії та теми, які дозволяють
структурувати інформацію та забезпечувати швидкий доступ до неї. Теми можна
доповнювати текстом і вкладеними файлами, що робить платформу зручною для
обговорення різноманітних питань.
Модерація виконується адміністраторами через спеціально створений
інтерфейс. Це дозволяє швидко обробляти скарги на порушення, блокувати
користувачів, які порушують правила, та здійснювати загальний контроль за
порядком у спільноті.
Функція сповіщень забезпечує інформування користувачів про нові
коментарі, відповіді на теми або інші важливі події. Система автоматично
надсилає повідомлення користувачам у реальному часі, що робить взаємодію з
платформою динамічною та зручною.
Система була впроваджена у тестове середовище, де перевірялися її
функції. Використання тестової бази даних дозволило перевірити операції зі
створення, читання, оновлення та видалення даних. Серверна частина успішно
взаємодіяла з клієнтським інтерфейсом, забезпечуючи стабільну роботу API.
Інтеграція основних модулів системи відбулася без критичних помилок, а
продуктивність платформи відповідала очікуванням.
Система демонструє високу адаптивність до змін і нових вимог, дозволяючи
97
ЧДТУ 241917.005 ПЗ
легко додавати нові функції без значного перегляду існуючої архітектури. Це
робить платформу готовою до використання як у невеликих спільнотах, так і в
масштабних проектах із високими вимогами до продуктивності та
масштабованості. Впровадження програмного комплексу підтверджує його
ефективність, стабільність і готовність до подальшого використання.
98
ЧДТУ 241917.005 ПЗ
Висновки до розділу 4
Було розглянуто ключові аспекти реалізації комунікативної платформи,
включаючи вибір засобів розробки, проектування бази даних, побудову
інтерфейсу користувача та програмних компонентів, а також тестування
створеного програмного забезпечення. В результаті реалізовано систему, що
відповідає сучасним вимогам до функціональності, продуктивності, безпеки та
зручності використання.
Розробка бази даних базувалася на використанні MongoDB, яка забезпечила
гнучкість у роботі з неструктурованими даними, а також високу продуктивність і
масштабованість. У процесі проєктування бази були враховані всі ключові
сутності платформи, включаючи користувачів, теми, повідомлення, файли та інші
елементи. Це дозволило створити ефективну модель даних, яка забезпечує
цілісність і узгодженість інформації.
Інтерфейс користувача розроблено з використанням React.js, що дало змогу
реалізувати адаптивний та динамічний дизайн. Інтерактивні компоненти
забезпечили зручність використання платформи на різних пристроях, а
використання сучасних бібліотек і технологій зробило інтерфейс швидким і
легким у підтримці.
Програмні компоненти системи були реалізовані із застосуванням
модульного підходу, що дозволило створити чітко структуровану архітектуру.
Серверна частина, побудована на Node.js і Express.js, забезпечила стабільну
роботу бізнес-логіки та взаємодію з базою даних через API. Використання JSON
Web Token (JWT) для аутентифікації користувачів підвищило безпеку доступу до
ресурсів.
Тестування системи включало модульне, інтеграційне, системне та
приймальне тестування. Усі етапи були успішно виконані, що підтвердило
коректність роботи окремих компонентів і їх інтеграцію в єдину платформу.
Система продемонструвала високу продуктивність, стійкість до збоїв і
відповідність заявленим вимогам.
99
ЧДТУ 241917.005 ПЗ
ЗАГАЛЬНІ ВИСНОВКИ
Кваліфікаційна робота магістра була виконана з метою розробки сучасної
комунікативної платформи, яка відповідає високим вимогам до продуктивності,
гнучкості, масштабованості та безпеки. Основна ідея полягала в аналізі,
обґрунтуванні вибору і практичному застосуванні стеку MERN (MongoDB,
Express.js, React, Node.js) для створення програмного забезпечення, яке здатне
забезпечити якісний користувацький досвід і відповідати сучасним стандартам
інженерії програмного забезпечення.
Соціальна цінність цієї роботи полягає у покращенні доступу до інформації
та створенні середовища для відкритої комунікації. Платформа може бути
використана в освітніх проєктах для організації навчальних обговорень, у
громадських ініціативах для підтримки суспільного діалогу, або в корпоративних
середовищах для забезпечення ефективної внутрішньої комунікації.
У результаті роботи було розроблено функціональну комунікативну
платформу, яка надає користувачам можливість створювати облікові записи,
керувати контентом, публікувати повідомлення, отримувати сповіщення та
користуватися інструментами модерації. Використання React.js дозволило
створити адаптивний і динамічний інтерфейс користувача, Node.js і Express.js
забезпечили надійну серверну логіку та швидку обробку запитів, а MongoDB
стала базою для гнучкого зберігання і обробки неструктурованих даних.
Проведений аналіз існуючих технологій та альтернативних стеків розробки
підтвердив переваги MERN у контексті швидкості розробки, простоти інтеграції
компонентів і підтримки високих навантажень. У ході роботи було детально
розглянуто переваги MERN у порівнянні зі стеками MEAN та LAMP, що стало
основою для обґрунтування його вибору. Результати підтвердили, що MERN є
оптимальним вибором для створення сучасних комунікативних платформ завдяки
його продуктивності, гнучкості та масштабованості.
Архітектура платформи побудована на основі модульного підходу, що
забезпечує чітке розділення функцій між компонентами, спрощує підтримку та
забезпечує можливість масштабування системи. Проектування бази даних
100
ЧДТУ 241917.005 ПЗ
охопило всі основні сутності, що дозволило досягти узгодженості даних і їхньої
доступності для різних функціональних модулів.
Особливу увагу було приділено тестуванню програмного забезпечення.
Модульне, інтеграційне, системне та приймальне тестування підтвердили
стабільність роботи системи, її продуктивність і відповідність функціональним
вимогам. Тестування також показало, що платформа здатна обробляти значні
навантаження, забезпечуючи стабільну і коректну роботу.
Розроблену платформу було впроваджено у тестове середовище, що дало
змогу перевірити її функціональність у реальних умовах. Усі компоненти —
інтерфейс користувача, серверна частина та база даних — успішно взаємодіяли
між собою, демонструючи готовність до практичного застосування.
Ця робота досягла своєї мети, підтвердивши доцільність використання стеку
MERN для розробки сучасних комунікативних платформ. Отримані результати
можуть бути використані для подальшого вдосконалення таких платформ, а також
для вирішення аналогічних задач у галузі розробки інтерактивного програмного
забезпечення. Створена система демонструє високий потенціал для використання
в освітніх, корпоративних та громадських організаціях, що підтверджує її
практичну цінність.
101
ЧДТУ 241917.005 ПЗ
СПИСОК ВИКОРИСТАНИХ ДЖЕРЕЛ
1 MERN Stack Guide - [Електронний ресурс] - Режим доступу:
https://www.mongodb.com/languages/mern-stack-tutorial
2 MEAN Stack - [Електронний ресурс] - Режим доступу:
https://www.mongodb.com/resources/languages/mean-stack
3 LAMP Stack - [Електронний ресурс] - Режим доступу:
https://aws.amazon.com/what-is/lamp-stack/
4 MongoDB Documentation - [Електронний ресурс] - Режим доступу:
https://www.mongodb.com/docs
5 Node.js Official Documentation - [Електронний ресурс] - Режим доступу:
https://nodejs.org/en/docs
6 Express.js Guide - [Електронний ресурс] - Режим доступу:
https://expressjs.com/en/guide/routing.html
7 React Official Documentation - [Електронний ресурс] - Режим доступу:
https://reactjs.org/docs
8 Модель предметної області - [Електронний ресурс] - Режим доступу:
https://uk.wikipedia.org/wiki/Модель_предметної_області
9 Аналіз вимог – [Електронний ресурс] - Режим доступу:
https://uk.wikipedia.org/wiki/Аналіз_вимог
10 Діаграма прецендентів - [Електронний ресурс] - Режим доступу:
https://uk.wikipedia.org/wiki/Діаграма_прецедентів
11 Діаграма класів - [Електронний ресурс] - Режим доступу:
https://uk.wikipedia.org/wiki/Діаграма_класів
12 Діаграма пакетів - [Електронний ресурс] - Режим доступу:
https://uk.wikipedia.org/wiki/Діаграма_пакетів
13 Діаграма розгортання - [Електронний ресурс] - Режим доступу:
https://uk.wikipedia.org/wiki/Діаграма_розгортання
14 Структурна схема - [Електронний ресурс] - Режим доступу:
https://uk.wikipedia.org/wiki/Структурна_схема
15 Клієнт-серверна архітектура - [Електронний ресурс] - Режим доступу:
102
ЧДТУ 241917.005 ПЗ
https://uk.wikipedia.org/wiki/Клієнт-серверна_архітектура
16 JSON Web Token - [Електронний ресурс] - Режим доступу: https://jwt.io/
17 Модульне тестування - [Електронний ресурс] - Режим доступу:
https://uk.wikipedia.org/wiki/Модульне_тестування
18 Mocha - [Електронний ресурс] - Режим доступу:
https://github.com/mochajs/mocha
19 Chai - [Електронний ресурс] - Режим доступу: https://github.com/chaijs/chai
20 Інтеграційне тестування - [Електронний ресурс] - Режим доступу:
https://uk.wikipedia.org/wiki/Інтеграційне_тестування
21 Системне тестування - [Електронний ресурс] - Режим доступу:
https://uk.wikipedia.org/wiki/Системне_тестування
22 Приймальне тестування - [Електронний ресурс] - Режим доступу:
https://uk.wikipedia.org/wiki/Приймальне_тестування
23 Mathur, R. (2024). MEAN vs MERN vs MEVN vs LAMP Stack for
Development. - [Електронний ресурс] - Режим доступу:
https://www.arkasoftwares.com/blog/mean-vs-mern-vs-mevn-vs-lamp-stack-for-
development
24 Airbrake. (2022). Comparing Popular Web Stacks: MERN, MEAN, MEVN,
MENG, LAMP, and Ruby on Rails. - [Електронний ресурс] - Режим доступу:
https://blog.airbrake.io/comparing-popular-web-stacks-mern-mean-mevn-meng-
lamp-and-ruby-on-rails
25 Remotely. (2024). LAMP vs. MEAN/MERN: Choosing the Right Dev Stack. -
[Електронний ресурс] - Режим доступу:
https://www.remotely.works/blog/lamp-vs-mean-mern-which-development-stack-
is-right-for-you
26 Методичні рекомендації до підготовки кваліфікаційної роботи магістра для
здобувачів вищої освіти зі спеціальності 121 «Інженерія програмного
забезпечення» усіх форм навчання [Текст] /Укл.: Голуб С.В., Заспа Г.О.,
Півень О.Б. Катаєва Є.Ю., Салапатов В.І., Метелап В.В., Олексюк В.В.; М-
во освіти і науки України.
103
ЧДТУ 241917.005 ПЗ
27 MongoDB Security Best Practices - [Електронний ресурс] - Режим доступу:
https://www.mongodb.com/security
28 Fowler M. Patterns of Enterprise Application Architecture [Текст] / M. Fowler. –
Addison-Wesley Professional, 2002.
29 Martin R.C. Clean Architecture: A Craftsman’s Guide to Software Structure and
Design [Текст] / R.C. Martin. – Prentice Hall, 2017.
30 Crockford D. JavaScript: The Good Parts [Текст] / D. Crockford. – O’Reilly
Media, 2008.
104
ДОДАТОК А
ЗАТВЕРДЖЕНО:
Зав. кафедри ПЗАС
проф. Голуб С. В.
___________________________
ТЕХНОЛОГІЧНІ ОСОБЛИВОСТІ РОЗРОБКИ ПРОГРАМНОГО
ЗАБЕЗПЕЧЕННЯ КОМУНІКАТИВНИХ ПЛАТФОРМ
Специфікація
482.ЧДТУ.231917 ПЗ
Листів 1
Розробник ________________ Золотоверхий А.Я.
Керівник ________________ Немченко В.В.
Черкаси 2024
Позначення Найменування Примітка
482.ЧДТУ.242317 12-01 Лістинг програми
482.ЧДТУ.232317 34-01 Інструкція користувача
482.ЧДТУ.232317 90-01 Графічні матеріали
106
ДОДАТОК Б
ТЕХНОЛОГІЧНІ ОСОБЛИВОСТІ РОЗРОБКИ ПРОГРАМНОГО
ЗАБЕЗПЕЧЕННЯ КОМУНІКАТИВНИХ ПЛАТФОРМ
Лістинг програми
ЧДТУ.231917 12-01
Листів 46
Розробник ________________ Золотоверхий А.Я.
Черкаси 2024
482. ЧДТУ.231917 12-01
FileUploadForm.js
import { Fragment, useContext, useEffect, useState } from 'react';
import { StoreContext } from 'store/Store';
import { Strings, imageTypes, fileExt } from 'support/Constants';
import FileInput from './FileInput';
const FileUploadForm = ({ mini, title, hint, sendFiles, clearFiles, multiple
= true, accept }) => {
const { lang } = useContext(StoreContext)
const [files, setFiles] = useState([])
const [inputVisible, setInputVisible] = useState(true)
const maxCount = multiple ? 4 : 1
useEffect(() => {
if (clearFiles) {
setFiles([])
setInputVisible(true)
}
if (files.length > 0) {
sendFiles && sendFiles(files)
} else {
setInputVisible(true)
}
}, [files, sendFiles, clearFiles])
useEffect(() => {
document.addEventListener('paste', handlePaste)
return () => {
document.removeEventListener('paste', handlePaste)
}
})
const handlePaste = (e) => {
if (files.length >= maxCount) return
const newFile = e.clipboardData.files[0]
if (!newFile || newFile.type.indexOf('image') === -1) return
const mergedArray = [...files, newFile]
let limitedArray = mergedArray.slice(0, maxCount)
limitedArray.map(i => i.url = URL.createObjectURL(i))
setFiles(limitedArray)
setInputVisible(false)
}
const handleFile = (e) => {
108
482. ЧДТУ.231917 12-01
if (files.length >= maxCount) return
const newFiles = e.target.files
const newFilesArray = Array.from(newFiles)
const mergedArray = [...files, ...newFilesArray]
let limitedArray = mergedArray.slice(0, maxCount)
limitedArray.map(i => i.url = URL.createObjectURL(i))
setFiles(limitedArray)
setInputVisible(false)
}
const removeFile = (file) => {
setFiles(files.filter(i => i.url !== file.url))
sendFiles(files.filter(i => i.url !== file.url))
}
return (
!mini ? (
<div className={files.length ? 'card_item attach_list' : 'card_item'}>
{files && (
files.map((item, index) => (
<Fragment key={index}>
{imageTypes.find(i => i === item.type) ? (
<div className="attached_file card_left" style={{
backgroundImage: `url(${item.url})` }}>
<span className="remove_file" onClick={() =>
removeFile(item)}>
<i className="bx bx-x" />
</span>
</div>
) : (
<div className="attached_file card_left empty">
<span className="remove_file" onClick={() =>
removeFile(item)}>
<i className="bx bx-x" />
</span>
<div
className="attached_info">{fileExt.exec(item.name)[1]}</div>
</div>
)}
</Fragment>
))
)}
{inputVisible && (
<div className="card_body file_input_body">
<div className="card_outside_title with_hint">
{title || Strings.attachFile[lang]}
<div className="title_hint">
109
482. ЧДТУ.231917 12-01
<i className="bx bx-help-circle" />
<div className="hint_popover">
{hint || `${Strings.maxFilesCount[lang]}: 4;
${Strings.maxSize[lang]}: 20 Mb ${Strings.perFile[lang]}`}
</div>
</div>
</div>
<div className="form_block">
<FileInput
onChange={handleFile}
multiple={multiple}
accept={accept}
disabled={files.length >= maxCount}
/>
</div>
</div>
)}
</div>
) : (
<Fragment>
{files.length ? (
<div className="card_item attach_list">
{files && (
files.map((item, index) => (
<Fragment key={index}>
{imageTypes.find(i => i === item.type) ? (
<div className="attached_file card_left" style={{
backgroundImage: `url(${item.url})` }}>
<span className="remove_file" onClick={() =>
removeFile(item)}>
<i className="bx bx-x" />
</span>
</div>
) : (
<div className="attached_file card_left empty">
<span className="remove_file" onClick={() =>
removeFile(item)}>
<i className="bx bx-x" />
</span>
<div
className="attached_info">{fileExt.exec(item.name)[1]}</div>
</div>
)}
</Fragment>
))
)}
</div>
) : null}
110
482. ЧДТУ.231917 12-01
<input
id="miniFileInput"
type="file"
className="miniFileInput"
multiple={multiple}
accept={accept}
onChange={handleFile}
disabled={files.length >= maxCount}
/>
<label htmlFor="miniFileInput" className="message_action_item
send_file" title={Strings.chooseAFile[lang]}>
<i className="bx bx-paperclip" />
</label>
</Fragment>
)
)
}
export default FileUploadForm;
forumController.js
const path = require('path');
const { Types } = require('mongoose');
const createError = require('http-errors');
const multer = require('multer');
const User = require('../models/User');
const Board = require('../models/Board');
const Thread = require('../models/Thread');
const Answer = require('../models/Answer');
const Notification = require('../models/Notification');
const deleteFiles = require('../utils//deleteFiles');
const { checkFileExec, videoTypes } = require('../utils/checkFileExec');
const storage = require('../utils/storage');
const createThumb = require('../utils/createThumbnail');
const upload = multer({
storage: storage('forum', 'attach'),
fileFilter: (req, file, callback) => checkFileExec(file, callback),
limits: { fields: 1, fileSize: 1048576 * 20 } // 20Mb
}).array('attach', 4) // 20 * 4 = 80Mb
module.exports.getBoards = async (req, res, next) => {
try {
const { limit = 10, page = 1, sort, pagination = true } = req.query
111
482. ЧДТУ.231917 12-01
let boards
if (sort === 'popular') {
boards = await Board.paginate({}, { sort: { threadsCount: -1,
answersCount: -1 }, page, limit, pagination: JSON.parse(pagination) })
} else if (sort === 'answersCount') {
boards = await Board.paginate({}, { sort: { answersCount: -1 }, page,
limit, pagination: JSON.parse(pagination) })
} else if (sort === 'newestThread') {
boards = await Board.paginate({}, { sort: { newestThread: -1 }, page,
limit, pagination: JSON.parse(pagination) })
} else if (sort === 'newestAnswer') {
boards = await Board.paginate({}, { sort: { newestAnswer: -1 }, page,
limit, pagination: JSON.parse(pagination) })
} else {
boards = await Board.paginate({}, { sort: { position: -1 }, page,
limit, pagination: JSON.parse(pagination) })
}
res.json(boards)
} catch(err) {
next(createError.InternalServerError(err))
}
}
module.exports.getBoard = async (req, res, next) => {
try {
const { name, boardId } = req.query
let board
if (name) {
board = await Board.findOne({ name })
} else if (boardId) {
board = await Board.findById(boardId)
} else {
return next(createError.BadRequest('Board name or boardId must not be
empty'))
}
res.json(board)
} catch(err) {
next(createError.InternalServerError(err))
}
}
module.exports.createBoard = async (req, res, next) => {
try {
const { name, title, body, position } = req.body
const admin = req.payload.role === 3
112
482. ЧДТУ.231917 12-01
if (!admin) return next(createError.Unauthorized('Action not allowed'))
if (name.trim() === '') return next(createError.BadRequest('Board name
must not be empty'))
if (title.trim() === '') return next(createError.BadRequest('Board title
must not be empty'))
if (!position || !Number.isInteger(position) || position < 0) return
next(createError.BadRequest('Position must be number'))
const nameUrl = name.trim().toLowerCase().substring(0, 12).replace(/[^a-
z0-9-_]/g, '')
const nameExist = await Board.findOne({ name: nameUrl })
if (nameExist) return next(createError.Conflict('Board with this short
name is already been created'))
const newBoard = new Board({
name: nameUrl,
title: title.trim().substring(0, 21),
body: body.substring(0, 100),
position,
createdAt: new Date().toISOString(),
threadsCount: 0,
answersCount: 0
})
const board = await newBoard.save()
res.json(board)
} catch(err) {
next(createError.InternalServerError(err))
}
}
module.exports.deleteBoard = async (req, res, next) => {
try {
const { boardId } = req.body
const admin = req.payload.role === 3
if (!admin) return next(createError.Unauthorized('Action not allowed'))
if (!boardId) return next(createError.BadRequest('boardId must not be
empty'))
const board = await Board.findById(boardId)
await board.delete()
res.json({ message: 'Board successfully deleted' })
} catch(err) {
next(createError.InternalServerError(err))
113
482. ЧДТУ.231917 12-01
}
}
module.exports.editBoard = async (req, res, next) => {
try {
const { boardId, name, title, body, position } = req.body
const admin = req.payload.role === 3
if (!admin) return next(createError.Unauthorized('Action not allowed'))
if (!boardId) return next(createError.BadRequest('boardId must not be
empty'))
if (name.trim() === '') return next(createError.BadRequest('Board name
must not be empty'))
if (title.trim() === '') return next(createError.BadRequest('Board title
must not be empty'))
if (!position || !Number.isInteger(position) || position < 0) return
next(createError.BadRequest('Position must be number'))
const nameUrl = name.trim().toLowerCase().substring(0, 12).replace(/[^a-
z0-9-_]/g, '')
const nameExist = await Board.findOne({ name: nameUrl })
if (nameExist) return next(createError.Conflict('Board with this short
name is already been created'))
await Board.updateOne({ _id: Types.ObjectId(boardId) }, {
name: nameUrl,
title: title.trim().substring(0, 21),
body: body.substring(0, 100),
position
})
const board = await Board.findById(boardId)
res.json(board)
} catch(err) {
next(createError.InternalServerError(err))
}
}
module.exports.getRecentlyThreads = async (req, res, next) => {
try {
const { limit = 10, page = 1 } = req.query
const populate = [{
path: 'author',
select: '_id name displayName onlineAt picture role ban'
}, {
path: 'likes',
select: '_id name displayName picture'
114
482. ЧДТУ.231917 12-01
}]
const threads = await Thread.paginate({}, { sort: { pined: -1,
newestAnswer: -1, createdAt: -1 }, page, limit, populate })
res.json(threads)
} catch(err) {
next(createError.InternalServerError(err))
}
}
module.exports.getThreads = async (req, res, next) => {
try {
const { boardId, limit = 10, page = 1, sort } = req.query
if (!boardId) return next(createError.BadRequest('boardId must not be
empty'))
const populate = [{
path: 'author',
select: '_id name displayName onlineAt picture role ban'
}, {
path: 'likes',
select: '_id name displayName picture'
}]
let threads
if (sort === 'answersCount') {
threads = await Thread.paginate({ boardId }, { sort: { pined: -1,
answersCount: -1 }, page, limit, populate })
} else if (sort === 'newestAnswer') {
threads = await Thread.paginate({ boardId }, { sort: { pined: -1,
newestAnswer: -1 }, page, limit, populate })
} else {
threads = await Thread.paginate({ boardId }, { sort: { pined: -1,
createdAt: -1 }, page, limit, populate })
}
res.json(threads)
} catch(err) {
next(createError.InternalServerError(err))
}
}
module.exports.getThread = async (req, res, next) => {
try {
const { threadId } = req.query
if (!threadId) return next(createError.BadRequest('threadId must not be
empty'))
115
482. ЧДТУ.231917 12-01
const populate = [{
path: 'author',
select: '_id name displayName onlineAt picture role ban'
}, {
path: 'likes',
select: '_id name displayName picture'
}]
const thread = await Thread.findById(threadId).populate(populate)
const board = await Board.findById(thread.boardId).select('_id name
title')
res.json({ board, thread })
} catch(err) {
next(createError.InternalServerError(err))
}
}
module.exports.createThread = async (req, res, next) => {
try {
upload(req, res, async (err) => {
if (err) return next(createError.BadRequest(err.message))
const { boardId, title, body } = JSON.parse(req.body.postData)
if (!boardId) return next(createError.BadRequest('boardId must not be
empty'))
if (title.trim() === '') return next(createError.BadRequest('Thread
title must not be empty'))
if (body.trim() === '') return next(createError.BadRequest('Thread body
must not be empty'))
const now = new Date().toISOString()
let files = null
if (req.files.length) {
files = []
await Promise.all(req.files.map(async (item) => {
if (videoTypes.find(i => i === item.mimetype)) {
const thumbFilename =
item.filename.replace(path.extname(item.filename), '.jpg')
const thumbnail = await createThumb(item.path, 'forum',
thumbFilename)
files.push({
file: `/forum/${item.filename}`,
thumb: `/forum/thumbnails/${thumbnail}`,
type: item.mimetype,
size: item.size
116
482. ЧДТУ.231917 12-01
})
} else {
files.push({
file: `/forum/${item.filename}`,
thumb: null,
type: item.mimetype,
size: item.size
})
}
}))
}
const newThread = new Thread({
boardId,
pined: false,
closed: false,
title: title.trim().substring(0, 100),
body: body.substring(0, 1000),
createdAt: now,
author: req.payload.id,
newestAnswer: now,
attach: files
})
const thread = await newThread.save()
await Board.updateOne({ _id: Types.ObjectId(boardId) }, { $inc: {
threadsCount: 1 }, newestThread: now })
await User.updateOne({ _id: Types.ObjectId(req.payload.id) }, { $inc: {
karma: 5 } })
res.json(thread)
})
} catch(err) {
next(createError.InternalServerError(err))
}
}
module.exports.deleteThread = async (req, res, next) => {
try {
const { threadId } = req.body
const moder = req.payload.role >= 2
if (!moder) return next(createError.Unauthorized('Action not allowed'))
if (!threadId) return next(createError.BadRequest('threadId must not be
empty'))
const thread = await Thread.findById(threadId).populate({ path: 'author',
select: 'role' })
117
482. ЧДТУ.231917 12-01
if (!thread.author) {
thread.author = {
role: 1
}
}
if (req.payload.role < thread.author.role) return
next(createError.Unauthorized('Action not allowed'))
if (thread.attach && thread.attach.length) {
const files = thread.attach.reduce((array, item) => {
if (item.thumb) {
return [
...array,
path.join(__dirname, '..', '..', '..', 'public', 'forum',
path.basename(item.file)),
path.join(__dirname, '..', '..', '..', 'public', 'forum',
'thumbnails', path.basename(item.thumb))
]
}
return [
...array,
path.join(__dirname, '..', '..', '..', 'public', 'forum',
path.basename(item.file))
]
}, [])
deleteFiles(files, (err) => {
if (err) console.error(err)
})
}
const answers = await Answer.find({ threadId: Types.ObjectId(threadId) })
const answersCount = answers.length
await Promise.all(answers.map(async (item) => {
const answer = await Answer.findById(item._id)
if (answer.attach && answer.attach.length) {
const files = answer.attach.reduce((array, item) => {
if (item.thumb) {
return [
...array,
path.join(__dirname, '..', '..', '..', 'public', 'forum',
path.basename(item.file)),
path.join(__dirname, '..', '..', '..', 'public', 'forum',
'thumbnails', path.basename(item.thumb))
]
}
118
482. ЧДТУ.231917 12-01
return [
...array,
path.join(__dirname, '..', '..', '..', 'public', 'forum',
path.basename(item.file))
]
}, [])
deleteFiles(files, (err) => {
if (err) console.error(err)
})
}
await answer.delete()
}))
await thread.delete()
await Board.updateOne({ _id: Types.ObjectId(thread.boardId) }, {
$inc: {
threadsCount: -1,
answersCount: -answersCount
}
})
res.json({ message: 'Thread successfully deleted' })
req.io.to('thread:' + threadId).emit('threadDeleted', { id: threadId })
} catch(err) {
next(createError.InternalServerError(err))
}
}
module.exports.clearThread = async (req, res, next) => {
try {
const { threadId } = req.body
const moder = req.payload.role >= 2
if (!moder) return next(createError.Unauthorized('Action not allowed'))
if (!threadId) return next(createError.BadRequest('threadId must not be
empty'))
const thread = await Thread.findById(threadId).populate({ path: 'author',
select: 'role' })
if (!thread.author) {
thread.author = {
role: 1
}
119
482. ЧДТУ.231917 12-01
}
if (req.payload.role < thread.author.role) return
next(createError.Unauthorized('Action not allowed'))
const answers = await Answer.find({ threadId: Types.ObjectId(threadId) })
const answersCount = answers.length
await Promise.all(answers.map(async (item) => {
const answer = await Answer.findById(item._id)
if (answer.attach && answer.attach.length) {
const files = answer.attach.reduce((array, item) => {
if (item.thumb) {
return [
...array,
path.join(__dirname, '..', '..', '..', 'public', 'forum',
path.basename(item.file)),
path.join(__dirname, '..', '..', '..', 'public', 'forum',
'thumbnails', path.basename(item.thumb))
]
}
return [
...array,
path.join(__dirname, '..', '..', '..', 'public', 'forum',
path.basename(item.file))
]
}, [])
deleteFiles(files, (err) => {
if (err) console.error(err)
})
}
await answer.delete()
}))
await Thread.updateOne({ _id: Types.ObjectId(threadId) }, { answersCount:
0 })
await Board.updateOne({ _id: Types.ObjectId(thread.boardId) }, { $inc: {
answersCount: -answersCount } })
res.json({ message: 'Thread successfully cleared' })
req.io.to('thread:' + threadId).emit('threadCleared', { id: threadId })
} catch(err) {
next(createError.InternalServerError(err))
}
}
120
482. ЧДТУ.231917 12-01
module.exports.editThread = async (req, res, next) => {
try {
upload(req, res, async (err) => {
if (err) return next(createError.BadRequest(err.message))
const { threadId, title, body, closed } = JSON.parse(req.body.postData)
if (!threadId) return next(createError.BadRequest('threadId must not be
empty'))
if (title.trim() === '') return next(createError.BadRequest('Thread
title must not be empty'))
if (body.trim() === '') return next(createError.BadRequest('Thread body
must not be empty'))
const thread = await Thread.findById(threadId).populate({ path:
'author', select: 'role' })
if (!thread.author) {
thread.author = {
role: 1
}
}
if (req.payload.id !== thread.author._id) {
if (req.payload.role < thread.author.role) {
return next(createError.Unauthorized('Action not allowed'))
}
}
if (req.files.length && thread.attach && thread.attach.length) {
const files = thread.attach.reduce((array, item) => {
if (item.thumb) {
return [
...array,
path.join(__dirname, '..', '..', '..', 'public', 'forum',
path.basename(item.file)),
path.join(__dirname, '..', '..', '..', 'public', 'forum',
'thumbnails', path.basename(item.thumb))
]
}
return [
...array,
path.join(__dirname, '..', '..', '..', 'public', 'forum',
path.basename(item.file))
]
}, [])
deleteFiles(files, (err) => {
if (err) console.error(err)
121
482. ЧДТУ.231917 12-01
})
}
let files = thread.attach
if (req.files.length) {
files = []
await Promise.all(req.files.map(async (item) => {
if (videoTypes.find(i => i === item.mimetype)) {
const thumbFilename =
item.filename.replace(path.extname(item.filename), '.jpg')
await createThumb(item.path, 'forum', thumbFilename)
files.push({
file: `/forum/${item.filename}`,
thumb: `/forum/thumbnails/${thumbFilename}`,
type: item.mimetype,
size: item.size
})
} else {
files.push({
file: `/forum/${item.filename}`,
thumb: null,
type: item.mimetype,
size: item.size
})
}
}))
}
const obj = {
title: title.trim().substring(0, 100),
body: body.substring(0, 1000),
closed: closed === undefined ? thread.closed : closed,
attach: files
}
if (closed === undefined) {
obj.edited = {
createdAt: new Date().toISOString()
}
}
await Thread.updateOne({ _id: Types.ObjectId(threadId) }, obj)
const populate = [{
path: 'author',
select: '_id name displayName onlineAt picture role ban'
}, {
path: 'likes',
122
482. ЧДТУ.231917 12-01
select: '_id name displayName picture'
}]
const editedThread = await Thread.findById(threadId).populate(populate)
res.json(editedThread)
req.io.to('thread:' + threadId).emit('threadEdited', editedThread)
})
} catch(err) {
next(createError.InternalServerError(err))
}
}
module.exports.adminEditThread = async (req, res, next) => {
try {
upload(req, res, async (err) => {
if (err) return next(createError.BadRequest(err.message))
const { threadId, title, body, pined, closed } =
JSON.parse(req.body.postData)
const moder = req.payload.role >= 2
if (!moder) return next(createError.Unauthorized('Action not allowed'))
if (!threadId) return next(createError.BadRequest('threadId must not be
empty'))
if (title.trim() === '') return next(createError.BadRequest('Board
title must not be empty'))
if (body.trim() === '') return next(createError.BadRequest('Thread body
must not be empty'))
const thread = await Thread.findById(threadId).populate({ path:
'author', select: 'role' })
if (!thread.author) {
thread.author = {
role: 1
}
}
if (req.payload.role < thread.author.role) return
next(createError.Unauthorized('Action not allowed'))
if (req.files.length && thread.attach && thread.attach.length) {
const files = thread.attach.reduce((array, item) => {
if (item.thumb) {
return [
...array,
path.join(__dirname, '..', '..', '..', 'public', 'forum',
path.basename(item.file)),
path.join(__dirname, '..', '..', '..', 'public', 'forum',
123
482. ЧДТУ.231917 12-01
'thumbnails', path.basename(item.thumb))
]
}
return [
...array,
path.join(__dirname, '..', '..', '..', 'public', 'forum',
path.basename(item.file))
]
}, [])
deleteFiles(files, (err) => {
if (err) console.error(err)
})
}
let files = thread.attach
if (req.files.length) {
files = []
await Promise.all(req.files.map(async (item) => {
if (videoTypes.find(i => i === item.mimetype)) {
const thumbFilename =
item.filename.replace(path.extname(item.filename), '.jpg')
await createThumb(item.path, 'forum', thumbFilename)
files.push({
file: `/forum/${item.filename}`,
thumb: `/forum/thumbnails/${thumbFilename}`,
type: item.mimetype,
size: item.size
})
} else {
files.push({
file: `/forum/${item.filename}`,
thumb: null,
type: item.mimetype,
size: item.size
})
}
}))
}
const obj = {
title: title.trim().substring(0, 100),
body: body.substring(0, 1000),
pined: pined === undefined ? thread.pined : pined,
closed: closed === undefined ? thread.closed : closed,
attach: files
124
482. ЧДТУ.231917 12-01
}
if (pined === undefined && closed === undefined) {
obj.edited = {
createdAt: new Date().toISOString()
}
}
await Thread.updateOne({ _id: Types.ObjectId(threadId) }, obj)
const populate = [{
path: 'author',
select: '_id name displayName onlineAt picture role ban'
}, {
path: 'likes',
select: '_id name displayName picture'
}]
const editedThread = await Thread.findById(threadId).populate(populate)
res.json(editedThread)
req.io.to('thread:' + threadId).emit('threadEdited', editedThread)
})
} catch(err) {
next(createError.InternalServerError(err))
}
}
module.exports.likeThread = async (req, res, next) => {
try {
const { threadId } = req.body
if (!threadId) return next(createError.BadRequest('threadId must not be
empty'))
const thread = await Thread.findById(threadId)
if (thread.likes.find(like => like.toString() === req.payload.id)) {
thread.likes = thread.likes.filter(like => like.toString() !==
req.payload.id) // unlike
} else {
thread.likes.push(req.payload.id) // like
}
await thread.save()
const populate = [{
path: 'author',
select: '_id name displayName onlineAt picture role ban'
}, {
path: 'likes',
125
482. ЧДТУ.231917 12-01
select: '_id name displayName picture'
}]
const likedThread = await Thread.findById(threadId).populate(populate)
res.json(likedThread)
req.io.to('thread:' + threadId).emit('threadLiked', likedThread)
} catch(err) {
next(createError.InternalServerError(err))
}
}
module.exports.getAnswers = async (req, res, next) => {
try {
const { threadId, limit = 10, page = 1, pagination = true } = req.query
if (!threadId) return next(createError.BadRequest('threadId must not be
empty'))
const populate = [{
path: 'author',
select: '_id name displayName onlineAt picture role ban'
}, {
path: 'likes',
select: '_id name displayName picture'
}]
const answers = await Answer.paginate({ threadId }, { page, limit,
populate, pagination: JSON.parse(pagination) })
res.json(answers)
} catch(err) {
next(createError.InternalServerError(err))
}
}
module.exports.createAnswer = async (req, res, next) => {
try {
upload(req, res, async (err) => {
if (err) return next(createError.BadRequest(err.message))
const { threadId, answeredTo, body } = JSON.parse(req.body.postData)
if (!threadId) return next(createError.BadRequest('threadId must not be
empty'))
if (body.trim() === '') return next(createError.BadRequest('Answer body
must not be empty'))
const now = new Date().toISOString()
126
482. ЧДТУ.231917 12-01
const thread = await Thread.findById(threadId)
let files = null
if (req.files.length) {
files = []
await Promise.all(req.files.map(async (item) => {
if (videoTypes.find(i => i === item.mimetype)) {
const thumbFilename =
item.filename.replace(path.extname(item.filename), '.jpg')
await createThumb(item.path, 'forum', thumbFilename)
files.push({
file: `/forum/${item.filename}`,
thumb: `/forum/thumbnails/${thumbFilename}`,
type: item.mimetype,
size: item.size
})
} else {
files.push({
file: `/forum/${item.filename}`,
thumb: null,
type: item.mimetype,
size: item.size
})
}
}))
}
const newAnswer = new Answer({
boardId: thread.boardId,
threadId,
answeredTo,
body: body.substring(0, 1000),
createdAt: now,
author: req.payload.id,
attach: files
})
const answer = await newAnswer.save()
await Board.updateOne({ _id: Types.ObjectId(thread.boardId) }, { $inc:
{ answersCount: 1 }, newestAnswer: now })
await Thread.updateOne({ _id: Types.ObjectId(threadId) }, { $inc: {
answersCount: 1 }, newestAnswer: now })
const populate = [{
path: 'author',
select: '_id name displayName onlineAt picture role ban'
127
482. ЧДТУ.231917 12-01
}, {
path: 'likes',
select: '_id name displayName picture'
}]
const populatedAnswer = await
Answer.findById(answer._id).populate(populate)
await User.updateOne({ _id: Types.ObjectId(req.payload.id) }, {
$inc: {
karma: populatedAnswer.author._id === req.payload.id ? 1 : 2
}
})
res.json(populatedAnswer)
req.io.to('thread:' + threadId).emit('answerCreated', populatedAnswer)
let type = 'answerToThread'
let to = thread.author
if (answeredTo && answeredTo !== threadId) {
const answerTo = await Answer.findById(answeredTo)
type = 'answerToAnswer'
to = answerTo.author
}
if (!answeredTo && req.payload.id === thread.author.toString()) return
const newNotification = new Notification({
type,
to,
from: req.payload.id,
pageId: threadId,
title: thread.title,
body: body.substring(0, 1000),
createdAt: new Date().toISOString(),
read: false
})
const notification = await newNotification.save()
const populateNotification = [{
path: 'to',
select: '_id name displayName onlineAt picture role ban'
}, {
path: 'from',
select: '_id name displayName onlineAt picture role ban'
}]
const populatedNotification = await
Notification.findById(notification._id).populate(populateNotification)
128
482. ЧДТУ.231917 12-01
req.io.to('notification:' + to).emit('newNotification',
populatedNotification)
})
} catch(err) {
next(createError.InternalServerError(err))
}
}
module.exports.deleteAnswer = async (req, res, next) => {
try {
const { answerId } = req.body
const moder = req.payload.role >= 2
if (!moder) return next(createError.Unauthorized('Action not allowed'))
if (!answerId) return next(createError.BadRequest('answerId must not be
empty'))
const answer = await Answer.findById(answerId).populate({ path: 'author',
select: 'role' })
if (!answer.author) {
answer.author = {
role: 1
}
}
if (req.payload.role < answer.author.role) return
next(createError.Unauthorized('Action not allowed'))
if (answer.attach && answer.attach.length) {
const files = answer.attach.reduce((array, item) => {
if (item.thumb) {
return [
...array,
path.join(__dirname, '..', '..', '..', 'public', 'forum',
path.basename(item.file)),
path.join(__dirname, '..', '..', '..', 'public', 'forum',
'thumbnails', path.basename(item.thumb))
]
}
return [
...array,
path.join(__dirname, '..', '..', '..', 'public', 'forum',
path.basename(item.file))
]
}, [])
deleteFiles(files, (err) => {
if (err) console.error(err)
129
482. ЧДТУ.231917 12-01
})
}
await answer.delete()
await Board.updateOne({ _id: Types.ObjectId(answer.boardId) }, { $inc: {
answersCount: -1 } })
await Thread.updateOne({ _id: Types.ObjectId(answer.threadId) }, { $inc:
{ answersCount: -1 } })
res.json({ message: 'Answer successfully deleted' })
req.io.to('thread:' + answer.threadId).emit('answerDeleted', { id:
answerId })
} catch(err) {
next(createError.InternalServerError(err))
}
}
module.exports.editAnswer = async (req, res, next) => {
try {
upload(req, res, async (err) => {
if (err) return next(createError.BadRequest(err.message))
const { answerId, body } = JSON.parse(req.body.postData)
if (!answerId) return next(createError.BadRequest('answerId must not be
empty'))
if (body.trim() === '') return next(createError.BadRequest('Answer body
must not be empty'))
const answer = await Answer.findById(answerId).populate({ path:
'author', select: 'role' })
if (!answer.author) {
answer.author = {
role: 1
}
}
if (req.payload.id === answer.author._id || req.payload.role <
answer.author.role) {
return next(createError.Unauthorized('Action not allowed'))
}
if (req.files.length && answer.attach && answer.attach.length) {
const files = answer.attach.reduce((array, item) => {
if (item.thumb) {
return [
...array,
130
482. ЧДТУ.231917 12-01
path.join(__dirname, '..', '..', '..', 'public', 'forum',
path.basename(item.file)),
path.join(__dirname, '..', '..', '..', 'public', 'forum',
'thumbnails', path.basename(item.thumb))
]
}
return [
...array,
path.join(__dirname, '..', '..', '..', 'public', 'forum',
path.basename(item.file))
]
}, [])
deleteFiles(files, (err) => {
if (err) console.error(err)
})
}
let files = answer.attach
if (req.files.length) {
files = []
await Promise.all(req.files.map(async (item) => {
if (videoTypes.find(i => i === item.mimetype)) {
const thumbFilename =
item.filename.replace(path.extname(item.filename), '.jpg')
await createThumb(item.path, 'forum', thumbFilename)
files.push({
file: `/forum/${item.filename}`,
thumb: `/forum/thumbnails/${thumbFilename}`,
type: item.mimetype,
size: item.size
})
} else {
files.push({
file: `/forum/${item.filename}`,
thumb: null,
type: item.mimetype,
size: item.size
})
}
}))
}
await Answer.updateOne({ _id: Types.ObjectId(answerId) }, {
body: body.substring(0, 1000),
edited: {
131
482. ЧДТУ.231917 12-01
createdAt: new Date().toISOString()
},
attach: files
})
const populate = [{
path: 'author',
select: '_id name displayName onlineAt picture role ban'
}, {
path: 'likes',
select: '_id name displayName picture'
}]
const editedAnswer = await Answer.findById(answerId).populate(populate)
res.json(editedAnswer)
req.io.to('thread:' + answer.threadId).emit('answerEdited',
editedAnswer)
})
} catch(err) {
next(createError.InternalServerError(err))
}
}
module.exports.likeAnswer = async (req, res, next) => {
try {
const { answerId } = req.body
if (!answerId) return next(createError.BadRequest('answerId must not be
empty'))
const answer = await Answer.findById(answerId)
if (answer.likes.find(like => like.toString() === req.payload.id)) {
answer.likes = answer.likes.filter(like => like.toString() !==
req.payload.id) // unlike
} else {
answer.likes.push(req.payload.id) // like
}
await answer.save()
const populate = [{
path: 'author',
select: '_id name displayName onlineAt picture role ban'
}, {
path: 'likes',
select: '_id name displayName picture'
}]
const likedAnswer = await Answer.findById(answerId).populate(populate)
132
482. ЧДТУ.231917 12-01
res.json(likedAnswer)
req.io.to('thread:' + answer.threadId).emit('answerLiked', likedAnswer)
} catch(err) {
next(createError.InternalServerError(err))
}
}
generalController.js
const path = require('path');
const { Types } = require('mongoose');
const createError = require('http-errors');
const User = require('../models/User');
const Board = require('../models/Board');
const Thread = require('../models/Thread');
const Answer = require('../models/Answer');
const Ban = require('../models/Ban');
const Report = require('../models/Report');
const File = require('../models/File');
const Comment = require('../models/Comment');
const Dialogue = require('../models/Dialogue');
const Message = require('../models/Message');
const AuthHistory = require('../models/AuthHistory');
const deleteFiles = require('../utils/deleteFiles');
module.exports.getStats = async (req, res, next) => {
try {
const bans = await User.find({ ban: { $ne: null } })
res.json([{
_id: 1,
title: 'Users',
count: await User.countDocuments()
}, {
_id: 2,
title: 'Boards',
count: await Board.countDocuments()
}, {
_id: 3,
title: 'Threads',
count: await Thread.countDocuments()
}, {
_id: 4,
title: 'Answers',
133
482. ЧДТУ.231917 12-01
count: await Answer.countDocuments()
}, {
_id: 5,
title: 'Bans',
count: bans.length
}, {
_id: 6,
title: 'Files',
count: await File.countDocuments()
}])
} catch(err) {
next(createError.InternalServerError(err))
}
}
module.exports.getUsers = async (req, res, next) => {
try {
const { limit = 10, page = 1, sort } = req.query
let users
const select = '_id name displayName createdAt onlineAt picture karma
role ban'
if (sort === 'online') {
const date = new Date()
date.setMinutes(date.getMinutes() - 5)
users = await User.paginate({ onlineAt: { $gte: date.toISOString() } },
{ sort: { onlineAt: -1 }, page, limit, select })
} else if (sort === 'admin') {
users = await User.paginate({ role: { $gte: 2 } }, { sort: { onlineAt:
-1 }, page, limit, select })
} else if (sort === 'old') {
users = await User.paginate({}, { sort: { createdAt: 1 }, page, limit,
select })
} else if (sort === 'karma') {
users = await User.paginate({}, { sort: { karma: -1, onlineAt: -1 },
page, limit, select })
} else {
users = await User.paginate({}, { sort: { createdAt: -1 }, page, limit,
select })
}
res.json(users)
} catch(err) {
next(createError.InternalServerError(err))
}
}
module.exports.getAdmins = async (req, res, next) => {
try {
134
482. ЧДТУ.231917 12-01
const { limit = 10, page = 1 } = req.query
const select = '_id name displayName createdAt onlineAt picture role ban'
const admins = await User.paginate({ role: { $gte: 2 } }, { sort: {
createdAt: -1 }, page, limit, select })
res.json(admins)
} catch(err) {
next(createError.InternalServerError(err))
}
}
module.exports.getUser = async (req, res, next) => {
try {
const { userName } = req.query
if (!userName) return next(createError.BadRequest('userName must not be
empty'))
const select = '_id name displayName createdAt onlineAt picture karma
role ban'
const populate = {
path: 'ban',
select: '_id admin reason body createdAt expiresAt',
populate: {
path: 'admin',
select: '_id name displayName onlineAt picture role'
}
}
const user = await User.findOne({ name: userName },
select).populate(populate)
if (!user) return next(createError.BadRequest('User not found'))
if (user.ban) {
if (user.ban.expiresAt < new Date().toISOString()) {
await User.updateOne({ _id: Types.ObjectId(user._id) }, { ban: null
})
user.ban = null
}
}
res.json(user)
} catch(err) {
next(createError.InternalServerError(err))
}
}
module.exports.getBans = async (req, res, next) => {
135
482. ЧДТУ.231917 12-01
try {
const { limit = 10, page = 1, sort } = req.query
let bans
if (sort === 'all') {
const populate = [{
path: 'user',
select: '_id name displayName onlineAt picture role ban'
}, {
path: 'admin',
select: '_id name displayName onlineAt picture role'
}]
bans = await Ban.paginate({}, { sort: { createdAt: -1 }, page, limit,
populate })
} else {
const select = '_id name displayName createdAt onlineAt picture role
ban'
const populate = {
path: 'ban',
select: '_id admin reason body createdAt expiresAt',
populate: {
path: 'admin',
select: '_id name displayName onlineAt picture role'
}
}
bans = await User.paginate({ ban: { $ne: null } }, { page, limit,
select, populate })
}
res.json(bans)
} catch(err) {
next(createError.InternalServerError(err))
}
}
module.exports.getUserBans = async (req, res, next) => {
try {
const { userId, limit = 10, page = 1 } = req.query
if (!userId) return next(createError.BadRequest('userId must not be
empty'))
const populate = [{
path: 'user',
select: '_id name displayName onlineAt picture role ban'
}, {
path: 'admin',
select: '_id name displayName onlineAt picture role'
}]
136
482. ЧДТУ.231917 12-01
const bans = await Ban.paginate({ user: userId }, { sort: { createdAt: -1
}, page, limit, populate })
res.json(bans)
} catch(err) {
next(createError.InternalServerError(err))
}
}
module.exports.getBan = async (req, res, next) => {
try {
const { userId } = req.query
if (!userId) return next(createError.BadRequest('userId must not be
empty'))
const select = '_id name displayName createdAt onlineAt picture role ban'
const populate = {
path: 'ban',
select: '_id admin reason body createdAt expiresAt',
populate: {
path: 'admin',
select: '_id name displayName onlineAt picture role'
}
}
const user = await User.findOne({ _id: Types.ObjectId(userId) },
select).populate(populate)
res.json(user)
} catch(err) {
next(createError.InternalServerError(err))
}
}
module.exports.createBan = async (req, res, next) => {
try {
const { userId, reason, body = '', expiresAt } = req.body
const moder = req.payload.role >= 2
if (!moder) return next(createError.Unauthorized('Action not allowed'))
if (!userId) return next(createError.BadRequest('userId must not be
empty'))
if (reason.trim() === '') return next(createError.BadRequest('Reason must
not be empty'))
if (!expiresAt) return next(createError.BadRequest('expiresAt must not be
empty'))
const user = await User.findById(userId).select('role')
137
482. ЧДТУ.231917 12-01
if (!user) return next(createError.BadRequest('User not found'))
if (req.payload.role < user.role) return
next(createError.Unauthorized('Action not allowed'))
const now = new Date().toISOString()
const newBan = new Ban({
user: userId,
admin: req.payload.id,
reason,
body: body.substring(0, 100),
createdAt: now,
expiresAt
})
const ban = await newBan.save()
const diff = new Date(expiresAt) - new Date(now)
const minutes = diff / 60000
await User.updateOne({ _id: Types.ObjectId(userId) }, { $inc: { karma:
minutes > 43799 ? -50 : -20 }, ban: ban._id })
res.json(ban)
req.io.to('notification:' + userId).emit('ban', ban)
} catch(err) {
next(createError.InternalServerError(err))
}
}
module.exports.unBan = async (req, res, next) => {
try {
const { userId } = req.body
const moder = req.payload.role >= 2
if (!moder) return next(createError.Unauthorized('Action not allowed'))
if (!userId) return next(createError.BadRequest('userId must not be
empty'))
await User.updateOne({ _id: Types.ObjectId(userId) }, { $inc: { karma: 10
}, ban: null })
res.json('User unbanned')
req.io.to('banned:' + userId).emit('unban', { message: 'Unbanned' })
} catch(err) {
next(createError.InternalServerError(err))
}
}
138
482. ЧДТУ.231917 12-01
module.exports.deleteBan = async (req, res, next) => {
try {
const { banId } = req.body
const moder = req.payload.role >= 2
if (!moder) return next(createError.Unauthorized('Action not allowed'))
if (!banId) return next(createError.BadRequest('banId must not be
empty'))
const ban = await Ban.findById(banId)
await ban.delete()
res.json('Ban successfully deleted')
} catch(err) {
next(createError.InternalServerError(err))
}
}
module.exports.getUserStats = async (req, res, next) => {
try {
const { userId } = req.query
if (!userId) return next(createError.BadRequest('userId must not be
empty'))
const user = await User.findById(userId)
if (!user) return next(createError.BadRequest('User not found'))
const threads = await Thread.find({ author: Types.ObjectId(userId) })
const answers = await Answer.find({ author: Types.ObjectId(userId) })
const bans = await Ban.find({ user: Types.ObjectId(userId) })
const files = await File.find({ author: Types.ObjectId(userId) })
const comments = await Comment.find({ author: Types.ObjectId(userId) })
res.json({
threadsCount: threads.length,
answersCount: answers.length,
bansCount: bans.length,
filesCount: files.length,
fileCommentsCount: comments.length,
karma: user.karma
})
} catch(err) {
next(createError.InternalServerError(err))
}
}
139
482. ЧДТУ.231917 12-01
module.exports.getUserThreads = async (req, res, next) => {
try {
const { userId, limit = 10, page = 1 } = req.query
if (!userId) return next(createError.BadRequest('userId must not be
empty'))
const populate = [{
path: 'author',
select: '_id name displayName onlineAt picture role ban'
}, {
path: 'likes',
select: '_id name displayName picture'
}]
const threads = await Thread.paginate({ author: userId }, { sort: {
createdAt: -1 }, page, limit, populate })
res.json(threads)
} catch(err) {
next(createError.InternalServerError(err))
}
}
module.exports.getUserAnswers = async (req, res, next) => {
try {
const { userId, limit = 10, page = 1 } = req.query
if (!userId) return next(createError.BadRequest('userId must not be
empty'))
const populate = [{
path: 'author',
select: '_id name displayName onlineAt picture role ban'
}, {
path: 'likes',
select: '_id name displayName picture'
}]
const answers = await Answer.paginate({ author: userId }, { sort: {
createdAt: -1 }, page, limit, populate })
res.json(answers)
} catch(err) {
next(createError.InternalServerError(err))
}
}
module.exports.getAuthHistory = async (req, res, next) => {
try {
const { userId, limit = 10, page = 1 } = req.query
140
482. ЧДТУ.231917 12-01
const moder = req.payload.role >= 2
if (!userId) return next(createError.BadRequest('userId must not be
empty'))
if (req.payload.id !== userId ) {
if (!moder) {
return next(createError.Unauthorized('Action not allowed'))
}
}
const populate = {
path: 'user',
select: '_id name displayName onlineAt picture role ban'
}
const authHistory = await AuthHistory.paginate({ user: userId }, { sort:
{ loginAt: -1 }, page, limit, populate })
res.json(authHistory)
} catch(err) {
next(createError.InternalServerError(err))
}
}
module.exports.searchAuthHistory = async (req, res, next) => {
try {
const { ip, limit = 10, page = 1 } = req.query
const moder = req.payload.role >= 2
if (!moder) return next(createError.Unauthorized('Action not allowed'))
if (!ip) return next(createError.BadRequest('ip must not be empty'))
const populate = {
path: 'user',
select: '_id name displayName onlineAt picture role ban'
}
const authHistory = await AuthHistory.paginate(
{ $text: { $search: ip } },
{ sort: { ip: -1, ua: -1, loginAt: -1 }, page, limit, populate }
)
res.json(authHistory)
} catch(err) {
next(createError.InternalServerError(err))
}
}
module.exports.getReports = async (req, res, next) => {
try {
const { limit = 10, page = 1, sort } = req.query
141
482. ЧДТУ.231917 12-01
const moder = req.payload.role >= 2
if (!moder) return next(createError.Unauthorized('Action not allowed'))
const populate = {
path: 'from',
select: '_id name displayName onlineAt picture role ban'
}
const read = sort === 'read' ? { read: true } : { read: false }
const reports = await Report.paginate(read, { sort: { createdAt: -1 },
page, limit, populate })
if (reports.totalDocs) {
await Report.updateMany({ read: false }, { read: true })
}
res.json(reports)
} catch(err) {
next(createError.InternalServerError(err))
}
}
module.exports.createReport = async (req, res, next) => {
try {
const { threadId, postId, body } = req.body
if (!threadId) return next(createError.BadRequest('threadId must not be
empty'))
if (!postId) return next(createError.BadRequest('postId must not be
empty'))
if (body.trim() === '') return next(createError.BadRequest('Report body
must not be empty'))
const reportExist = await Report.find({ postId: Types.ObjectId(postId) })
if (reportExist.length) return next(createError.BadRequest('Report to the
post already has'))
const thread = await Thread.findById(threadId)
const newReport = new Report({
from: req.payload.id,
threadId,
postId,
title: thread.title,
body: body.substring(0, 1000),
createdAt: new Date().toISOString(),
read: false
})
const report = await newReport.save()
142
482. ЧДТУ.231917 12-01
const populate = {
path: 'from',
select: '_id name displayName onlineAt picture role ban'
}
const populatedReport = await
Report.findById(report._id).populate(populate)
res.json(populatedReport)
req.io.to('adminNotification').emit('newAdminNotification', { type:
'report' })
} catch(err) {
next(createError.InternalServerError(err))
}
}
module.exports.deleteReports = async (req, res, next) => {
try {
const moder = req.payload.role >= 2
if (!moder) return next(createError.Unauthorized('Action not allowed'))
await Report.deleteMany({ read: true })
res.json({ message: 'Reports successfully deleted' })
} catch(err) {
next(createError.InternalServerError(err))
}
}
module.exports.search = async (req, res, next) => {
try {
const { limit = 10, page = 1, query, type } = req.query
if (!query) return next(createError.BadRequest('query must not be
empty'))
const populate = [{
path: 'author',
select: '_id name displayName onlineAt picture role ban'
}, {
path: 'likes',
select: '_id name displayName picture'
}]
let results
if (type === 'answers') {
results = await Answer.paginate({ $text: { $search: query } }, { sort:
{ createdAt: -1 }, page, limit, populate })
143
482. ЧДТУ.231917 12-01
} else if (type === 'users') {
const select = '_id name displayName createdAt onlineAt picture role
ban'
results = await User.paginate({ $text: { $search: query } }, { sort: {
onlineAt: -1 }, page, limit, select })
} else if (type === 'boards') {
results = await Board.paginate({ $text: { $search: query } }, { sort: {
newestAnswer: -1 }, page, limit })
} else {
results = await Thread.paginate({ $text: { $search: query } }, { sort:
{ createdAt: -1 }, page, limit, populate })
}
res.json(results)
} catch(err) {
next(createError.InternalServerError(err))
}
}
module.exports.editRole = async (req, res, next) => {
try {
const { userId, role = 1 } = req.body
const admin = req.payload.role === 3
if (!admin) return next(createError.Unauthorized('Action not allowed'))
if (!role || !Number.isInteger(role) || role < 1) return
next(createError.BadRequest('Role must be number'))
if (!role > 2) return next(createError.BadRequest('Max role number: 2'))
if (!userId) return next(createError.BadRequest('userId must not be
empty'))
await User.updateOne({ _id: Types.ObjectId(userId) }, { role })
res.json({ message: 'User role updated' })
} catch(err) {
next(createError.InternalServerError(err))
}
}
module.exports.deleteUser = async (req, res, next) => {
try {
const { userId } = req.body
const admin = req.payload.role === 3
if (!admin) return next(createError.Unauthorized('Action not allowed'))
if (!userId) return next(createError.BadRequest('userId must not be
empty'))
const user = await User.findById(userId)
144
482. ЧДТУ.231917 12-01
await Ban.deleteMany({ user: userId })
const dialogues = await Dialogue.find({
$or: [{
to: Types.ObjectId(userId)
}, {
from: Types.ObjectId(userId)
}]
})
await Promise.all(dialogues.map(async (item) => {
const dialogue = await Dialogue.findById(item._id)
await dialogue.delete()
}))
const messages = await Message.find({
$or: [{
to: Types.ObjectId(userId)
}, {
from: Types.ObjectId(userId)
}]
})
await Promise.all(messages.map(async (item) => {
const message = await Message.findById(item._id)
if (message.file && message.file.length) {
const files = message.file.reduce((array, item) => {
if (item.thumb) {
return [
...array,
path.join(__dirname, '..', '..', '..', 'public', 'message',
path.basename(item.file)),
path.join(__dirname, '..', '..', '..', 'public', 'message',
'thumbnails', path.basename(item.thumb))
]
}
return [
...array,
path.join(__dirname, '..', '..', '..', 'public', 'message',
path.basename(item.file))
]
}, [])
deleteFiles(files, (err) => {
if (err) console.error(err)
})
}
145
482. ЧДТУ.231917 12-01
await messages.delete()
}))
await user.delete()
res.json({ message: 'User successfully deleted' })
} catch(err) {
next(createError.InternalServerError(err))
}
}
Input.js
import { useState } from 'react';
const Input = ({ type = 'text', name, value, placeholder = '', required =
false, maxLength, onChange, onFocus, onBlur }) => {
const [showPass, setShowPass] = useState(false)
return (
<>
<input
className="input_area"
type={type === 'password' ? showPass ? 'text' : 'password' : type}
name={name}
value={value}
placeholder={placeholder}
maxLength={maxLength}
required={required}
onChange={onChange}
onFocus={onFocus}
onBlur={onBlur}
/>
{type === 'password' && (
<div className="input_action" onClick={() => setShowPass(prev =>
!prev)}>
{showPass
? <i className="bx bx-show" />
: <i className="bx bx-hide" />
}
</div>
)}
</>
)
}
export default Input;
146
482. ЧДТУ.231917 12-01
authController.js
const { Types } = require('mongoose');
const createError = require('http-errors');
const { isJapanese, toRomaji } = require('wanakana');
const User = require('../models/User');
const AuthHistory = require('../models/AuthHistory');
const { registerSchema, loginSchema } = require('../utils/validationSchema');
const { signAccessToken } = require('../utils/jwt');
const toLatin = require('../utils/transliterate');
const register = async (req, res, next) => {
try {
const result = await registerSchema.validateAsync(req.body)
let name = result.username.toLowerCase().replace(/\s/g, '')
if (/[а-яА-ЯЁё]/.test(name)) {
name = toLatin(name)
}
if (isJapanese(name)) {
name = toRomaji(name)
}
const forbiddenNames = [
'admin', 'administrator', 'moder', 'moderator', 'deleted', 'user',
'test', 'qwerty', '12345', '123456789', '1234567890'
]
if (forbiddenNames.find(i => i === name)) {
throw createError.Conflict('Username is prohibited')
}
const userNamedoesExist = await User.findOne({ name })
if (userNamedoesExist) {
throw createError.Conflict('Username is already been registered')
}
const emailDoesExist = await User.findOne({ email: result.email })
if (emailDoesExist) {
throw createError.Conflict('E-mail is already been registered')
}
let displayName = result.username.replace(/\s/g, '')
const now = new Date().toISOString()
const user = new User({
name,
displayName,
147
482. ЧДТУ.231917 12-01
email: result.email,
password: result.password,
createdAt: now,
onlineAt: now
})
const savedUser = await user.save()
const accessToken = await signAccessToken(savedUser)
const authHistory = new AuthHistory({
user: savedUser._id,
loginAt: now,
ip: req.headers['x-forwarded-for'] || req.connection.remoteAddress,
ua: req.headers['user-agent']
})
await authHistory.save()
res.json({
user: {
id: savedUser._id,
name: savedUser.name,
displayName: savedUser.displayName,
picture: savedUser.picture,
role: savedUser.role
},
accessToken
})
} catch(error) {
if (error.isJoi === true) error.status = 422
next(error)
}
}
const login = async (req, res, next) => {
try {
const result = await loginSchema.validateAsync(req.body)
let name = result.username.toLowerCase().replace(/\s/g, '')
if (/[а-яА-ЯЁё]/.test(name)) {
name = toLatin(name)
}
if (isJapanese(name)) {
name = toRomaji(name)
}
const populate = {
path: 'ban',
select: '_id expiresAt',
}
const user = await User.findOne({ name }).populate(populate)
148
482. ЧДТУ.231917 12-01
if (!user) throw createError.NotFound('User not registered')
const isMatch = await user.isValidPassword(result.password)
if (!isMatch) throw createError.Unauthorized('Username or password not
valid')
const now = new Date().toISOString()
if (user.ban) {
if (user.ban.expiresAt < now) {
await User.updateOne({ _id: Types.ObjectId(user._id) }, { ban: null
})
} else {
return res.json({
ban: {
userId: user._id,
}
})
}
}
const accessToken = await signAccessToken(user)
const authHistory = new AuthHistory({
user: user._id,
loginAt: now,
ip: req.headers['x-forwarded-for'] || req.connection.remoteAddress,
ua: req.headers['user-agent']
})
await authHistory.save()
res.json({
user: {
id: user._id,
name: user.name,
displayName: user.displayName,
picture: user.picture,
role: user.role
},
accessToken
})
} catch(error) {
if (error.isJoi === true) {
return next(createError.BadRequest('Invalid username or password'))
}
next(error)
}
}
149
482. ЧДТУ.231917 12-01
module.exports = { register, login }
AuthHistory.js
const { model, Schema, Types } = require('mongoose');
const mongoosePaginate = require('mongoose-paginate-v2');
const authHistorySchema = new Schema({
user: {
type: Types.ObjectId,
ref: 'User'
},
loginAt: Date,
ip: String,
ua: String
})
authHistorySchema.plugin(mongoosePaginate)
authHistorySchema.index({ ip: 'text' })
module.exports = model('AuthHistory', authHistorySchema);
Comment.js
const { model, Schema, Types } = require('mongoose');
const mongoosePaginate = require('mongoose-paginate-v2');
const commentSchema = new Schema({
fileId: Types.ObjectId,
commentedTo: Types.ObjectId,
body: String,
createdAt: Date,
author: {
type: Types.ObjectId,
ref: 'User'
},
edited: {
createdAt: Date
},
likes: [{
type: Types.ObjectId,
ref: 'User'
}]
})
commentSchema.plugin(mongoosePaginate)
commentSchema.index({ body: 'text' })
150
482. ЧДТУ.231917 12-01
module.exports = model('Comment', commentSchema);
DataView.js
import Loader from 'components/Loader';
import Errorer from 'components/Errorer';
const DataView = ({ data, noData, loading, moreLoading, card: Card,
noDataMessage, errorMessage, lang, children }) => {
return !noData ? (
!loading ? (
data.length ? (
<>
{children}
<div className="items_list">
{data.map(item => (
<Card key={item._id} data={item} />
))}
</div>
{moreLoading && <Loader className="more_loader" color="#64707d" />}
</>
) : <Errorer message={noDataMessage} />
) : <Loader color="#64707d" />
) : <Errorer message={errorMessage} />
}
export default DataView;
Dialogue.js
const { model, Schema, Types } = require('mongoose');
const mongoosePaginate = require('mongoose-paginate-v2');
const dialogueSchema = new Schema({
from: {
type: Types.ObjectId,
ref: 'User'
},
to: {
type: Types.ObjectId,
ref: 'User'
},
lastMessage: {
type: Types.ObjectId,
ref: 'Message'
151
482. ЧДТУ.231917 12-01
},
updatedAt: Date
})
dialogueSchema.plugin(mongoosePaginate)
module.exports = model('Dialogue', dialogueSchema);
FileInput.js
import { useContext } from 'react';
import { StoreContext } from 'store/Store';
import { Strings } from 'support/Constants';
const FileInput = ({ onChange, multiple = false, accept, disabled }) => {
const { lang } = useContext(StoreContext)
return (
<div className="file_area">
<input
id="fileInput"
type="file"
multiple={multiple}
accept={accept}
onChange={onChange}
disabled={disabled}
/>
<label htmlFor="fileInput" className="file_input"
title={Strings.chooseAFile[lang]}>
<div className="secondary_btn">{Strings.choose[lang]}</div>
<span>{Strings.fileNotSelected[lang]}</span>
</label>
</div>
)
}
export default FileInput;
152
ДОДАТОК В
ТЕХНОЛОГІЧНІ ОСОБЛИВОСТІ РОЗРОБКИ ПРОГРАМНОГО
ЗАБЕЗПЕЧЕННЯ КОМУНІКАТИВНИХ ПЛАТФОРМ
Інструкція користувача
482.ЧДТУ.231917 ПЗ
Листів 6
Розробник ________________ Золотоверхий А.Я.
Черкаси 2024
482.ЧДТУ. 231917 34-01 2
1. Щоб розпочати користуватися платформою, користувач повинен перейти
до веб-застосунку через браузер. Користувач повинен створити обліковий запис,
заповнивши форму реєстрації: ввести логін, адресу електронної пошти та пароль.
Після реєстрації користувачу буде надано доступ до всіх функцій платформи. Для
входу користувач використовує дані вказані при реєстрації.
Рисунок В.1 – Сторінка створення облікового запису
2. Головна сторінка надає користувачу доступ до основних розділів через
навігаційне меню, розташоване ліворуч:
Рисунок В.2 – Навігаційне меню
482.ЧДТУ. 231917 34-01 3
3. Щоб створити тред, користувач натискає кнопку "Створити тред",
вкажіть назву, текст і виберіть відповідну дошку. Користувач може додавати
зображення та файли до тредів. Для відповіді на тред користувач заповняє форму
коментаря та натискає "Відповісти".
Рисунок В.3 – Сторінка створення треду
4. У розділі "Файли/Завантаження" користувач може додати новий файл,
вибравши відповідну папку. Після завантаження файл може бути перевірений
адміністратором перед публікацією.
482.ЧДТУ. 231917 34-01 4
Рисунок В.4 – Сторінка завантаження файлу
Рисунок В.5 – Сторінка модерації файлів
5. Профіль користувача дозволяє змінювати налаштування, включаючи
зміну пароля та завантаження аватару. Профіль також відображає активність
користувача, наприклад кількість створених тредів і відповідей.
482.ЧДТУ. 231917 34-01 5
Рисунок В.6 – Сторінка профілю користувача
6. У розділі "Повідомлення" користувач може переглядати особисті діалоги
з іншими користувачами. Сповіщення надають інформацію про нові відповіді,
коментарі або дії адміністратора.
Рисунок В.7 – Особисті повідомлення
7. Користувач може скористатися пошуковим рядком у верхньому правому
куті для швидкого пошуку тредів, відповідей або користувачів. Пошук підтримує
фільтри для точнішої видачі результатів.
482.ЧДТУ. 231917 34-01 6
Рисунок В.8 – Пошуковий рядок та сторінка відображення пошукови запитів
8. Адміністратори можуть модерувати контент, перевіряти файли, керувати
скаргами та блокуваннями, використовуючи спеціальний інтерфейс
адміністратора.
Рисунок В.9 – Панель керування адміністратора
9. Інтерфейс платформи підтримує вибір мови. Користувач має змогу
обирати потрібну мову в налаштуваннях.
Рисунок В.10 – Меню вибору мови користувацького інтерфейсу
ДОДАТОК Г
ТЕХНОЛОГІЧНІ ОСОБЛИВОСТІ РОЗРОБКИ ПРОГРАМНОГО
ЗАБЕЗПЕЧЕННЯ КОМУНІКАТИВНИХ ПЛАТФОРМ
Графічні матеріали
482.ЧДТУ.241917 90-01
Листів 10
Розробник ________________ Золотоверхий А.Я.
Черкаси 2024
482.ЧДТУ.231917 90-01 2
Рисунок Г.1 – Слайд 1
Рисунок Г.2 – Слайд 2
482.ЧДТУ.231917 90-01 3
Рисунок Г.3 – Слайд 3
Рисунок Г.4 – Слайд 4
482.ЧДТУ.231917 90-01 4
Рисунок Г.5 – Слайд 5
Рисунок Г.6 – Слайд 6
482.ЧДТУ.231917 90-01 5
Рисунок Г.7 – Слайд 7
Рисунок Г.8 – Слайд 8
482.ЧДТУ.231917 90-01 6
Рисунок Г.9 – Слайд 9
Рисунок Г.10 – Слайд 10
482.ЧДТУ.231917 90-01 7
Рисунок Г.11 – Слайд 11
Рисунок Г.12 – Слайд 12
482.ЧДТУ.231917 90-01 8
Рисунок Г.13 – Слайд 13
Рисунок Г.14 – Слайд 14
482.ЧДТУ.231917 90-01 9
Рисунок Г.14 – Слайд 15
Рисунок Г.16 – Слайд 16
482.ЧДТУ.231917 90-01 10
Рисунок Г.17 – Слайд 17
Рисунок Г.18 – Слайд 18