Utils-клиенты (libs/apis/utils)
libs/apis/utils содержит тонкие NestJS-обёртки над внешними инфраструктурными клиентами (БД, кэш, объектное хранилище, брокер сообщений, почта). Каждая обёртка — отдельная Nx-библиотека с модулем + сервисом, инкапсулирующая создание соединения, его жизненный цикл (OnModuleInit / OnModuleDestroy / OnApplicationShutdown) и типизированный API. Конфигурация в каждый клиент приходит из соответствующего конфиг-модуля из libs/apis/configs.
Сводная таблица
Заголовок раздела «Сводная таблица»| Клиент | Оборачивает (npm) | Импорт (алиас) | Как подключается | Источник конфига |
|---|---|---|---|---|
prisma-client | @prisma/client (PrismaClient) | @crewsforge-back/apis/utils/prisma-client | PrismaClientModule импортирует AppConfigModule; сервис extends PrismaClient, $connect в onModuleInit, $disconnect в onModuleDestroy | AppConfigService (уровень логов зависит от env) |
redis-client | redis (node-redis v4, createClient) | @crewsforge-back/redis-client | Провайдер-фабрика REDIS_CLIENT создаёт и connect()-ит клиент; сервис инжектит его через @Inject(REDIS_CLIENT) | RedisConfigService (config-shared-redis) |
s3-client | @aws-sdk/client-s3 + @aws-sdk/s3-request-presigner | @crewsforge-back/s3-client | Провайдер-фабрика S3_CLIENT создаёт new S3Client({...}); сервис инжектит клиент и S3ConfigService | S3ConfigService (config-shared-s3) |
rabbit-client | amqplib | @crewsforge-back/rabbit-client | Сервис вручную открывает соединение/канал в методе connect() (не в фабрике), хранит connection+channel | RabbitConfigService (config-shared-rabbit) |
mailer-client | @nestjs-modules/mailer (nodemailer SMTP) | @crewsforge-back/mailer-client | MailerModule.forRootAsync(...) с фабрикой из SmtpConfigService; сервис оборачивает MailerService | SmtpConfigService (config-shared-smtp) |
prisma-client
Заголовок раздела «prisma-client»Обёртка над PrismaClient. PrismaClientService extends PrismaClient и реализует OnModuleInit ($connect) / OnModuleDestroy ($disconnect). Уровень логирования зависит от окружения: в non-production добавляются info, warn, query к базовому error (через AppConfigService.env). Модуль импортирует AppConfigModule, провайдит и экспортирует сервис. Регистрируется через обычный imports: [PrismaClientModule] (без forRoot).
Сериализация денег. Конструктор сервиса вызывает enableBigIntJsonSerialization() из
@crewsforge-back/apis/core/money. Причина: денежные поля схемы — BigInt в минорных единицах,
а JSON.stringify этот тип не умеет и бросает TypeError — любой ответ с суммой отдавал бы 500.
Настройка живёт здесь, а не в main.ts каждого сервиса, потому что источник BigInt в
приложении — именно Prisma: так её получают и тесты, собирающие AppModule напрямую. В ответах
сумма представлена целым числом минорных единиц; значение за пределами безопасного целочисленного
диапазона JSON даёт RangeError, а не молчаливую потерю точности.
Transactional adapter (@nestjs-cls). Сам PrismaClientModule НЕ содержит настройки транзакций. Декларативные транзакции подключаются на уровне каждого приложения в app.module.ts через nestjs-cls:
ClsModule.forRoot({ plugins: [ new ClsPluginTransactional({ // ... adapter: new TransactionalAdapterPrisma({ prismaInjectionToken: PrismaClientService }), }), ],})Адаптер @nestjs-cls/transactional-adapter-prisma привязывается к PrismaClientService через prismaInjectionToken. После этого:
- Сервисы помечают методы декоратором
@Transactional()(@nestjs-cls/transactional) — весь метод выполняется в одной транзакции через CLS-контекст. - Репозитории инжектят
TransactionHost<TransactionalAdapterPrisma>и работают черезthis.txHost.tx.<model>..., что автоматически использует активную транзакцию (или обычное соединение вне транзакции).
Так одно и то же соединение Prisma участвует и в обычных запросах, и в транзакциях без ручного проброса tx. Настройка присутствует во всех приложениях: auth-api, user-api, admin-api, project-api, ai-agent-service.
redis-client
Заголовок раздела «redis-client»Обёртка над node-redis. Клиент создаётся провайдером-фабрикой под токеном REDIS_CLIENT (Symbol): createClient({ socket: { host, port }, password }), вешается обработчик error, вызывается await client.connect(). RedisClientService инжектит клиент через @Inject(REDIS_CLIENT) и предоставляет удобный API: set (с опциональным TTL через EX), get, множества (sAdd/sRem/sMembers), deleteByPattern (итеративный SCAN + DEL), геттер client. При onModuleDestroy / onApplicationShutdown — корректный close() + destroy(). Модуль экспортирует и токен REDIS_CLIENT, и сервис.
s3-client
Заголовок раздела «s3-client»Обёртка над AWS SDK v3. Клиент new S3Client({ endpoint, region, credentials, forcePathStyle: false }) создаётся провайдером-фабрикой под токеном S3_CLIENT (Symbol) из S3ConfigService. S3ClientService инжектит клиент и конфиг и предоставляет доменный API: uploadFile / deleteFile / getFileUrl (presigned URL через getSignedUrl, TTL по умолчанию 3600с, ACL по умолчанию private), а также билдеры путей и хелперы для аватаров/портфолио пользователя (buildUserAvatarPath, uploadUserAvatar, getUserPortfolioUrl и т.д.). Бакет берётся из S3ConfigService.bucket. При shutdown — s3Client.destroy().
rabbit-client
Заголовок раздела «rabbit-client»Обёртка над amqplib. В отличие от redis/s3, соединение НЕ создаётся фабрикой при старте модуля — RabbitClientService открывает его вручную методом connect(): строит URL amqp://user:pass@host:port, создаёт connection и channel, выставляет prefetch из конфига, вешает обработчики error/close. API: assertExchange, assertQueue (durable), bindQueue, publish (persistent JSON-сообщения), consume (с авто-ack при успехе и nack(false,false) при ошибке через Logger). При onModuleDestroy / onApplicationShutdown закрывает канал и соединение. Модуль импортирует RabbitConfigModule.
mailer-client
Заголовок раздела «mailer-client»Обёртка над @nestjs-modules/mailer (поверх nodemailer). Модуль подключает транспорт через MailerModule.forRootAsync(...): SMTP-транспорт (host, port, secure: false, auth: { user, pass }, tls.rejectUnauthorized: false) и defaults.from — всё из SmtpConfigService. MailerClientService оборачивает MailerService и даёт методы: send(options), sendTemplate(to, subject, template, context, extras), sendPlain(to, subject, text, html, extras), sendBulk(mails[]), геттер client. При shutdown пытается аккуратно закрыть транспорт. Используется провайдером email-sender-api (см. docs/03-services/email-sender.md).