import { Module, Logger as NestLogger } from '@nestjs/common'; import { ConfigModule, ConfigService } from '@nestjs/config'; import { APP_FILTER, APP_GUARD, APP_INTERCEPTOR } from '@nestjs/core'; import { ThrottlerModule, ThrottlerGuard } from '@nestjs/throttler'; import { CacheModule } from '@nestjs/cache-manager'; import { redisStore } from 'cache-manager-redis-yet'; import { LoggerModule } from 'nestjs-pino'; import { I18nModule, AcceptLanguageResolver, HeaderResolver, QueryResolver, } from 'nestjs-i18n'; import * as path from 'path'; import { ServeStaticModule } from '@nestjs/serve-static'; // Config import { appConfig, databaseConfig, jwtConfig, redisConfig, i18nConfig, featuresConfig, throttleConfig, } from './config/configuration'; import { geminiConfig } from './modules/gemini/gemini.config'; import { validateEnv } from './config/env.validation'; // Common import { GlobalExceptionFilter } from './common/filters/global-exception.filter'; import { ResponseInterceptor } from './common/interceptors/response.interceptor'; // Database import { DatabaseModule } from './database/database.module'; // Modules import { AuthModule } from './modules/auth/auth.module'; import { UsersModule } from './modules/users/users.module'; import { AdminModule } from './modules/admin/admin.module'; import { HealthModule } from './modules/health/health.module'; import { GeminiModule } from './modules/gemini/gemini.module'; import { CmsModule } from './modules/cms/cms.module'; import { MailModule } from './modules/mail/mail.module'; // Guards import { JwtAuthGuard, RolesGuard, PermissionsGuard, } from './modules/auth/guards'; @Module({ imports: [ // Configuration ConfigModule.forRoot({ isGlobal: true, validate: validateEnv, load: [ appConfig, databaseConfig, jwtConfig, redisConfig, i18nConfig, featuresConfig, throttleConfig, geminiConfig, ], }), // Logger (Structured Logging with Pino) LoggerModule.forRootAsync({ imports: [ConfigModule], inject: [ConfigService], useFactory: (configService: ConfigService) => { return { pinoHttp: { level: configService.get('app.isDevelopment') ? 'debug' : 'info', transport: configService.get('app.isDevelopment') ? { target: 'pino-pretty', options: { singleLine: true, }, } : undefined, }, }; }, }), // i18n I18nModule.forRootAsync({ useFactory: (configService: ConfigService) => ({ fallbackLanguage: configService.get('i18n.fallbackLanguage', 'en'), loaderOptions: { path: path.join(__dirname, '/i18n/'), watch: configService.get('app.isDevelopment', true), }, }), resolvers: [ new HeaderResolver(['x-lang', 'accept-language']), new QueryResolver(['lang']), AcceptLanguageResolver, ], inject: [ConfigService], }), // Throttling ThrottlerModule.forRootAsync({ inject: [ConfigService], useFactory: (configService: ConfigService) => [ { ttl: configService.get('throttle.ttl', 60000), limit: configService.get('throttle.limit', 100), }, ], }), // Caching (Redis with in-memory fallback) CacheModule.registerAsync({ isGlobal: true, imports: [ConfigModule], useFactory: async (configService: ConfigService) => { const logger = new NestLogger('CacheModule'); const useRedis = configService.get('REDIS_ENABLED', 'false') === 'true'; if (useRedis) { try { const store = await redisStore({ socket: { host: configService.get('redis.host', 'localhost'), port: configService.get('redis.port', 6379), }, ttl: 60 * 1000, // 1 minute default }); logger.log('✅ Redis cache connected'); return { store: store as unknown as any, ttl: 60 * 1000, }; } catch { logger.warn('⚠️ Redis connection failed, using in-memory cache'); } } // Fallback to in-memory cache logger.log('📦 Using in-memory cache'); return { ttl: 60 * 1000, }; }, inject: [ConfigService], }), // Database DatabaseModule, // Core Modules AuthModule, UsersModule, AdminModule, // Optional Modules (controlled by env variables) GeminiModule, HealthModule, // CMS Module CmsModule, // Mail Module MailModule, // Serve uploaded files ServeStaticModule.forRoot({ rootPath: path.join(__dirname, '..', 'uploads'), serveRoot: '/uploads', }), ], providers: [ // Global Exception Filter { provide: APP_FILTER, useClass: GlobalExceptionFilter, }, // Global Response Interceptor { provide: APP_INTERCEPTOR, useClass: ResponseInterceptor, }, // Global Rate Limiting { provide: APP_GUARD, useClass: ThrottlerGuard, }, // Global JWT Auth Guard { provide: APP_GUARD, useClass: JwtAuthGuard, }, // Global Roles Guard { provide: APP_GUARD, useClass: RolesGuard, }, // Global Permissions Guard { provide: APP_GUARD, useClass: PermissionsGuard, }, ], }) export class AppModule { private readonly logger = new NestLogger(AppModule.name); constructor() { this.logger.log('AppModule initialized'); } }