Files
HarunCAN_Studio_BE/src/app.module.ts
Harun CAN e0d41d0386
Some checks failed
Backend Deploy 🚀 / build-and-deploy (push) Has been cancelled
main
2026-03-17 13:16:12 +03:00

225 lines
5.6 KiB
TypeScript

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');
}
}