# Backend HTTP API ## Выбор boundary Сначала определи, меняется wire contract или только реализация существующего use case. Для route/request/response/status/error shape читай [HTTP semantics](../../../docs/architecture/http-api.md) и [общий contract workflow](../../../docs/development/runtime-openapi-verification.md). | Проверка | Где выполнять | | --- | --- | | Тип/формат/диапазон входа | Runtime DTO class с class-validator/class-transformer | | Согласованность полей, бизнес-ограничение | Feature service/domain helper | | Session и identity | Existing guard/strategy | | Доступ user к конкретному account | Existing access service | | HTTP envelope/безопасная ошибка | Общий HttpExceptionFilter | Controller объявляет contract и делегирует; не обращается напрямую к Prisma/gRPC и не выполняет финансовые расчёты или сложную оркестрацию. Controller вызывает application use case/service. Identity берётся из verified `request.user`, не из body/userId, предоставленного клиентом. Access rules активируют Security. ## DTO и errors DTO — runtime class: TS interface не предоставляет validation metadata. `*.controller.ts` и `*.dto.ts` остаются около HTTP boundary, в root компактного module или presentation. DTO можно передать application boundary при совпадении формы; отдельный Input с теми же полями не нужен. Domain не импортирует DTO: например, чистые денежные расчёты используют `Money`, а Swagger — `MoneyDto`. Нормализованная форма input нужна только при смысловом отличии от wire contract; выбор suffix принадлежит [Architecture](backend-architecture.md). ValidationPipe уже настроен в `configureApp` (`transform`, `whitelist`). Не обещай rejection неизвестных fields: `forbidNonWhitelisted` не включён. Для query numbers/arrays выбирай явное преобразование и валидаторы, как в [operations DTO](../../src/modules/investments/operations/presentation/brokerage-operation.dto.ts). Swagger metadata описывает те же required/optional/nullable/enum/range значения. Используй типизированные response DTO, `ApiOkResponse`/другой фактический status и существующий `ApiProblemResponses`. При новых ошибках задай публичный stable `code`; сообщение внутреннего exception не является UI contract. Не возвращай raw upstream error, Prisma record с secrets или stack. Текущая форма ошибок описана у HTTP owner; не добавляй поля RFC только потому, что они встречаются в tutorial. **Безопасный путь:** используй exception и общий filter, а не локальный `res.status(...).json(...)`. Исключение — транспортная операция вроде cookie; следуй существующему auth controller с `passthrough` и явно заданным status. ## Пример и проверка [Operations controller](../../src/modules/investments/operations/presentation/brokerage-operations.controller.ts) показывает guard, user.sub, DTO query и service delegation. Для нового field обновляй canonical source и generated artifacts в определённом направлении; body type frontend не исправляется вручную. Проверь happy path и применимые invalid input/access/not-found/domain/upstream errors на boundary, где они возникают. Unit вызов controller не запускает pipes, guards или serialization. `npm run test:openapi-contract` проверяет schema parity, но не поведение invalid request; выбирай соответствующий test по [Testing](backend-testing.md). Финальный gate не заменяет semantic review ошибок.