import { Module } 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 { BullModule } from '@nestjs/bullmq'; 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'; // 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'; // Video SaaS Modules import { ProjectsModule } from './modules/projects/projects.module'; import { VideoQueueModule } from './modules/video-queue/video-queue.module'; import { VideoAiModule } from './modules/video-ai/video-ai.module'; import { StorageModule } from './modules/storage/storage.module'; import { BillingModule } from './modules/billing/billing.module'; import { XTwitterModule } from './modules/x-twitter/x-twitter.module'; import { EventsModule } from './modules/events/events.module'; import { RenderCallbackModule } from './modules/render-callback/render-callback.module'; import { DashboardModule } from './modules/dashboard/dashboard.module'; import { NotificationsModule } from './modules/notifications/notifications.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, ], }), // BullMQ — Redis tabanlı job kuyruğu (Video üretim pipeline) BullModule.forRootAsync({ imports: [ConfigModule], useFactory: (configService: ConfigService) => ({ connection: { host: configService.get('redis.host', 'localhost'), port: configService.get('redis.port', 6379), password: configService.get('redis.password') || undefined, }, }), inject: [ConfigService], }), // Logger (Structured Logging with Pino) LoggerModule.forRootAsync({ imports: [ConfigModule], inject: [ConfigService], useFactory: async (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 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 }); console.log('✅ Redis cache connected'); return { store: store as unknown as any, ttl: 60 * 1000, }; } catch { console.warn('⚠️ Redis connection failed, using in-memory cache'); } } // Fallback to in-memory cache console.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, // Video SaaS Modules ProjectsModule, VideoQueueModule, VideoAiModule, StorageModule, BillingModule, XTwitterModule, // Real-time & Callback Modules EventsModule, RenderCallbackModule, DashboardModule, NotificationsModule, ], 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 {}