Курсова робота (2 курс) — Java-версія
Цей проєкт — система автоматизації бібліотечного фонду, розроблена на мові програмування Java 17 з використанням бази даних PostgreSQL. Система забезпечує ефективне управління бібліотечними ресурсами: книгами, читачами, бібліотеками, бібліотекарями та статистикою відвідувань.
Інтерфейс розроблено для двох типів користувачів: бібліотекарів, які здійснюють основну діяльність з обробки даних, та адміністраторів, які мають повний доступ до функцій керування системою.
Консольний UI побудований на Lanterna — Java-аналозі бібліотеки ftxui, яку використовує оригінальна C++ версія цього проєкту: кольорові кнопки, рамки, прокручувані списки, навігація стрілками/Tab/Enter і повноцінний клік мишею.
Пароль і логін БД винесено з коду в конфігурацію (db.properties / змінні середовища) — див. розділ ⚙️ Налаштування підключення до БД.
Раніше Main читав LIBRARY_DB_URL/LIBRARY_DB_USER/LIBRARY_DB_PASSWORD напряму зі змінних середовища зі значеннями за замовчуванням, прописаними прямо в коді. Тепер цим займається окремий клас com.libcode.library.config.DbConfig: він читає ті самі змінні середовища (для Docker — без змін), а якщо їх немає — локальний файл db.properties (шаблон — db.properties.example, сам файл у .gitignore, тож реальний пароль ніколи не потрапляє в репозиторій), і лише як останній fallback — вбудовані значення за замовчуванням.
Звіти (System Statistics / Query Results) більше не дублюються у файл — показуються тільки у власному вікні застосунку.
Раніше ExtendFeatures/PostgresOutput, окрім показу звіту у вікні, ще й записували той самий вміст у output.txt/statistics.txt "про всяк випадок" — жодна частина застосунку ці файли назад не читала, тож це було просто дублювання того, що й так видно на екрані. Метод IDBOutput.writeToFile() перейменовано на display(), файловий запис прибрано, output.txt/statistics.txt більше не створюються.
Звіти (System Statistics / Query Results) показуються у власному вікні застосунку, а не в зовнішньому текстовому редакторі.
Раніше ExtendFeatures/PostgresOutput записували результат у файл і намагалися відкрити його через SystemTextEditor (Notepad на Windows, java.awt.Desktop/системний редактор на Linux). У мінімальному Docker/noVNC-оточенні (Xvfb + fluxbox, без встановленого текстового редактора) це мовчки не спрацьовувало, а fallback друкував текст у справжній stdout процесу — невидимий у вікні noVNC. Тепер обидва місця малюють звіт напряму через новий com.libcode.library.ui.ReportWindow — те саме вікно Lanterna/Swing, що й решта UI, тож воно завжди видиме там, де видимий сам застосунок. Клас SystemTextEditor видалено як більше не потрібний.
Заразом виправлено дві незручності самого ReportWindow:
- Прокрутка стрілками не працювала, якщо вміст не вміщався на екран: фокус за замовчуванням стояв на кнопці «Close», тож перше натискання стрілки просто перемикало фокус, а не гортало текст; після досягнення нижнього/верхнього краю тексту стрілка знову «з'їдала» фокус замість продовження прокрутки. Тепер фокус одразу на текстовому полі, а
setVerticalFocusSwitching(false)/setHorizontalFocusSwitching(false)тримають фокус там незалежно від позиції каретки. Enterне закривав вікно, якщо фокус був не на кнопці (а після виправлення вище — він за замовчуванням саме там): текстове поле в режимі read-only просто «з'їдало»Enter, нічого не роблячи. ТеперEnter(іEscape) закривають вікно глобально, незалежно від того, який компонент у фокусі (WindowListenerAdapter.onInput+setCloseWindowWithEscape(true)).
| Назва | Призначення | |
|---|---|---|
| ☕ | Java 17 | Основна мова програмування |
| 🐘 | PostgreSQL | Система управління базами даних |
| 📦 | Maven 3.8+ | Збірка проєкту, залежності, тести, пакування |
| 💻 | IntelliJ IDEA | Середовище розробки |
| 🔄 | Git | Система керування версіями |
| 🔗 | PostgreSQL JDBC | Драйвер для роботи з PostgreSQL — jdbc.postgresql.org |
| ✨ | Lanterna | Бібліотека для консольного UI — github.com/mabe02/lanterna |
| 🧪 | JUnit 5 + Mockito | Модульне тестування |
| 📦 | jpackage | Збірка нативного .exe (входить до JDK, з версії 14) |
Не потрібно встановлювати ні PostgreSQL, ні JDK, ні Maven вручну — достатньо Docker. Застосунок має графічний (не текстовий) інтерфейс на Lanterna/Swing, тому контейнер піднімає віртуальний дисплей і віддає вікно програми в браузер через noVNC — працює однаково на Windows, macOS та Linux.
# Linux / macOS
./run.sh
# Windows
run.batСкрипт сам збере образи, підніме застосунок разом з БД (уже
заповненою тестовими даними з data/library.sql) і відкриє
http://localhost:6080/vnc.html у браузері — там і буде вікно
програми.
Без скрипта — те саме вручну:
docker compose up --buildі відкрити http://localhost:6080/vnc.html вручну.
Детальніше про змінні середовища, скидання БД, розповсюдження образу без збірки на цільовій машині тощо — див. DOCKER.md.
-
Завантаж PostgreSQL з офіційного сайту: 👉 postgresql.org/download
-
Під час встановлення запам'ятай пароль користувача
postgres— він знадобиться далі. -
Переконайся, що
bin-папка PostgreSQL (наприклад,C:\Program Files\PostgreSQL\16\bin) додана до системної змінноїPath, щоб командиpsql,createdb,pg_restoreбули доступні з будь-якої консолі.
Є два способи підготувати базу: Варіант А створює порожню схему з нуля, Варіант Б відновлює з готового дампу.
createdb -U postgres library
psql -U postgres -d library -f schema.sqlМінімальний набір таблиць (schema.sql), на якому побудовані всі запити проєкту:
CREATE TABLE users (
id SERIAL PRIMARY KEY,
role TEXT NOT NULL,
login TEXT NOT NULL UNIQUE,
password TEXT NOT NULL
);
CREATE TABLE libraries (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
location TEXT
);
CREATE TABLE librarians (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
CREATE TABLE work_schedule (
id SERIAL PRIMARY KEY,
worker_id INTEGER REFERENCES librarians(id),
library_id INTEGER REFERENCES libraries(id),
start_day TEXT,
end_day TEXT,
start_time TEXT,
end_time TEXT
);
CREATE TABLE authors (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
CREATE TABLE books (
id SERIAL PRIMARY KEY,
title TEXT NOT NULL
);
CREATE TABLE book_details (
book_id INTEGER PRIMARY KEY REFERENCES books(id),
genre TEXT,
publisher TEXT,
year INTEGER,
isbn TEXT
);
CREATE TABLE book_authors (
book_id INTEGER REFERENCES books(id),
author_id INTEGER REFERENCES authors(id),
PRIMARY KEY (book_id, author_id)
);
CREATE TABLE categories (
id SERIAL PRIMARY KEY,
category_type TEXT NOT NULL
);
CREATE TABLE readers (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
address TEXT,
phone TEXT
);
CREATE TABLE category_details (
reader_id INTEGER PRIMARY KEY REFERENCES readers(id),
category_id INTEGER REFERENCES categories(id),
institution_name TEXT,
major TEXT,
school_number TEXT,
kindergarten_name TEXT,
research_field TEXT
);
CREATE TABLE visits (
id SERIAL PRIMARY KEY,
reader_id INTEGER REFERENCES readers(id),
book_id INTEGER REFERENCES books(id),
library_id INTEGER REFERENCES libraries(id),
visit_time TIMESTAMP NOT NULL DEFAULT now()
);
-- Обліковий запис адміністратора для першого входу:
INSERT INTO users (role, login, password) VALUES ('admin', 'admin', 'admin');
-- Хоча б одна бібліотека, щоб можна було зареєструвати бібліотекаря:
INSERT INTO libraries (name, location) VALUES ('Central Library', 'Main St 1');# 1. Створити базу даних
createdb -U postgres library
# 2. Перейти до папки з дампом (вкажи свій шлях)
cd "D:\Download\libcode-java\database"
# 3a. Відновлення з текстового SQL-дампу
psql -U postgres -d "library" -f "library.sql"
# 3b. Відновлення з бінарного дампу (pg_dump --format=custom)
pg_restore -U postgres -d "library" -c "library.dump"При виконанні команд система може запитати пароль користувача
postgres. Після відновлення переконайся, що вusersє хоча б один рядок зrole = 'admin', а вlibraries— хоча б один запис.
На відміну від попередньої версії, пароль не зашивається в код: усе підключення до БД читає клас com.libcode.library.config.DbConfig, який шукає значення у трьох місцях за таким пріоритетом (перше знайдене — і використовується):
- Змінні середовища
LIBRARY_DB_URL/LIBRARY_DB_USER/LIBRARY_DB_PASSWORD— саме їх встановлюютьDockerfile/docker-compose.yml, тож контейнерний запуск працює без жодних змін. - Файл
db.propertiesу робочій директорії застосунку (ключіdb.url,db.user,db.password) — зручний спосіб налаштувати підключення локально, без запуску Docker і без експорту змінних середовища щоразу заново. - Вбудовані значення за замовчуванням (ті самі, що й раніше) — використовуються, лише якщо не задано ні змінних середовища, ні
db.properties.
cp db.properties.example db.propertiesі відредагувати значення під свою БД:
db.url=jdbc:postgresql://localhost:5432/library
db.user=postgres
db.password=твій_парольdb.properties додано до .gitignore — реальний пароль ніколи не потрапить у git; у репозиторії лежить лише шаблон db.properties.example.
# PowerShell
$env:LIBRARY_DB_URL = "jdbc:postgresql://localhost:5432/library"
$env:LIBRARY_DB_USER = "postgres"
$env:LIBRARY_DB_PASSWORD = "твій_пароль"# bash / zsh
export LIBRARY_DB_URL="jdbc:postgresql://localhost:5432/library"
export LIBRARY_DB_USER="postgres"
export LIBRARY_DB_PASSWORD="твій_пароль"Якщо не задано ні змінних середовища, ні db.properties — застосунок підключається за вбудованими значеннями за замовчуванням (jdbc:postgresql://localhost:5432/library, postgres / admin1).
Проєкт збирається Maven — жодних додаткових пакетних менеджерів (на кшталт vcpkg) не потрібно, усі залежності (Lanterna, PostgreSQL JDBC, JUnit, Mockito) підтягуються автоматично з Maven Central.
git clone https://github.com/VSCRM/Library.git
cd Librarymvn clean package
java -jar target/library-console.jarmvn package компілює код, прогонить весь набір тестів і (через maven-shade-plugin) створює єдиний самодостатній library-console.jar з уже вбудованим драйвером PostgreSQL — окремо налаштовувати classpath не потрібно.
mvn testНабір тестів (JUnit 5 + Mockito) перевіряє кожен клас через його публічний контракт — реальна база даних для запуску тестів не потрібна: усі виклики java.sql.* підмінені моками.
Окремий Maven-профіль exe одразу після пакування запускає jpackage, тож один командний рядок дає одразу і .jar, і .exe:
mvn clean package -PexeРезультат — target\LibCodeLibraryConsole\LibCodeLibraryConsole.exe, який можна запускати напряму: цільова машина не потребує встановленої Java. Профіль вимагає повний JDK (не лише JRE) з jpackage на PATH — саме тому це окремий opt-in профіль, а не частина стандартної збірки: звичайний mvn package так само коректно працює на будь-якій платформі/CI.
ℹ️
.exeзбирається без консольного вікна: увесь реальний інтерфейс застосунку малюється у власному Swing-вікні Lanterna (див.LanternaScreens), тож окрема консоль Windows не потрібна.
Ручний виклик jpackage (якщо потрібно кастомізувати прапорці):
mvn clean package
jpackage --input target --main-jar library-console.jar --main-class com.libcode.library.Main --name LibCodeLibraryConsole --type app-image --dest targetЗамість --type app-image можна вказати --type msi або --type exe (потребує WiX Toolset) для отримання одного файла-інсталятора замість папки.
Це очікувано, а не пропущений крок: Java компілюється в байткод, а не в машинний код конкретної ОС/CPU, тож .jar виконується без змін на Windows/macOS/Linux, поки на машині є JVM. Саме тому стандартний спосіб поширення Java-застосунку — це .jar + java -jar .... Якщо потрібен саме нативний подвійним-кліком запускний файл для користувачів без Java — для цього і є jpackage (профіль exe вище).
Проєкт побудований на пошаровій архітектурі (UI → координація → бізнес-логіка → доступ до БД) і використовує наступні патерни проєктування:
| Патерн | Клас(и) | Призначення |
|---|---|---|
| Singleton | logging.Logger |
Єдина точка запису подій з таймстампом у log.txt |
| Proxy | auth.AuthorizationProxy → auth.Authorization |
Обмеження часу входу (07:00–16:00) перед делегуванням реальній перевірці |
| Abstract Factory | interfaces.IDBFactory / db.PostgresFactory |
Створення пари пов'язаних об'єктів доступу до БД (з'єднання + вивід) |
| Facade | ApplicationCoordinator.java |
Координація взаємодії між компонентами |
| Factory Method | interfaces.IMenuCreator / menu.MenuCreator |
Динамічне створення AdminMenu або LibrarianMenu залежно від ролі |
| Decorator | ui.ConsoleUtilsDecorator |
Стилізація консольного виведення без зміни базової реалізації |
| Adapter | db.ResultAdapter |
Конвертація java.sql.ResultSet у формат IDBOutput |
SOLID застосовано послідовно у всьому проєкті: кожен клас відповідає за одну задачу (SRP), нові ролі/меню/джерела даних додаються реалізацією інтерфейсу без зміни наявного коду (OCP), вузькі рольові інтерфейси (IBaseOperations, IAddOperations) замість одного великого (ISP), а всі залежності передаються через конструктор (DIP) — саме це і робить можливим тестування без реальної БД.
Повний перелік усіх файлів проєкту (кожна папка — за алфавітом: спершу підпапки, потім файли):
libcode-java/
├── data/ # DB — дампи бази даних, для відновлення
│ ├── library.dump
│ └── library.sql
├── docker/
│ └── entrypoint.sh # запуск Xvfb + fluxbox + x11vnc + noVNC + застосунку
├── src/
│ ├── main/java/com/libcode/library/
│ │ ├── app/ # Facade — координація застосунку
│ │ │ └── ApplicationCoordinator.java
│ │ ├── auth/ # Авторизація + Proxy обмеження часу
│ │ │ ├── Authorization.java
│ │ │ └── AuthorizationProxy.java
│ │ ├── config/ # Налаштування підключення до БД
│ │ │ ├── DbConfig.java # пріоритет: env vars → db.properties → дефолти
│ │ │ └── DbCredentials.java
│ │ ├── db/ # Abstract Factory + Adapter для PostgreSQL
│ │ │ ├── PostgresConnection.java
│ │ │ ├── PostgresFactory.java
│ │ │ ├── PostgresOutput.java
│ │ │ └── ResultAdapter.java
│ │ ├── features/ # Бізнес-логіка бібліотекаря/адміністратора
│ │ │ ├── ExtendFeatures.java
│ │ │ └── MainFeatures.java
│ │ ├── interfaces/ # Усі контракти (I*.java)
│ │ │ ├── IAddOperations.java
│ │ │ ├── IApplicationCoordinator.java
│ │ │ ├── IAuthorization.java
│ │ │ ├── IBaseOperations.java
│ │ │ ├── IConsoleUtils.java
│ │ │ ├── IDBConnect.java
│ │ │ ├── IDBFactory.java
│ │ │ ├── IDBOutput.java
│ │ │ ├── IMenu.java
│ │ │ ├── IMenuCreator.java
│ │ │ ├── IUserContext.java
│ │ │ └── UserContextFactory.java
│ │ ├── logging/ # Singleton — журналювання подій
│ │ │ └── Logger.java
│ │ ├── menu/ # Factory Method — меню за роллю
│ │ │ ├── AdminMenu.java
│ │ │ ├── LibrarianMenu.java
│ │ │ └── MenuCreator.java
│ │ ├── model/ # Дані, що передаються між шарами
│ │ │ ├── LoginCredentials.java
│ │ │ └── UserContext.java
│ │ ├── ui/ # Lanterna-інтерфейс + Decorator стилізації
│ │ │ ├── AnsiColors.java
│ │ │ ├── ConsoleTheme.java
│ │ │ ├── ConsoleUtils.java
│ │ │ ├── ConsoleUtilsDecorator.java
│ │ │ ├── EndOfInputException.java
│ │ │ ├── LanternaScreens.java # спільне вікно + підтримка кліку/наведення мишею
│ │ │ ├── MarqueeListItemRenderer.java
│ │ │ ├── MarqueeTicker.java
│ │ │ └── ReportWindow.java # звіти/статистика — власне вікно замість зовнішнього редактора
│ │ ├── util/ # Спільні допоміжні класи
│ │ │ ├── ConsoleInputReader.java
│ │ │ ├── DropdownSelector.java
│ │ │ └── SqlTransactions.java
│ │ └── Main.java # точка входу (composition root)
│ └── test/java/com/libcode/library/
│ ├── app/
│ │ └── ApplicationCoordinatorTest.java
│ ├── auth/
│ │ ├── AuthorizationProxyTest.java
│ │ └── AuthorizationTest.java
│ ├── config/
│ │ └── DbConfigTest.java
│ ├── db/
│ │ ├── PostgresConnectionTest.java
│ │ ├── PostgresFactoryTest.java
│ │ ├── PostgresOutputTest.java
│ │ └── ResultAdapterTest.java
│ ├── features/
│ │ ├── ExtendFeaturesTest.java
│ │ ├── LanternaKeystrokes.java # спільні хелпери для симуляції клавіш у тестах
│ │ └── MainFeaturesTest.java
│ ├── logging/
│ │ └── LoggerTest.java
│ ├── menu/
│ │ ├── AdminMenuTest.java
│ │ ├── LibrarianMenuTest.java
│ │ └── MenuCreatorTest.java
│ ├── model/
│ │ └── UserContextTest.java
│ ├── ui/
│ │ ├── ConsoleUtilsDecoratorTest.java
│ │ ├── ConsoleUtilsTest.java
│ │ ├── LanternaScreensTest.java # математика піксель→комірка (клік/наведення мишею)
│ │ ├── MouseHoverSelectionTest.java # виділення рухається за наведенням миші, як стрілками
│ │ └── ReportWindowTest.java # фокус/скрол/Enter-Escape для вікна звітів
│ └── util/
│ └── ConsoleInputReaderTest.java
├── .dockerignore
├── .env.example # шаблон змінних для docker-compose (LIBRARY_DB_*)
├── .gitignore
├── db.properties.example # шаблон локального db.properties (db.url/db.user/db.password)
├── docker-compose.yml # app + PostgreSQL, посів з data/library.sql
├── Dockerfile # мультистейдж-збірка (Maven) + рантайм з noVNC
├── DOCKER.md # інструкції з запуску в Docker
├── LICENSE
├── pom.xml
├── README.md
├── run.bat # запуск у Docker + автовідкриття браузера (Windows)
└── run.sh # запуск у Docker + автовідкриття браузера (Linux/macOS)
(target/, .idea/ та інші згенеровані/IDE-папки навмисно виключені, як і рантайм-файли log.txt/db.properties — див. .gitignore.)
- Information about books — перелік усіх книг (назва, автор, жанр, видавництво, рік, ISBN) через
JOINтаблицьbook_details,book_authors,authors - Information about readers — перелік читачів та їхньої категорії (
JOINзcategory_details,categories) - Information about visits — історія відвідувань (
JOINvisits,readers,libraries,books) - Most popular books — рейтинг книг за кількістю видач (
GROUP BY+COUNT+ORDER BY) - Add book — додавання книги; автор створюється автоматично, якщо ще не існує; жанр/видавництво/рік/ISBN — необов'язкові
- Add reader — додавання читача з категорією (школяр, студент, дошкільник, науковець), кожна з власним набором полів
- Add visit — реєстрація видачі книги через випадаючі списки наявних читачів, бібліотек і книг
- Exit — вихід із системи
- Information about libraries — перелік усіх бібліотек фонду
- Information about librarians — перелік бібліотекарів з прив'язкою до бібліотеки та графіком роботи
- Add user — створення облікового запису (логін, пароль, роль); для бібліотекаря додатково — ПІБ, бібліотека, графік роботи
- System statistics — статистика по всіх таблицях + хвіст
log.txt - Log out — вихід із системи
Увесь UI малюється в окремому Swing-вікні (аналог ftxui з C++ версії): кольорові рамки, кнопки, прокручувані списки. Вибір пункту меню чи кнопки роботить трьома рівноцінними способами:
- стрілками ↑ / ↓ +
Enter; - клавішею
Tabдля переходу між полями; - мишею — реалізовано власним мостом між реальними AWT-подіями миші та внутрішнім механізмом синтетичного вводу Lanterna (
LanternaScreens.installMouseSupport), оскільки стандартний Swing-бекенд Lanterna сам по собі ні кліки, ні рух миші не генерує. Сірий фон поточного пункту тепер рухається за курсором під час наведення (mouseMoved→MouseActionType.MOVE), а не тільки після кліку — так само, як він рухається стрілками; клік (mousePressed/mouseReleased) додатково одразу підтверджує вибір, якEnter.
Прокрутка колесом миші (наприклад, у ReportWindow) також підтримується, хоча Lanterna нативно її не має: LanternaScreens.injectWheelScroll транслює обертання колеса у повторні натискання стрілок (LanternaScreens.wheelScrollKeyPresses, покрито LanternaScreensTest) — звичайне колесо гортає вертикально (↑/↓), а Shift + колесо — горизонтально (←/→), за тим самим принципом, що й у браузерах та IDE.
- Авторизація з розмежуванням прав доступу — роль (
admin/librarian) визначається запитом до БД, і система формує відповідне меню - Обмеження часу доступу (Proxy) — вхід дозволений лише з 07:00 до 16:00; поза цим вікном спроба входу відхиляється й фіксується в журналі
- JOIN-запити до БД — усі звітні розділи будуються на
JOINкількох пов'язаних таблиць - Автоматичне відображення результатів — вивід будь-якого звітного запиту одразу показується у власному вікні застосунку (
ReportWindow, поверх Lanterna/Swing) — без залежності від зовнішнього текстового редактора, що особливо важливо в мінімальному Docker/noVNC-оточенні, де такого редактора просто немає; окремий файл на диску для цього більше не створюється (див. 🆕 Останні зміни) - Журналювання дій системи — усі ключові події фіксуються з таймстампом у
log.txtчерезSingleton Logger - Транзакційні багатокрокові вставки — додавання книги/читача/бібліотекаря виконується в одній транзакції з відкатом при помилці
- Розширюваність на інші СУБД — доступ до БД абстраговано через
Abstract Factory(IDBFactory,IDBConnect,IDBOutput)
mvn testПокриття: Logger (Singleton, потокобезпека), AuthorizationProxy (межі вікна 07:00–16:00), PostgresConnection (переходи стану з'єднання), ResultAdapter/PostgresOutput (конвертація, вирівняний показ звіту в ReportWindow через ін'єктований reportViewer), DbConfig (пріоритет змінних середовища над db.properties над вбудованими значеннями за замовчуванням), MenuCreator/AdminMenu/LibrarianMenu (маршрутизація за роллю), ApplicationCoordinator (повний цикл вхід → меню → вихід), MainFeatures/ExtendFeatures (SQL, транзакції, дропдауни, валідація вводу, показ статистики), ConsoleUtils (навігація стрілками/Tab/мишею через DefaultVirtualTerminal), ReportWindow (фокус стартує на тексті, а не на кнопці — прокрутка стрілками працює одразу; Enter/Escape закривають вікно незалежно від того, який компонент у фокусі; коректний fallback на консоль, якщо термінал узагалі не піднявся — ReportWindowTest), LanternaScreens (чиста математика перетворення піксель→комірка, що лежить в основі кліку й наведення мишею — LanternaScreensTest), а також окремий MouseHoverSelectionTest, що підтверджує на рівні самого Lanterna: подія наведення (MouseActionType.MOVE) переводить фокус і рухає виділення на пункт під курсором так само, як стрілки.
| Роль | Доступ |
|---|---|
| admin | Бібліотеки, бібліотекарі, реєстрація користувачів, системна статистика |
| librarian | Книги, читачі, відвідування, найпопулярніші книги, додавання нових записів |
Вхід дозволений лише з 07:00 до 16:00 — навмисне обмеження (AuthorizationProxy), а не помилка застосунку.
Цей проєкт ліцензовано під MIT License. Детальніше дивіться у файлі LICENSE.