import { Module, NestModule, MiddlewareConsumer, RequestMethod } from '@nestjs/common'; import { ConfigModule, ConfigService } from '@nestjs/config'; import { TypeOrmModule } from '@nestjs/typeorm'; import { TenantContextModule, TenantContextMiddleware, SimpleTenantFinder, DEFAULT_TENANT_ID, } from '@iconsulting/shared'; import { ConversationModule } from './conversation/conversation.module'; import { ClaudeModule } from './infrastructure/claude/claude.module'; import { HealthModule } from './health/health.module'; @Module({ imports: [ // Configuration ConfigModule.forRoot({ isGlobal: true, envFilePath: ['.env.local', '.env'], }), // Tenant context module (global) TenantContextModule.forRoot({ tenantFinder: SimpleTenantFinder, middlewareOptions: { allowDefaultTenant: true, defaultTenantId: DEFAULT_TENANT_ID, excludePaths: ['/health', '/health/*'], }, isGlobal: true, }), // Database TypeOrmModule.forRootAsync({ imports: [ConfigModule], inject: [ConfigService], useFactory: (configService: ConfigService) => ({ type: 'postgres', host: configService.get('POSTGRES_HOST', 'localhost'), port: configService.get('POSTGRES_PORT', 5432), username: configService.get('POSTGRES_USER', 'iconsulting'), password: configService.get('POSTGRES_PASSWORD'), database: configService.get('POSTGRES_DB', 'iconsulting'), entities: [__dirname + '/**/*.orm{.ts,.js}'], // 生产环境禁用synchronize,使用init-db.sql初始化schema synchronize: false, // 连接池配置 - 优化并发性能 extra: { max: configService.get('DB_POOL_SIZE', 20), min: 2, idleTimeoutMillis: 30000, connectionTimeoutMillis: 5000, }, logging: configService.get('NODE_ENV') === 'development' ? ['query', 'error'] : ['error'], retryAttempts: 3, retryDelay: 1000, }), }), // Health check (excluded from global prefix) HealthModule, // Feature modules ConversationModule, ClaudeModule, ], }) export class AppModule implements NestModule { constructor( private readonly tenantMiddleware: TenantContextMiddleware, ) {} configure(consumer: MiddlewareConsumer) { consumer .apply((req: any, res: any, next: any) => this.tenantMiddleware.use(req, res, next)) .exclude( { path: 'health', method: RequestMethod.GET }, { path: 'health/(.*)', method: RequestMethod.ALL }, ) .forRoutes('*'); } }