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

Архитектура сервиса

Сервер DataHUB (backend) — единое Spring Boot-приложение, но логически разделено на два независимых контура: LK-контур для административного UI и Exchange-контур для шинной части. У каждого контура своя точка входа nginx, свои контроллеры, своя авторизация и своя нагрузочная характеристика. Несмотря на это, оба контура работают с одной БД и одним брокером — общая модель данных не дублируется.

Карта пакетов

Исходный код Сервера DataHUB разделён по верхним пакетам Java следующим образом.

com.datahub
├── backend          ← LK-контур: админ-UI, авторизация, нотификации
│   ├── api          ← REST-контроллеры LK
│   │   ├── controller   admin / auth / bus / health / user
│   │   ├── security     JWT, auth-фильтры, verification, util
│   │   └── errors       глобальная обработка ошибок
│   ├── config       Spring-конфигурация LK-домена
│   ├── db           Entity / Repository / Health (JPA)
│   ├── notification email/SMS-пайплайн (rabbitmq receiver/transmitter)
│   └── service      сервисы бизнес-логики LK
├── exchange         ← Exchange-контур: шинная часть
│   ├── cache        кеши конфигурации обмена
│   ├── config       Spring-конфигурация exchange-домена
│   ├── controller   REST-контроллеры обмена
│   ├── error        обработка ошибок обмена
│   ├── rabbit       работа с RabbitMQ (model, util)
│   ├── service      сервисы бизнес-логики обмена
│   └── web          web-слой обмена
├── dto              ← общие DTO, по доменам
│   ├── base
│   ├── client / clientsystem / messageclass / messageroute
│   ├── user (auth / changeemail / changepassword / me)
│   └── validation
└── logging          ← единый Logger

Граница между com.datahub.backend.* и com.datahub.exchange.* — основная архитектурная инвариа­нта: LK-контур не вызывает напрямую логику exchange-контура и наоборот. Общее — только модель данных в dto и БД.

LK-контур

Обслуживает административный интерфейс DataHUB. Внешний доступ — через nginx на lk.<domain>/api/*, упирающийся в frontend (Next.js) и его REST-вызовы.

Контроллеры

Пакет Назначение
api.controller.admin Управление системами, пакетами, маршрутами, пользователями (требует роли администратора)
api.controller.auth Регистрация, вход, 2FA, сброс пароля, refresh токена — см. Безопасность
api.controller.user Профиль текущего пользователя (/me), смена пароля и email
api.controller.bus Просмотр состояния обмена со стороны админа — очереди, подписки, маршруты
api.controller.health Healthcheck-эндпоинты

Авторизация

api.security — основной модуль авторизации платформы. JWT (access 15m, refresh 7d), pepper-хеширование паролей, верификация email/2FA через OTP. Полная схема — в Безопасности и в Интеграции / Авторизация.

Нотификации

notification.* — асинхронная отправка email и SMS из админ-сценариев (подтверждение почты, 2FA-код, сброс пароля, нотификация о важных событиях).

Архитектурно:

  • notification.service — публикует событие в RabbitMQ-очередь нотификаций.
  • notification.rabbitmq.transmitter — продюсер (помещает сообщение в очередь).
  • notification.rabbitmq.receiver — консьюмер (читает из очереди и вызывает sender).
  • notification.sender — обёртки над почтовым клиентом и SMS-провайдером.

Внутренняя очередь нужна, чтобы сценарии админ-UI не зависели от состояния SMTP/SMS-провайдера: backend публикует событие — UI получает мгновенный ответ; реальная отправка идёт асинхронно.

Exchange-контур

Обслуживает обмен между подключёнными системами. Внешний доступ — через nginx на exchange.<domain>/*, к которому подключаются клиентские системы напрямую (1С, ERP, мобильные приложения).

Контроллеры и web

exchange.controller и exchange.web — REST-эндпоинты обмена: приём сообщения от отправителя, выдача сообщений получателю, подтверждение обработки, операции с пакетами. Контрактно эти эндпоинты документированы через OpenAPI/Swagger; их состав описан в Интеграции / Транспортный API.

Работа с RabbitMQ

exchange.rabbit — взаимодействие с брокером сообщений. Управляет публикацией сообщений в очереди подписанных получателей, чтением из очередей при выдаче. Подробнее — в Работе с очередями.

Кеш

exchange.cache — Caffeine-кеш над конфигурацией обмена (системы, маршруты, пакеты). Конфигурация обмена меняется относительно редко, а читается на каждом запросе — кеш снимает нагрузку с БД.

При изменении конфигурации через LK-контур backend сбрасывает соответствующий кеш — либо явно (по событию), либо по TTL.

Сервисы и обработка ошибок

exchange.service — бизнес-логика приёма и выдачи сообщений: валидация, маршрутизация, журналирование. exchange.error — отдельная обработка ошибок, специфичных для шинного контура (отличается от админ-ошибок: другие коды, другие сообщения, другая семантика для клиентских систем).

Общие компоненты

DTO (com.datahub.dto.*). Объекты передачи данных, общие для обоих контуров. Сгруппированы по доменам: client, clientsystem, messageclass, messageroute, user/*, base, validation. Один DTO может использоваться и в LK-контроллере (для отображения в админке), и в Exchange-контроллере (для обмена) — но это сознательное решение, не «случайное переиспользование».

База данных (com.datahub.backend.db). Сущности и репозитории JPA. Backend.db живёт под пакетом backend, но используется и из exchange.* — общая модель данных, общий контекст транзакций.

Логирование (com.datahub.logging). Единый Logger, обёрнутый над SLF4J. Используется во всех пакетах для единообразного формата сообщений и контекста (system-id, request-id, message-id, package).

Жизненный цикл запросов

LK-запрос

flowchart LR
    B[Браузер] --> N["nginx · lk.&lt;domain&gt;"]
    N --> F["Next.js SSR/API"]
    F --> LK["backend · LK-controller"]
    LK --> P[("PostgreSQL")]
    LK -.->|"если требуется"| MQ["RabbitMQ · нотификации"]

Типичная LK-операция: пользователь меняет настройку маршрута → frontend POST'ит в /api/admin/... → LK-контроллер валидирует JWT → сохраняет в PostgreSQL → сбрасывает соответствующий кеш Exchange-контура → возвращает результат.

Exchange-запрос

flowchart LR
    IS["Клиентская ИС"] --> N["nginx · exchange.&lt;domain&gt;"]
    N --> EX["backend · Exchange-controller"]
    EX --> C["Caffeine · кеш маршрутов"]
    C -.->|"cache miss"| P[("PostgreSQL")]
    EX --> MQ["RabbitMQ · публикация / чтение"]

Типичная Exchange-операция: ИС-отправитель POST'ит сообщение → Exchange-контроллер валидирует авторизацию → читает маршруты из кеша → публикует сообщение в RabbitMQ-очереди подписанных получателей → возвращает подтверждение приёма. В БД при этом ничего не пишется — централизованного «лога доставки сообщений» нет.

Healthcheck

Backend публикует:

  • /api/actuator/health — встроенный Spring Actuator: liveness, readiness, состояние БД, RMQ, кешей.
  • /healthz — упрощённый healthcheck для nginx и docker.

Подробнее — в Развертывание / Мониторинг и логи.

Почему монолит, а не микросервисы

Разделение LK ↔ Exchange сделано на уровне пакетов и контроллеров, но не на уровне отдельных деплоев. Это сознательный выбор:

  • Общая БД и общая модель данных — раздробить их между двумя сервисами означало бы либо разделить транзакции (сложно для конфигурации), либо ввести inter-service-вызовы (дополнительная нагрузка и точки отказа).
  • LK-контур обычно недогружен (десятки запросов в секунду от админов), Exchange — сильно нагружен; в монолите общие ресурсы (JPA-pool, кеш) шарятся естественно.
  • Один артефакт = более простой релиз и эксплуатация: одно обновление, одна проверка совместимости.

Если в будущем нагрузка Exchange-контура потребует отдельного масштабирования — описанная архитектура позволяет вынести его в отдельный сервис без существенной переработки модели. См. Масштабирование.

Что дальше