Перейти к содержанию

Архитектура системы управления библиотекой

Обзор

Система управления библиотекой представляет собой fullstack приложение, состоящее из frontend (React + TypeScript) и backend (Node.js + Express) компонентов, работающих с PostgreSQL базой данных.

Архитектура следует принципам многослойной архитектуры (Layered Architecture) с разделением на слои: Presentation, Application, Domain, Infrastructure.

Структура проекта

library_system/
├── src/                    # Frontend приложение (React + TypeScript)
│   ├── components/         # React компоненты
│   │   ├── dialogs/        # Модальные окна
│   │   ├── ui/             # Базовые UI компоненты (shadcn/ui)
│   │   └── ...             # Другие компоненты
│   ├── pages/              # Страницы приложения
│   ├── hooks/              # Custom React hooks
│   ├── lib/                # Утилиты и конфигурация
│   └── types/              # TypeScript типы
│
├── server/                 # Backend приложение (Node.js + Express)
│   ├── config/             # Конфигурация (DB, LDAP, Swagger)
│   ├── models/             # Sequelize модели (Domain Layer)
│   ├── repositories/       # Слой доступа к данным (Data Access Layer)
│   │   ├── BaseRepository.js
│   │   ├── OperationRepository.js      # Главный репозиторий (Facade)
│   │   ├── OperationQueryRepository.js # Методы чтения
│   │   ├── OperationCommandRepository.js # Методы создания/изменения
│   │   └── ...             # Другие репозитории
│   ├── services/           # Бизнес-логика (Application Layer)
│   │   ├── operations/     # Сервисы операций
│   │   └── ...
│   ├── routes/             # API маршруты (Presentation Layer)
│   ├── middleware/         # Express middleware
│   ├── validators/         # Валидация данных
│   ├── dto/                # Data Transfer Objects
│   ├── utils/              # Утилиты
│   ├── migrations/         # SQL миграции
│   ├── scripts/            # Вспомогательные скрипты
│   │   ├── process-outbox-events.js
│   │   ├── reconcile-outbox-stuck.js
│   │   └── cleanup-expired-bookings.js
│   └── workers/
│       ├── outboxProcessor.js
│       └── outboxWorker.js
│
└── docs/                   # Документация

Frontend архитектура

Технологический стек

  • React 18.3 - UI библиотека
  • TypeScript 5.8 - Типизация
  • Vite 5.4 - Сборщик и dev-сервер
  • React Router 6.30 - Маршрутизация
  • TanStack Query 5.83 - Управление серверным состоянием и кэширование
  • React Hook Form 7.61 - Управление формами
  • Zod 3.25 - Валидация схем
  • shadcn/ui - UI компоненты на базе Radix UI
  • Tailwind CSS 3.4 - Стилизация
  • date-fns 3.6 - Работа с датами
  • qrcode 1.5 - Генерация QR-кодов

Структура frontend

Компоненты (src/components/)

Диалоги (dialogs/): - books/ - Диалоги работы с книгами (добавление, редактирование, копии) - operations/ - Диалоги операций (выдача, возврат, списание, продление, массовые операции) - bookings/ - Диалоги бронирований - users/ - Диалоги управления пользователями - reference/ - Диалоги справочников (авторы, жанры, издательства, полки) - export-import/ - Диалоги экспорта/импорта данных

UI компоненты (ui/): - Базовые компоненты: Button, Input, Dialog, Table, Select, Calendar и т.д. - Состояния: LoadingState, ErrorState, EmptyState - Специальные: QueueProcessingIndicator

Другие компоненты: - Layout.tsx - Основной layout приложения - AppSidebar.tsx - Боковая панель навигации - NotificationCenter.tsx - Центр уведомлений - DueDateNotifications.tsx - Уведомления о сроках возврата - QRScanner.tsx - Компонент сканирования QR-кодов - QRGenerator.tsx - Компонент генерации QR-кодов - PaginatedList.tsx - Компонент пагинации списков - ProtectedRoute.tsx - Защита маршрутов

Страницы (src/pages/)

Публичные: - Auth.tsx - Авторизация - Catalog.tsx - Публичный каталог книг - BookDetail.tsx - Детальная информация о книге

Для читателей: - MyLoans.tsx - Мои выдачи (с возможностью продления) - MyBookings.tsx - Мои бронирования и очереди

Для библиотекарей и администраторов: - Dashboard.tsx - Главная страница с статистикой - BookCatalog.tsx - Административный каталог книг - ActiveLoans.tsx - Активные выдачи (с возможностью продления) - Bookings.tsx - Управление бронированиями - Operations.tsx - История операций - Users.tsx - Управление пользователями - Authors.tsx - Управление авторами - Genres.tsx - Управление жанрами - References.tsx - Справочники - Inventory.tsx - Инвентаризация - WriteOffHistory.tsx - История списаний - Scan.tsx - QR сканирование - Settings.tsx - Настройки

Маршрутизация

Приложение использует React Router с защищенными маршрутами:

  • /auth - Авторизация (публичный)
  • / - Дашборд (admin, librarian)
  • /catalog - Публичный каталог (все роли)
  • /my-loans, /my-bookings - Личные кабинеты (reader)
  • Остальные маршруты - Административные функции (admin, librarian)

Управление состоянием

  • TanStack Query — кэширование и синхронизация данных с сервером; централизованные ключи в src/lib/queryKeys.ts, инвалидация — src/lib/invalidateLibraryCache.ts
  • React Hook Form — локальное состояние форм
  • React Context — глобальное состояние (тема, доступность)
  • Сессия и вкладкиsrc/lib/api.ts (ensureSessionFresh, координация refresh между вкладками), src/lib/authSync.ts (синхронный logout через BroadcastChannel)

Backend архитектура

Технологический стек

  • Node.js - Runtime окружение
  • Express 4.18 - Web framework
  • Sequelize 6.37 - ORM для PostgreSQL
  • PostgreSQL - Реляционная база данных
  • Redis 4.7 - Кэширование (опционально)
  • JWT - Аутентификация
  • Winston 3.15 - Логирование
  • Swagger - API документация

Архитектурные слои

1. Routes (server/routes/) - Presentation Layer

API маршруты, обрабатывающие HTTP запросы:

  • auth.js - Аутентификация и авторизация
  • books/ - Операции с книгами (CRUD, импорт, статистика)
  • create.js, update.js, delete.js, import.js, stats.js
  • bookCopies.js - Управление экземплярами книг
  • operations.js - Операции выдачи/возврата/списания/продления
  • bookings.js - Бронирования и очередь
  • users.js - Управление пользователями
  • authors.js, genres.js, publishers.js - Справочники
  • qr.js - QR-коды
  • health.js - Health check

Поток запроса:

HTTP Request → Middleware (auth, csrf, validation) → Route Handler → Service → Repository → Database

2. Services (server/services/) - Application Layer

Бизнес-логика приложения:

Основные сервисы: - OperationService.js - Оркестрация операций (фасад) - BookingService.js - Логика бронирований и очереди - createBooking() - Создание бронирования - cancelBooking() - Отмена бронирования - addToQueue() - Добавление в очередь - processQueueForBook() - Обработка очереди для книги - cancelExpiredBookings() - Отмена просроченных бронирований

Сервисы операций (services/operations/): - LoanService.js - Логика выдачи книг - ReturnService.js - Логика возврата книг - WriteOffService.js - Логика списания книг - RenewalService.js - Логика продления выдач - OperationStatsService.js - Статистика операций

Другие сервисы: - BookService.js — логика работы с книгами - UserService.js — логика работы с пользователями - ReferenceService.js — справочники: авторы, жанры, издательства, полки, состояния, языки (с кэшем; методы getAll*Sorted, пагинация, CRUD для авторов/жанров/издательств; для инвалидации кэша используется cache.del / cache.invalidate) - SupplierService.js — поставщики (getAllSorted, getById, create, update, delete); маршрут suppliers.js вызывает только сервис - SupplyService.js — поставки (getAllWithDetails, getByIdWithDetails, create, update, delete); маршрут supply.js вызывает только сервис - UserCategoryService.js — категории пользователей (getAllSorted, getById, create, update, delete с проверкой «в использовании»); маршрут userCategories.js вызывает только сервис - ImportService.js — импорт книг из CSV (оркестрация репозиториев, парсинг по заголовкам, создание/поиск справочников и книг без дубликатов); маршрут books/import.js только проверяет файл и вызывает ImportService.importFromCsv()

3. Repositories (server/repositories/) - Data Access Layer

Слой доступа к данным, абстрагирующий работу с БД.

Архитектурный паттерн: Repository Pattern + CQRS (Command Query Responsibility Segregation)

Базовая структура: - BaseRepository.js - Базовый класс для всех репозиториев - Предоставляет общие методы: findById(), findAll(), create(), update(), delete()

Специализированные репозитории:

OperationRepository (Facade Pattern): - OperationRepository.js (~150 строк) - Главный репозиторий, объединяющий Query и Command - Делегирует вызовы методов в соответствующие репозитории - Предоставляет единый интерфейс для работы с операциями - validateRequiredFields() - Утилита валидации

  • OperationQueryRepository.js (~650 строк) - Методы чтения (Query)
  • findAllWithDetails() - Поиск операций с деталями
  • findWriteOffs() - Поиск операций списания
  • findActiveLoansForReader() - Активные займы читателя
  • findAllActiveLoans() - Все активные займы
  • findOverdueLoans() - Просроченные займы
  • findByIdWithIncludes() - Поиск по ID с включениями
  • findAll() - Поиск всех операций
  • findActiveLoansForBook() - Активные выдачи для книги
  • getActiveLoansStats() - Статистика активных выдач
  • getTotalLoansStats() - Статистика всех выдач

  • OperationCommandRepository.js (~650 строк) - Методы создания/изменения (Command)

  • createLoanWithBooking() - Создание выдачи с бронированием
  • createReturn() - Создание возврата
  • createWriteOff() - Создание списания
  • validateRequiredFields() - Валидация обязательных полей

Другие репозитории: - BookRepository.js - Работа с книгами - BookCopyRepository.js - Работа с экземплярами - BookingRepository.js - Работа с бронированиями - BookingQueueRepository.js - Работа с очередью бронирований - UserRepository.js - Работа с пользователями - ReferenceRepository.js - Работа со справочниками - И другие репозитории для справочников

Преимущества разделения: - ✅ Разделение ответственности (чтение vs запись) - ✅ Упрощение поддержки (меньше строк в каждом файле) - ✅ Улучшенная навигация - ✅ Упрощенное тестирование - ✅ Обратная совместимость (единый интерфейс через OperationRepository)

Принципы работы репозиториев: - ✅ Репозитории НИКОГДА не создают транзакции - Только принимают через options.transaction - ✅ Репозитории НИКОГДА не коммитят/откатывают транзакции - Управление только в сервисах - ✅ Валидация обязательности транзакции - Репозитории проверяют наличие транзакции для критических операций - ✅ Явные границы транзакций - Один сервисный метод = одна транзакция

4. Models (server/models/) - Domain Layer

Sequelize модели, описывающие структуру БД:

Основные сущности: - User - Пользователи (profiles) - Book - Книги (book_titles) - BookCopy - Экземпляры книг (book_copies) - Operation - Операции (operations) - Booking - Бронирования (bookings) - BookingQueue - Очередь бронирований - Renewal - Продления выдач

Справочники: - Author, Genre, Publisher, Language, Condition, Shelf - UserCategory - Категории пользователей - OperationType, OperationStatus - Типы и статусы операций - BookingStatus - Статусы бронирований

Служебные: - OutboxEvent - События для асинхронной обработки (Outbox Pattern) - IdempotencyKey - Ключи идемпотентности

5. Middleware (server/middleware/)

  • auth.js - JWT аутентификация и авторизация
  • csrf.js - CSRF защита
  • asyncHandler.js - Обработка асинхронных ошибок
  • apiVersion.js - Версионирование API

6. Validators (server/validators/)

Централизованная валидация входящих данных (express-validator). Все валидаторы реэкспортируются из index.js. Маршруты подключают их и не дублируют инлайн-цепочки body()/param().

Файлы: - bookValidators.js — создание/редактирование книг, экземпляров (в т.ч. snake_case/camelCase для POST /book-copies) - userValidators.js — пользователи - bookingValidators.js — бронирования - operationValidators.js — операции (выдача, возврат, списание, продление) - referenceValidators.js — авторы, издательства, жанры, полки - authValidators.js — вход (login, password) - userCategoryValidators.js — категории пользователей - qrValidators.js — QR-операции - supplyValidators.js, supplierValidators.js — поставки и поставщики

Использование: маршруты users.js, books/crud.js, bookCopies.js, bookings.js, operations.js, authors.js, publishers.js, shelves.js, genres.js, auth.js, userCategories.js, qr.js, supply.js, suppliers.js используют валидаторы из validators/.

7. DTO (server/dto/)

Data Transfer Objects для форматирования ответов API. Реэкспорт из index.js.

  • BaseDTO.js — базовый класс
  • BookingDTO.js — форматирование бронирований
  • OperationDTO.js — форматирование операций (в т.ч. OperationDTO.format(operation))
  • UserDTO.js — форматирование пользователей

Сервисы (например, BookingService, UserService) импортируют DTO из ../dto для единообразных ответов.

Разделение валидации и бизнес-логики

Текущее состояние

  • Валидация (backend): В server/validators/ сосредоточены все цепочки express-validator; маршруты вызывают валидаторы и не дублируют правила в роутах. Дублирование validateRequiredFields убрано из модели Operation и оставлено только в OperationCommandRepository.
  • Валидация (frontend): Схемы форм (Zod) хранятся в src/lib/validators/: operationSchemas.ts, referenceSchemas.ts, userSchemas.ts, bookSchemas.ts, index.ts. Диалоги и страницы импортируют схемы и используют zodResolver(schema) без дублирования z.object() для тех же сущностей.
  • Маршруты: Вызывают валидацию → при успехе вызывают сервисы (не репозитории напрямую, где это внедрено). Исключение: auth.js по-прежнему использует UserRepository/UserCategoryRepository для логина/setup; при желании можно вынести в AuthService.
  • Сервисы: Бизнес-логика, оркестрация, транзакции. Не проверяют формат полей запроса.

Принципы

Слой Ответственность Не должен
Validators Формат и обязательность полей запроса Реализовывать бизнес-правила
Routes Валидация → вызов сервиса → ответ Дублировать валидацию, содержать бизнес-логику
Services Бизнес-правила, оркестрация, транзакции Проверять тип/формат полей запроса
Repositories Чтение/запись БД Проверять «пришли ли нужные поля с фронта»

База данных

PostgreSQL

База данных использует PostgreSQL с следующими основными таблицами:

Основные сущности

  • profiles - Пользователи системы
  • book_titles - Названия книг
  • book_copies - Экземпляры книг
  • operations - Операции (выдача, возврат, списание)
  • bookings - Бронирования
  • booking_queue - Очередь бронирований
  • renewals - Продления выдач

Справочники

  • authors - Авторы
  • genres - Жанры
  • publishers - Издательства
  • languages - Языки
  • conditions - Состояния книг
  • shelves - Полки
  • user_categories - Категории пользователей
  • operation_types - Типы операций
  • operation_status - Статусы операций
  • booking_status - Статусы бронирований

Связующие таблицы

  • book_authors - Связь книг и авторов
  • book_genres - Связь книг и жанров
  • user_roles - Роли пользователей

Служебные таблицы

  • outbox_events - События для асинхронной обработки (Outbox Pattern)
  • idempotency_keys - Ключи идемпотентности
  • loan_tokens, return_tokens - Токены для QR-кодов

Миграции

База данных управляется через SQL миграции в server/migrations/:

  • Последовательные миграции от 001 до 039
  • init.sql - Инициализационный скрипт
  • migration-runner.js - Скрипт применения миграций
  • apply-init.js - Применение init.sql

Индексы и оптимизация

База данных содержит множество индексов для оптимизации запросов: - Индексы на часто используемые поля - Составные индексы для сложных запросов - GIN индексы для полнотекстового поиска (pg_trgm) - Уникальные индексы для предотвращения дубликатов

Триггеры и ограничения

  • check_unique_active_loan - Триггер для предотвращения множественных активных выдач
  • Учитывает операции возврата
  • Проверяет наличие активной выдачи без возврата
  • prevent_writeoff_with_active_loans - Предотвращение списания с активными выдачами
  • prevent_book_copy_id_change - Предотвращение изменения book_copy_id после создания операции

Асинхронная обработка (Outbox Pattern)

Проблема

При возврате книги или отмене бронирования нужно обработать очередь надёжно и без заметной задержки для читателя.

Решение: синхронное продвижение + Outbox Pattern

Основной путь:

  • ВозвратReturnService вызывает processQueueForBook и triggerOutboxProcessing() сразу после коммита
  • Отмена брониBookingService.cancelBooking синхронно вызывает processQueueForBook после коммита
  • Lazy expiration — просроченные pending на экземпляр отменяются при createBooking, addToQueue и processQueueForBook (не блокируют очередь до cron)

Резервный путь (Outbox):

Компоненты:

  1. OutboxEvent (таблица outbox_events)
  2. Хранит события для асинхронной обработки
  3. Тип события: CopyBecameAvailable
  4. Payload: { bookCopyId, hasActiveBooking, hasQueue }

  5. outbox-worker (контейнер Docker, scripts/run-outbox-daemon.js)

  6. Отдельный процесс; у API по умолчанию OUTBOX_WORKER_ENABLED=false
  7. Периодически вызывает processOutboxBatch() (несколько раундов за тик)
  8. Подстраховка, если синхронный прогон не завершился

  9. outboxWorker.js (встроенный воркер в server/index.js, OUTBOX_WORKER_ENABLED=true)

  10. Для локального node index.js без отдельного контейнера

  11. process-outbox-events.js (скрипт / cron)

  12. Тот же processOutboxBatch, для окружений без встроенного воркера или как подстраховка

  13. outboxProcessor.js

  14. Блокировка события FOR UPDATE SKIP LOCKED
  15. BookingService.processQueueForBook() — создание брони для головы очереди
  16. Пометка события обработанным и закрытие дубликатов по bookCopyId

  17. Создание событий:

  18. При возврате книги (OperationCommandRepository.createReturn)
  19. При отмене бронирования (BookingService.cancelBooking)
  20. При истечении бронирований (BookingService.cancelExpiredBookings)

Преимущества: - ✅ Надёжность (события не теряются) - ✅ Идемпотентность (можно повторять обработку) - ✅ Быстрый отклик (синхронное продвижение) + резерв через outbox - ✅ Масштабируемость (воркер можно вынести в отдельный контейнер)

Рекомендуемая настройка production (Docker):

  • Контейнер outbox-worker с OUTBOX_WORKER_ENABLED=true; у backendfalse (без дублирования при нескольких репликах)
  • Профиль jobs: booking-cleanup — ежедневная массовая отмена просроченных броней (дополнение к lazy expiration)
  • Опционально: cron process-outbox-events.js, если воркер отключён

Обработка очереди бронирований

Логика обработки

  1. Добавление в очередь:
  2. Пользователь встает в очередь на недоступную книгу
  3. Создается запись в booking_queue с позицией

  4. Обработка очереди:

  5. При освобождении экземпляра (возврат, отмена, lazy expiration) вызывается BookingService.processQueueForBook()
  6. Дополнительно создаётся OutboxEvent типа CopyBecameAvailable для подстраховки
  7. Для первого в очереди создаётся бронь, запись удаляется из booking_queue

  8. Условия обработки:

  9. Нет активной выдачи на экземпляр
  10. Нет активного (не просроченного) бронирования на экземпляр
  11. Экземпляр не списан; при рассинхроне is_available восстанавливается в processQueueForBook

  12. Пропуск головы очереди (переход к следующему):

  13. У пользователя уже есть бронь на этот экземпляр
  14. Достигнут лимит активных броней (5)
  15. Учётная запись неактивна

  16. Если экземпляр ещё забронирован другим читателем:

  17. Очередь ждёт отмены/истечения брони; затем новое outbox-событие обрабатывает очередь

Безопасность

Аутентификация

  • JWT токены - Для аутентификации пользователей
  • LDAP интеграция - Опциональная интеграция с Active Directory
  • bcryptjs - Хеширование паролей

Защита

  • CSRF токены - Защита от CSRF атак
  • Helmet - Защита HTTP заголовков
  • Rate Limiting - Ограничение частоты запросов
  • Валидация входных данных - На уровне API и БД
  • Транзакции - Атомарность операций
  • Row-level locking - Предотвращение race conditions

Авторизация

Система ролей: - admin - Администратор (полный доступ) - librarian - Библиотекарь (операции с книгами) - reader - Читатель (личный кабинет)

Интеграции

LDAP

Опциональная интеграция с LDAP/Active Directory для: - Аутентификации пользователей - Автоматического создания профилей - Извлечения информации о группах студентов

Redis

Используется для кэширования справочных данных (авторы, жанры, издательства, языки). Модуль server/utils/cache.js экспортирует get, set, invalidate и алиас del (равный invalidate) для совместимости с сервисами, вызывающими cache.del('authors') и т.п. При отсутствии Redis используется in-memory кэш.

QR-коды

  • Генерация QR-кодов для быстрой выдачи/возврата
  • Сканирование QR-кодов через веб-камеру
  • Массовая генерация QR-кодов

Импорт книг из CSV

Оркестрация в ImportService (server/services/ImportService.js). Маршрут books/import.js принимает файл и вызывает ImportService.importFromCsv(csvContent).

Формат CSV: первая строка — заголовки (порядок колонок не важен, сопоставление по названию). Поддерживаемые колонки:

  • Обязательные: Инвентарный номер, Название, Автор(ы) (несколько через ;)
  • Опциональные: ISBN, Год издания, Страниц, Издание, Язык, Издательство, Жанры (;), Полка, Состояние, Статус (доступна/выдана), Цена покупки, Текущая стоимость, Описание

Поведение без дубликатов:

  • Справочники (авторы, издательства, жанры, полки, языки) — поиск по названию; при отсутствии создаётся запись.
  • Книга — поиск по связке название + ISBN + издательство; при отсутствии создаётся книга с авторами и жанрами, затем добавляется экземпляр.
  • Экземпляр — по инвентарному номеру; при существующем номере строка пропускается, в ответ добавляется skipped и запись в errors.

Ответ API: { success, imported, skipped, errors } (количество успешно импортированных строк, пропущенных из‑за дубликата инв. номера, массив ошибок по строкам).

Паттерны проектирования

Repository Pattern

Все операции с БД инкапсулированы в репозиториях: - Абстракция от конкретной реализации БД - Переиспользование кода - Упрощение тестирования

CQRS (Command Query Responsibility Segregation): - OperationQueryRepository - Только чтение - OperationCommandRepository - Только запись - OperationRepository - Facade, объединяющий оба

Service Layer

Бизнес-логика вынесена в сервисы: - Разделение ответственности - Возможность переиспользования логики - Упрощение тестирования - Управление транзакциями - Сервисы создают и управляют транзакциями - Оркестрация операций - Координация между несколькими репозиториями

DTO Pattern

Использование DTO для: - Форматирования данных для API - Контроля структуры ответов - Преобразования внутренних моделей

Outbox Pattern

Асинхронная обработка событий: - Надежность (события не теряются) - Идемпотентность - Масштабируемость

Idempotency

Система поддерживает идемпотентность операций через: - idempotency_keys таблицу - Заголовок Idempotency-Key на критичных POST (бронирование, очередь AddToQueue, выдача и др.) - Повторная обработка запросов без побочных эффектов

Transaction Management

Архитектурный принцип: Services own transactions, repositories never create them

  • REPEATABLE READ - Уровень изоляции транзакций для критических операций
  • SELECT FOR UPDATE - Row-level locking для предотвращения race conditions
  • Транзакции создаются только в сервисах - Репозитории принимают транзакции через options.transaction
  • Один сервисный метод = одна транзакция - Четкие границы транзакций
  • Нет вложенных транзакций - Все транзакции явно управляются сервисами
  • Атомарность операций - Все изменения в рамках одной транзакции

Пример:

// Service создает транзакцию
const transaction = await createTransaction('REPEATABLE READ');
try {
  // Передает транзакцию в репозиторий
  const result = await Repository.method(data, { transaction });
  await transaction.commit();
  return result;
} catch (error) {
  if (transaction && !transaction.finished) {
    await transaction.rollback();
  }
  throw error;
}

Обработка ошибок

Frontend

  • ErrorBoundary — перехват ошибок React
  • ErrorState / EmptyState — разделение ошибки загрузки и пустого списка (каталог, «Мои выдачи», «Мои бронирования») с кнопкой повтора
  • Toast уведомления — пользовательские уведомления об ошибках
  • Валидация форм — Zod схемы для валидации

Backend

DomainError Pattern - Структурированная обработка ошибок:

  • DomainError класс - Базовый класс для доменных ошибок
  • errorCode - Код ошибки (например, BOOK_NOT_FOUND)
  • message - Сообщение об ошибке
  • statusCode - HTTP статус код
  • details - Дополнительные метаданные

  • ERROR_CODES - Стандартизированные коды ошибок:

  • BOOK_NOT_FOUND, BOOK_COPY_NOT_FOUND
  • USER_NOT_FOUND, USER_INACTIVE, USER_LIMIT_EXCEEDED
  • OPERATION_NOT_FOUND, OPERATION_TYPE_NOT_CONFIGURED
  • BOOKING_NOT_FOUND, BOOKING_EXPIRED, BOOKING_LIMIT_EXCEEDED
  • VALIDATION_ERROR, CONFIGURATION_ERROR
  • И другие...

  • createDomainError() - Фабрика для создания ошибок с автоматическим маппингом HTTP статусов

  • Централизованная обработка:

  • errorHandler.js - Middleware для обработки ошибок
  • asyncHandler.js - Обработка асинхронных ошибок с requestId
  • Автоматическое логирование с контекстом
  • Корректные HTTP статус коды

  • Транзакции - Автоматический откат изменений при ошибках

Производительность

Оптимизации

  • Индексы БД - Оптимизация запросов
  • Кэширование - Redis для справочных данных
  • Lazy loading - Ленивая загрузка компонентов
  • Pagination - Пагинация больших списков
  • Debounce - Оптимизация поиска
  • Batch operations - Массовые операции

Мониторинг

  • Winston логи - Структурированное логирование
  • Request ID - Трейсинг запросов
  • Метрики производительности - Логирование времени выполнения

Развертывание

Docker

Проект включает Docker конфигурации: - Dockerfile - Для frontend - server/Dockerfile - Для backend - docker-compose.dev.yml — PostgreSQL для локальной разработки - docker-compose.yml — production (backend, frontend, nginx) - docker-compose.ssl.yml — дополнение для SSL в Docker - См. DOCKER.md

Nginx

Конфигурация Nginx для: - Раздачи статических файлов frontend - Проксирования API запросов - SSL/TLS терминации

Скрипты

Вспомогательные скрипты (server/scripts/): - outboxWorker.js - Встроенная обработка очереди (env OUTBOX_WORKER_*) - process-outbox-events.js - Ручной/cron прогон outbox - reconcile-outbox-stuck.js - Разовая очистка зависших событий - cleanup-expired-bookings.js - Отмена просроченных броней (cron) - setup-test-db.js - Настройка тестовой БД - validate-migrations.js - Валидация миграций - check-constraint-violations.js - Проверка нарушений ограничений

Тестирование

Frontend

  • TypeScript для статической проверки типов
  • ESLint для проверки кода

Backend

  • Jest - Фреймворк для тестирования
  • Supertest - Тестирование HTTP endpoints
  • Unit тесты в server/__tests__/unit/
  • Integration тесты в server/__tests__/integration/

Документация API

Swagger

API документация доступна по адресу /api-docs (в dev режиме или при ENABLE_SWAGGER=true)

Масштабируемость

Система спроектирована с учетом масштабируемости: - Stateless backend - Можно горизонтально масштабировать - Кэширование - Для снижения нагрузки на БД - Асинхронная обработка - Через outbox pattern - Оптимизированные запросы - К БД - Транзакции - Для консистентности данных - Row-level locking - Для предотвращения race conditions

Ключевые особенности архитектуры

1. Разделение ответственности

  • Routes - Обработка HTTP запросов, валидация входных данных
  • Services - Бизнес-логика, управление транзакциями, оркестрация операций
  • Repositories - Доступ к данным, НЕ создают транзакции
  • Models - Структура данных, валидация на уровне модели

2. CQRS для операций

  • Query Repository - Оптимизирован для чтения
  • Command Repository - Оптимизирован для записи
  • Facade Repository - Единый интерфейс

3. Асинхронная обработка

  • Outbox Pattern - Надежная обработка событий
  • Очередь бронирований - Автоматическое продвижение
  • Cron задачи - Периодическая обработка

4. Надежность

  • Транзакции - Атомарность операций, управление только в сервисах
  • Row-level locking - Предотвращение race conditions (SELECT FOR UPDATE)
  • Idempotency - Повторная обработка без побочных эффектов через idempotency_keys
  • Валидация - На всех уровнях (Routes, Services, Models, Database)
  • DomainError - Структурированная обработка ошибок с кодами и метаданными
  • RequestId propagation - Трейсинг запросов через все слои

5. Производительность

  • Индексы БД - Оптимизация запросов
  • Кэширование - Redis для справочных данных
  • Пагинация - Для больших списков
  • Batch operations - Массовые операции

Поток данных

Выдача книги

Frontend (LoanDialog) 
  → API POST /api/operations/loan 
  → Route Handler (operations.js)
  → OperationService.createLoan()
  → LoanService.createLoan()
  → OperationRepository.createLoanWithBooking()
  → OperationCommandRepository.createLoanWithBooking()
  → Database (Transaction)

Возврат книги с обработкой очереди

Frontend (ReturnDialog)
  → API POST /api/operations/return
  → ReturnService.createReturn()
  → Database (Transaction) + OutboxEvent.create()
  → Database Commit
  → [Синхронно] BookingService.processQueueForBook()
  → triggerOutboxProcessing() [подстраховка для outbox-worker]

[Резерв]
  → outbox-worker / process-outbox-events.js
  → outboxProcessor.processOutboxBatch()
  → BookingService.processQueueForBook()

Отмена бронирования с обработкой очереди

Frontend (MyBookings / BookDetail)
  → API PUT /api/bookings/:id/cancel
  → BookingService.cancelBooking()
  → Database (Transaction) + OutboxEvent.create()
  → Database Commit
  → [Синхронно] BookingService.processQueueForBook()

Бронирование с очередью

Frontend (BookDetail)
  → API POST /api/bookings/queue  [Idempotency-Key]
  → BookingService.addToQueue()
  → cancelExpiredPendingForCopy() [lazy expiration]
  → BookingQueueRepository.addToQueue()
  → Database (Transaction)

[Когда экземпляр освобождается]
  → processQueueForBook() (синхронно после возврата/отмены)
  → OutboxEvent — резерв для воркера
  → Создаётся бронирование для первого в очереди

Статистика кода

Backend

  • Routes: ~15 файлов
  • Services: ~10 файлов
  • Repositories: ~22 файла (включая Query/Command разделение)
  • Models: ~20 моделей
  • Migrations: 39 миграций + init.sql

Frontend

  • Pages: 19 страниц
  • Components: ~89 компонентов
  • Dialogs: ~30 диалогов

Заключение

Архитектура системы следует принципам: - Многослойная архитектура - Четкое разделение слоев - Repository Pattern - Абстракция доступа к данным - Service Layer - Бизнес-логика в сервисах - CQRS - Разделение чтения и записи - Outbox Pattern - Асинхронная обработка событий - Idempotency - Надежность операций - Transaction Safety - Консистентность данных

Система спроектирована для: - ✅ Масштабируемости - ✅ Надежности - ✅ Поддерживаемости - ✅ Производительности