- Replace 4 duplicate meta DTOs (AuthResponseMetaDto, PortfolioResponseMetaDto, BrokerResponseMetaDto, ScreenerResponseMetaDto) with shared ApiResponseMeta - Wrap shares getShare() in ApiEnvelopePayload (was raw object, unlike bonds) - Remove unnecessary CacheModule import from securities module - Update portfolio controller nullDataEnvelopeSchema to use shared ApiResponseMeta - All 116 tests pass
2.6 KiB
2.6 KiB
Backend Architecture Improvements — Plan
Подход
Разбиваем на итерации от самых безопасных (только DTO/косметика) к самым рискованным (сплит сервисов). Каждая итерация — отдельная задача с отдельным commit'ом.
Итерации
Итерация 1: Shared envelope DTO + fixes
- Вынести
ApiResponseMetaвcommon/dto/api-response.dto.tsкак единый класс, убрать дубликаты*ResponseMetaDtoв модулях. - Убрать
AuthResponseMetaDto→ заменить наApiResponseMeta. - Поправить
shares/shares.service.ts:getShare()— обернуть результат вApiEnvelopePayload. - Убрать лишний импорт
CacheModuleизsecurities/securities.module.ts. - Убрать
PortfolioResponseMetaDtoиBrokerResponseMetaDto— заменить наApiResponseMeta.
Итерация 2: Screener caching + server-side пагинация
- Добавить кеширование полного screener-датасета при пустом фильтре.
- Ключ кеша:
'screener:full'с TTL изapp.cache.marketDataTtl.
Итерация 3: Domain exception hierarchy
- Создать
common/exceptions/с базойDomainExceptionи конкретными классами. - Обновить
HttpExceptionFilterдля map'инга доменных → HTTP исключений. - Заменить
NotFoundExceptionнаEntityNotFoundExceptionв сервисах.
Итерация 4: Health check improvement
- Добавить проверки: Prisma ping, MOEX
/health, T-Bank gRPC connectivity. - Обновить
HealthResponseDtoс полемchecks.
Итерация 5: RequestLoggingMiddleware через DI
- Перенести middleware в корректный DI-контекст через
configure()вAppModule.
Итерация 6 (отдельный эпик): MoexClientService split
- Выделить
MoexSecuritiesClient,MoexMarketDataClient,MoexCandlesClient. - Общий rate limiter + circuit breaker в shared utils.
Data Flow
Controller → Service → [CacheService.getOrFetch] → [MoexClient* или TBank*] → Внешнее API
↓
ApiEnvelopePayload<T>
↓
TransformInterceptor → ApiResponse<T>
После итерации 1 все модули следуют этому потоку единообразно.