-
admin-- приложение-админка.auth-- сервис авторизации.cfm-- сервис отправки OTP-кодов подтверждений.front-- см. admin/front/README.md.gateway-- api-шлюз для BE, точка входа.
-
infrastructure-- инфраструктурные элементы, вынесенные отдельно для упрощения. -
monitoring-- приложение для мониторинга системы. -
node-- обвязки физического сервера, на котором развернут проект. При физическом разделении компонентов эти обвязки были бы частью каждого отдельно развернутого компонента.
Схема:
Структура компонента нижнего уровня:
|- app -- код приложения, конфиги, ресурсы, ...
|- build -- элементы сборки контейнеров (Dockerfile'ы, конфиги, ...).
|- state -- состояние развернутого приложения, сохраняемое между запусками (логи, данные, ...).
Структура основана на Hexagonal Architecture.
Для некоторых компонентов (например,
front,gateway, ... ) такая организация может быть излишней -- однако, применяется намеренно однообразия ради. Спорный момент...
Используемые слои:
-
cmd / api -- клиенты ядра приложения (например, http-сервер, планировщик, ...), primary-adapter`ы. Каждый клиент обращается к ядру через Контейнер -- набор компонентов и операций, используемых этим клиентом ядра. Если разница в наборах незначительна, контейнер может быть общим для нескольких клиентов.
-
adapt -- не является полноценным слоем, содержит secondary-adapter`ы. Выделен из классического слоя инфраструктуры для наглядности.
-
opera -- классический операционный слой.
-
domain -- классический доменный слой.
-
data -- альтернатива комбинации opera и domain для случаев, ориентированных на прямую работу с данными.
-
infra -- классические инфраструктурные элементы, за исключением secondary-adapter`ов.
-
std -- утилитарный код, который можно рассматривать в рамках проекта как часть стандартной библиотеки языка. Например, тип данных Email, функции работы с массивами, ...
-
env -- "мнимый" слой окружения.
Направление зависимостей -- строго сверху вниз: вышележащий слой имеет доступ только к примыкающим снизу слоям (см. схему).
Исключением является std и использование неизменяемых объектов из всех нижележащих слоев в качестве DTO для уменьшения количества трансформаций.
Доступ к смежным слоям выполняется через интерфейсы и адаптеры.
В зависимости от приложения те или иные слои могут отсутствовать.
client не входит в приложение, но изображен на схеме для наглядности.
TODO
TODO
-
Копировать
.env.exampleв.env, переопределить переменные при необходимости. -
Выполнить
. tools.sh up
Файлы не распределены по папкам компонентов (для пущей инкапсуляции), поскольку могут использовать общие элементы (например, DEPLOY_... переменные окружения). Также такой подход усложнил бы использование переменных окружения и запуск проекта (например, при конфликте переменных API_KEY в файлах /cmp1/.env и /cmp2/.env).
Для экспорта логов в систему мониторинга используются grafana-alloy-контейнеры.
Для ротации логов на сервере используется logrotate.
При текущей конфигурации (alloy-экспортеры c интервалами сбора 5s и logrotate в режиме copy-truncate) возможна ситуация, когда между сборами логов alloy-экспортером произойдет запись новых логов и ротация файла. Тогда логи, записанные в промежуток между последним сбором и ротацией, не будут собраны, поскольку уже "архивированы".
Кроме того, logrotate с copy-truncate сам по себе может терять логи во время выполнения (см. в конфиге logrotate).
Включение "архивных" файлов в сбор и tail_from_end=false подберет пропущенные, но и продублирует все ранее собранные логи, поскольку новый файл -- новый поток (как минимум метка "имя файла" изменится).
Простое и однозначное решение не было найдено, но вероятность промаха мала -- оставлено нерешенным.
Генерация кода из proto-файлов настроена на пакет с именем pb -- для api/grpc/pb.
Поэтому в infra/clients/{service} пакет pb используется для удобства обновления клиента простым копированием файлов.
Выделять подобный код в общие пакеты в данном проекте излишне.
Сервис может содержать grpc-сервер и несколько grpc-клиентов для других сервисов.
Имена файлов, из которых сгенерен был grpc-код сервера и всех клиентов должны отличаться в пределах сервиса,
иначе возникнет ошибка panic: proto: file ".proto" is already registered.
Это значит, что, например, нельзя использовать файл с именем ".proto" для генерации сервера в сервисе auth
и использовать для реализации клиента скопированные файлы из сервиса cfm,
которые также были сгенерированы по файлу с именем ".proto" -- нужно использовать "auth.proto" и "cfm.proto".
См. node/build/prometheus-exporter/README.md.
Используется по аналогии с protobuf/grpc для стандартизации и удобства использования структур запросов/ответов.
В gateway ендпоинты разделены по бандлам для простоты восприятия.
Каждый бандл, если в нем используется openapi, содержит свою спецификацию -- это накладывает некоторые ограничения:
-
необходимо дублировать общие компоненты, которые требуются спецификациям нескольких бандлов:
- папку
commonс общими элементами components.securitySchemesиз-за ограничений протокола и генератора (allOfи$ref).
- папку
-
необходимо прописывать полный путь в урле внутри бандла, хотя напрашивается использование относительного. Технически это можно было бы сделать в точке инициализации роутера, передав префикс в BaseUrl-опции, однако в получаемой документации этот префикс не будет добавлен, что будет сбивать с толку.
В спецификациях сокращено количество описываемых HTTP‑статусов до трёх базовых сценариев:
200-- успешный ответ;422-- ожидаемые неуспешные сценарии (бизнес‑ошибки) с уточняющим полемcodeи текстовым сообщениемmessage.редиректы(например, 307 Temporary Redirect).
Все прочие HTTP-коды в спецификации не описываются: они считаются внештатными ситуациями, багами и т.д.
Такой подход выбран для упрощения как спецификации, так и использования сгенерированного кода, поскольку генератор создает отдельный тип (структуру) респонса для каждого описанного в спецификации кода ответа.

