ENTITY_NAME в пути — placeholder каталога вашей сущности, например product для Product; EntityName — её тип в коде. Подставьте фактические имена своего проекта. Примеры Article ниже показывают отдельную сущность, а не обязательный модуль любого приложения.
HTTP и PostgreSQL находятся во внешних адаптерах. Прикладной сервис Article работает с интерфейсом Repository, а не с конкретным драйвером БД. Реализации подключаются при сборке приложения в bootstrap.
Custom-hooks входят в тот же сценарий через объявленные интерфейсы. Поэтому типовую обработку можно обновлять генерацией, а собственные проверки и действия — развивать в custom-коде.
За что отвечает каждый пакет
| Пакет | Ответственность |
|---|---|
domain |
Типы сущностей и общие ошибки. Не импортирует HTTP и PostgreSQL. |
app/ENTITY_NAME |
Команды, запросы и сценарии Article. Объявляет интерфейсы Repository и Hooks. |
adapters |
HTTP-обработчики и PostgreSQL-репозиторий с pgx и явным SQL. |
infrastructure |
Подключение к БД, миграции и технические механизмы. |
generated/bootstrap |
Сборка конфигурации, репозитория, сервиса, hooks и HTTP-обработчиков. |
Дерево показывает основные пути на примере Article, а не полный список файлов. Набор файлов зависит от модели и возможностей проекта.
backend/ · пример Article с CRUD
cmd/api/main.go
internal/
├── domain/
│ └── article.go
├── app/
│ ├── article/
│ │ ├── commands.go
│ │ ├── queries.go
│ │ └── service.go
│ └── listquery/query.go
├── adapters/
│ ├── http/generated/
│ │ ├── article_handler.go
│ │ ├── article_mapper.go
│ │ └── article_routes.go
│ └── postgres/generated/
│ ├── article_repository.go
│ └── ENTITY_NAME_queries.sql
├── infrastructure/
│ ├── database/database.go
│ └── migrations/migrations.go
├── generated/
│ ├── bootstrap/app.go
│ ├── config/config.go
│ ├── registry/entities.go
│ └── customcontracts/composition.go
└── custom/
├── app/
│ ├── composition.go
│ └── routes.go
└── ENTITY_NAME/hooks.go
domain — типы сущностей и ошибки
Здесь определены типы сущностей и общие ошибки. Пакет не импортирует HTTP и PostgreSQL: формат запроса преобразует HTTP-mapper, строки БД — адаптер хранения. Файлы моделей остаются под управлением генератора, хотя в их пути нет слова generated.
app — сценарии и их интерфейсы
В ENTITY_NAME/service.go объявлены Repository, Hooks и Service. Команды и запросы задают входные данные сценариев. Интерфейсы находятся в том пакете, который их использует: сервис определяет, какие операции ему нужны от хранилища и custom-расширений.
adapters — HTTP и PostgreSQL
HTTP-обработчик принимает запрос, вызывает прикладной сервис и формирует ответ. PostgreSQL-репозиторий реализует интерфейс Repository с помощью pgx и явного SQL. Во время выполнения сервис вызывает репозиторий через интерфейс; в исходниках адаптер зависит от контракта app, а не наоборот.
infrastructure — технические механизмы
Подключение к БД, запуск миграций и хранение файлов при включённой media-функциональности отделены от обработки Article. Так настройка соединений и хранилищ не смешивается с логикой работы над записью.
bootstrap — подключение реализаций
cmd/api/main.go запускает приложение, собранное в generated/bootstrap/app.go. Bootstrap связывает конфигурацию, репозиторий, сервис, hooks и HTTP-обработчики. Собственные зависимости подключаются через custom composition, поэтому редактировать сгенерированный bootstrap не требуется.
Зависимости пакетов и порядок вызовов
adapters/http ──────→ app/ENTITY_NAME ──────→ domain
adapters/postgres ──→ app/ENTITY_NAME
custom/article ─────→ app/ENTITY_NAME + domain
bootstrap → adapters + app + infrastructure + custom
Стрелки показывают зависимость исходного кода: пакет слева использует контракт справа. При обработке запроса сервис может вызвать PostgreSQL-репозиторий через интерфейс, не импортируя пакет postgres. Custom указывает на владельца реализации, а не добавляет пятый архитектурный слой.
Путь запроса: создание Article
После проверки доступа на HTTP-границе успешное создание записи проходит следующие шаги.
HTTP → Service
Обработчик читает тело запроса, преобразует его в данные сущности и передаёт сервису Article.
validateCreate → BeforeCreate
Сервис проверяет стандартные требования, затем вызывает custom-hook. В нём можно выполнить дополнительную проверку или преобразовать данные.
Repository.Create
PostgreSQL-адаптер записывает данные в БД и возвращает созданную сущность.
AfterCreate → HTTP-ответ
После создания сервис вызывает AfterCreate. Затем результат преобразуется в формат ответа API.
Если BeforeCreate возвращает ошибку, запись не выполняется. AfterCreate вызывается уже после Repository.Create: его ошибка сама по себе не гарантирует откат записи. Если твоим действиям нужна общая транзакция, её поведение нужно явно определить в проекте.
Где добавить свою логику
Используй backend/internal/custom/ENTITY_NAME/hooks.go для проверок и действий в сценариях сущности. Через custom/app/composition.go подключай зависимости. Для отдельных маршрутов предусмотрены custom/app/routes.go и RegisterRoutes. Не редактируй generated bootstrap для подключения расширений.