Целевая раскладка модулей

NOTE

Статус: Target design. Документ описывает целевую архитектуру. Сервисы, модули и контракты, упомянутые ниже, могут ещё не существовать в backend/. Правила маркировки — в 50-processes/documentation-standard.md.

Этот документ описывает целевую структуру backend-кода и архитектурные границы между модулями. Это не буквальное описание текущего дерева файлов.

Сейчас в репозитории уже есть минимальный scaffold:

  • backend/cmd/api-server/ — текущая точка входа HTTP API.
  • backend/internal/httpserver/ — простой handler с health/readiness endpoint’ами.
  • docs/docs/ и deploy/ — канонические docs и локальный контур.

Ниже описано, во что этот scaffold должен вырасти по мере реализации целевой архитектуры.

Планируемая раскладка backend

backend/
├── cmd/                         # точки входа процессов
│   ├── api-server/             # public/admin HTTP API
│   ├── ingestor/               # orchestration коннекторов и ingestion jobs
│   ├── matcher/                # matching engine
│   └── estimate-builder/       # meta-search / estimate pipeline

├── internal/
│   ├── core/                   # доменные и прикладные модули
│   │   ├── catalog/
│   │   ├── offers/
│   │   ├── pricing/
│   │   ├── search/
│   │   ├── matching/
│   │   ├── enrichment/
│   │   └── meta-search/
│   │
│   ├── connectors/             # интеграции с поставщиками
│   │   ├── etm/
│   │   └── ...
│   │
│   └── platform/               # общая инфраструктура
│       ├── config/
│       ├── errors/
│       ├── observability/
│       ├── messaging/
│       ├── rate-limiter/
│       ├── storage/
│       └── auth/

├── go.mod
└── ...

Структура одного модуля (bounded context)

Полное описание решения — ADR-0031.

Каждый модуль в internal/core/<bc>/ — это тонкое ядро плюс набор суб-модулей, где каждый суб-модуль соответствует одному агрегату (или use-case-bounded группе агрегатов).

internal/core/<bc>/
├── AGENTS.md
├── README.md
├── di.go                       # fx.Module() BC, собирает суб-модули
├── kernel/
│   ├── domain/                 # BC-wide VO / IDs / shared errors (по необходимости)
│   └── infra/                  # shared pg helpers и прочие адаптеры
└── <submodule>/                # = агрегат или use-case-bounded группа
    ├── AGENTS.md
    ├── README.md
    ├── di.go                   # fx.Module() суб-модуля
    ├── domain/                 # плоский layout
    ├── app/
    ├── infra/
    │   └── postgres/
    └── api/
        └── http/

Внутри одного суб-модуля слои (domain, app, infra, api) держатся плоскими. Дополнительное дробление (domain/model/, app/command/, app/query/, …) вводится только если суб-модуль действительно перерос плоскую раскладку — это указывается в его README.md.

Правила зависимостей

Разрешённый граф зависимостей внутри суб-модуля:

api  ──▶  app  ──▶  domain


         infra

Обязательные правила:

  • domain суб-модуля не знает о PG, Kafka, HTTP, Elasticsearch и других внешних технологиях. Разрешено: core/<bc>/kernel/domain и whitelist internal/platform/{clock,errors,money,ids}.
  • app импортирует только свой domain + тот же whitelist платформенных пакетов. Он не видит infra, api и тем более пакеты соседних суб-модулей.
  • infra реализует domain-порты и может импортировать kernel/infra + internal/platform/**.
  • api — тонкий слой; импортирует app своего суб-модуля + platform/httpx + platform/errors.
  • Соседние суб-модули (<bc>/<sub-a><bc>/<sub-b>) не импортируют пакеты друг друга напрямую. Если суб-модулю A нужна логика B, A объявляет consumer-owned порт в своём domain/, B-ориентированный адаптер — в своём infra/, проводка — в core/<bc>/di.go.
  • Доменные модули в internal/core/* не импортируют конкретные поставщиковые реализации из internal/connectors/*.
  • Межмодульное (между BC) взаимодействие — только через consumer-owned контракты + события + проводку в cmd/*/main.go.

Эти правила машинно проверяются линтером go-arch-lint — конфиг backend/.go-arch-lint.yml генерируется из дерева (инструмент backend/cmd/archlint-gen), и CI-job backend-archlint запускается в каждом merge request.

Как читать этот документ вместе с репозиторием

  • Если нужно понять, что уже можно запустить, смотрите ../40-operations/deployment.md и текущее дерево backend/.
  • Если нужно понять, как должен быть организован код при дальнейшем росте, используйте этот документ.
  • Если нужно понять, почему выбрана именно такая структура, смотрите ADR-001 и связанные документы в adr/.

Регистрация коннекторов

Ядро не знает о конкретных поставщиках заранее. В целевом состоянии registration/wiring коннекторов происходит в composition root процесса ingestion.

Принцип такой:

  • доменный ingestion-модуль работает только с интерфейсом Connector;
  • конкретный connector (etm, другой supplier) реализует этот интерфейс в своём модуле;
  • composition root регистрирует нужные реализации в зависимости от конфигурации окружения.

Внедрение зависимостей

Композиционный корень — fx.App (см. ADR-0030 и P25 в principles.md).

  • cmd/<process>/main.go = только fx.New(...) + app.Run();
  • платформенные модули — backend/internal/platform/di (Core, Observability, Postgres, Kafka, Redis, OpenAPI, Health, HTTP);
  • каждый BC предоставляет Module() в backend/internal/core/<bc>/di.go;
  • ресурсы с внешним соединением регистрируют fx.Lifecycle hooks; graceful shutdown — через fx;
  • тестовая композиция — fxtest.New + fx.Replace с mockery-моками. Unit-тесты на доменную/app-логику в DI не нуждаются и продолжают работать через обычные конструкторы.

Межмодульное и межсервисное взаимодействие

  • синхронные вызовы: internal HTTP/Connect endpoint’ы;
  • асинхронные вызовы: Kafka;
  • локально и в production-like окружениях сервисы общаются через сеть docker-compose, а не через localhost одного контейнера.

Общие библиотеки

internal/platform/* содержит только общую инфраструктуру:

  • config — конфигурация из env и файлов;
  • errors — общий registry кодов ошибок, typed error model, correlation helpers и policy/lint правила против raw string errors;
  • observability — OTel и logging;
  • messaging — Kafka adapters;
  • rate-limiter — Redis token bucket;
  • storage — helpers для PG, ES, ClickHouse, S3;
  • auth — shared auth utilities.

Бизнес-логика живёт не здесь, а в доменных модулях internal/core/*.