4.0 KiB
Backend architecture
Выбор владельца
Найди существующий use case, его collaborators и tests до создания module/service. Сохрани ответственность в текущем module, если новая возможность относится к нему. Module — граница связного набора providers, а не папка для каждого endpoint.
| Решение | Owner |
|---|---|
| Route, request/response mapping, status/cookie | Controller, HTTP rules |
| Business use case, orchestration, domain validation | Feature service |
| Input shape/format | DTO + configured ValidationPipe |
| Атомарность/DB query | Сервис use case через PrismaService, Data |
| Внешний protocol, deadline/retry/limiting | Existing client, Integrations |
| Чистое вычисление/mapper без lifecycle и DI | Обычная функция рядом с domain owner |
| Bootstrap/config/global cross-cutting concern | AppModule, config, существующий common owner |
Безопасный путь: расширь текущий owner; выделяй collaborator, когда он скрывает самостоятельный инвариант или координацию. Не вводи CQRS, generic repository, interface с одной реализацией или base controller только ради шаблона Nest. Не превращай common в хранилище бизнес-логики и не переноси frontend модели сюда.
Существующие seams
TbankConnectionModule уже объединяет счета, портфель, операции, доходы и события.
Новый связанный use case обычно добавляется в него; создание отдельного module
требует собственной ответственности, не только нового файла.
- BrokerageOperationsController передаёт user/account/query в service, без финансовых вычислений в controller.
- TbankAccessService владеет connection/account access и generation; новые account use cases используют его вместо копирования guard/decrypt logic.
- decimal.ts — пример pure domain helper; Injectable и adapter для арифметики не нужны.
Наличие guard подтверждает session, но не владение account. При пересечении access boundary добавь Security. Ошибка upstream не должна обходить общий HTTP filter или превращать чужой account в доступный.
Logging
Единственный logger — nestjs-pino; application events используют существующий
StructuredLogger и
request context. Выбирай стабильное имя события и разрешённые scalar fields.
Wrapper отбрасывает неизвестные поля, но это не разрешение помещать secret
в message/stack: review sensitive logging обязателен.
Не добавляй второй logger или сырой request/body/error payload.
Источник rationale — ADR 008;
при secrets/user data читай также Security.
Проверка
npm run typecheck:app, npm run lint, targeted Jest по изменённому use case.
Смысл boundaries проверяется review: backend не имеет отдельного автоматического
FSD/DI architecture checker. Existing tests и build не доказывают правильный owner.