// services/api/src/app-cn.module.ts // 根模块:Prisma(@Global,封装 @photo/db-cn)、日志(nestjs-pino / pino-http)、 // request-id 中间件、全局异常过滤器、全局校验管道(Task 13 起,DTO 经 // class-validator 声明、ValidationPipe 强制,失败由过滤器映射 400 VALIDATION_FAILED)、 // /v1/health、/v1/auth/*(Task 13)。 // 功能模块(albums/uploads/photos/public)自 Task 15+ 起逐个加入。 // 过滤器/管道经 APP_FILTER/APP_PIPE、中间件经 NestModule 在模块层注册——e2e 直接 // import 本模块即可获得与生产一致的管线(全局前缀除外,由入口设置)。 import { type MiddlewareConsumer, Module, type NestModule, ValidationPipe, } from '@nestjs/common'; import { APP_FILTER, APP_PIPE } from '@nestjs/core'; import { LoggerModule } from 'nestjs-pino'; import { AlbumsModule } from './albums/albums.module'; import { AdminModule } from './admin/admin.module'; import { AllExceptionsFilter } from './all-exceptions.filter'; import { AuthModule } from './auth/auth.module'; import { AdsModule } from './ads/ads.module'; import { EmbedModule } from './embed/embed.module'; import { HealthController } from './health.controller'; import { PhotosModule } from './photos/photos.module'; import { PrismaModule } from './prisma/prisma.module'; import { PublicModule } from './public/public.module'; import { RequestIdMiddleware } from './request-id.middleware'; import { SyncModule } from './sync/sync.module'; import { UploadsModule } from './uploads/uploads.module'; import { UserSyncModule } from './user-sync/user-sync.module'; // P2 Task 2:logger 装配选项(genReqId/redact/level)收敛至 shared,与 ov 入口 // 共用单一来源;此处仅消费,行为不变(P1 e2e 套件守护)。 import { createLoggerOptions } from './shared/logger-options'; @Module({ imports: [ // @Global:功能模块(Task 12+)直接注入 PrismaService,无需 re-import。 PrismaModule, AuthModule, // 相册域(Task 14 起步:PermissionsService;控制器自 Task 15 加入)。 AlbumsModule, // 上传域(Task 18 init;Task 19 renew/complete/history)。 UploadsModule, // 公开(观众端)域(Task 22 getPublicAlbum;Task 23 公开照片读)。 PublicModule, // 照片管理域(Task 24:可见性生命周期 PATCH/DELETE;P1b Task 4 增补 // /albums/{albumId}/photos 管理列表)。 PhotosModule, // 管理辅助域(P1b Task 4:/admin/users 账号前缀查询)。 AdminModule, // 展示位管理域(P4b Task 2:/admin/embed-slots,slot-state 事件源)。 EmbedModule, // 广告位管理域(ads-carousel Task 6 起:/admin/ads/uploads 直传初始化; // CRUD Task 7——ad.* 事件源,仅 cn 入口装配)。 AdsModule, // 内部同步域(P2 Task 3:/internal/sync/bootstrap|reconcile,HMAC 鉴权, // 仅 cn 入口装配——cn 是内容同步的源端)。 SyncModule, // 用户同步域(P4a Task 7:mock 源定期同步 + /admin/user-sync 管理端点 + // setInterval 调度器——仅 cn 装配,ov 入口不碰)。 UserSyncModule, LoggerModule.forRoot(createLoggerOptions()), ], controllers: [HealthController], providers: [ { provide: APP_FILTER, useClass: AllExceptionsFilter }, // 全局校验管道(Task 13):whitelist 剥离 DTO 未声明的属性(契约未禁未知 // 字段,剥离而非拒绝);校验失败抛 BadRequestException → 过滤器映射 // 400 VALIDATION_FAILED。经 APP_PIPE 在模块层注册,e2e 复用同一管线。 { provide: APP_PIPE, useFactory: () => new ValidationPipe({ whitelist: true }), }, ], }) export class AppCnModule implements NestModule { configure(consumer: MiddlewareConsumer): void { consumer.apply(RequestIdMiddleware).forRoutes('*'); } }