2025년 2월 14일

김동환·2025년 2월 14일
0

TIL (Today I Learned) - AppModule 설정

오늘은 NestJSAppModule 설정에 대해 정리했다.
이 모듈은 프로젝트의 루트 모듈로, 다양한 기능 모듈들을 불러오고 전역 설정을 담당한다.


1️⃣ 환경 변수 및 설정 (ConfigModule)

  • ConfigModule.forRoot()을 사용하여 환경 변수 설정을 전역으로 적용했다.
  • Joi를 활용해 환경 변수의 유효성을 검증했다.
  • 추가된 검증 항목
    • ACCESS_SECRET_KEY: JWT 인증을 위한 시크릿 키
    • ACCESS_EXPIRES_IN: 액세스 토큰 만료 시간 (기본값: 1분)

2️⃣ 데이터베이스 설정 (TypeOrmModule)

  • TypeOrmModule.forRootAsync()를 활용하여 데이터베이스 설정을 비동기적으로 적용했다.
  • ConfigService를 이용해 .env 파일에서 값을 가져와 설정을 구성했다.
  • 주요 옵션
    • SnakeNamingStrategy: typeorm-naming-strategies를 사용하여 DB 컬럼을 snake_case로 변환
    • synchronize: DB_SYNC 환경 변수 값을 기반으로 동기화 여부 결정
    • logging: true 설정으로 SQL 로그 확인 가능

3️⃣ 도메인 모듈 구성

다양한 도메인 기능을 AppModule에서 가져와 사용했다.

  • UsersModule, PostsModule, CommentsModule: 사용자, 게시글, 댓글 기능
  • AuthModule: 인증 및 JWT 기반 보안 기능
  • AchievementsModule, UsersAchievementsModule: 업적 시스템 관련 모듈
  • GamesModule: 마피아 게임의 핵심 기능
  • StatisticsModule: 게임 및 유저 통계 관리

4️⃣ 기타 주석 처리된 코드

  • 이벤트 시스템 (EventEmitterModule)
    • EventEmitterModule.forRoot()가 주석 처리되어 있지만, 이벤트 기반 처리가 필요할 때 활성화 가능
  • JWT 모듈 (JwtModule)
    • ACCESS_SECRET_KEYACCESS_EXPIRES_IN을 활용하여 JWT 인증 설정을 적용할 수 있도록 준비됨
  • 정적 파일 제공 (ServeStaticModule)
    • ServeStaticModule을 이용해 정적 파일을 제공할 수 있도록 설정 가능

배운 점 & 다음 할 일

✅ 환경 변수 검증을 통해 안전한 설정이 가능함을 이해했다.
TypeORM을 설정할 때 forRootAsync()를 활용하면 ConfigService와 함께 비동기적으로 설정을 적용할 수 있음을 확인했다.
JwtModuleServeStaticModule 같은 추가적인 기능을 활성화할 경우의 사용법을 익혔다.

다음으로는 웹소켓과 연동하여 GamesModule에서 실시간 데이터 처리를 어떻게 구현할지 조사해볼 계획!

app.module.ts

import { Global, Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { AchievementsModule } from './achievements/achievements.module';
import { UsersAchievementsModule } from './user-achievements/users-achievements.module';
import { GamesModule } from './games/games.module';
import { StatisticsModule } from './statistics/statistics.module';
import { SnakeNamingStrategy } from 'typeorm-naming-strategies';
import { TypeOrmModule, TypeOrmModuleOptions } from '@nestjs/typeorm';
import Joi from 'joi';
import { UsersModule } from './users/users.module';
import { PostsModule } from './posts/posts.module';
import { CommentsModule } from './comments/comments.module';
import { AuthModule } from './auth/auth.module';

const typeOrmModuleOptions = {
  useFactory: async (
    configService: ConfigService,
  ): Promise<TypeOrmModuleOptions> => ({
    namingStrategy: new SnakeNamingStrategy(),
    type: 'mysql',
    host: configService.get('DB_HOST'),
    port: configService.get('DB_PORT'),
    username: configService.get('DB_USERNAME'),
    password: configService.get('DB_PASSWORD'),
    database: configService.get('DB_NAME'),
    entities: [__dirname + '/**/entities/*.{ts,js}'],
    synchronize: configService.get('DB_SYNC'),
    logging: true,
  }),
  inject: [ConfigService],
};
@Global()
@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
      validationSchema: Joi.object({
        DB_USERNAME: Joi.string().required(),
        DB_PASSWORD: Joi.string().required(),
        DB_HOST: Joi.string().required(),
        DB_PORT: Joi.number().required(),
        DB_NAME: Joi.string().required(),
        DB_SYNC: Joi.boolean().required(),
        ACCESS_SECRET_KEY: Joi.string().required(), // 액세스 시크릿 키 검증 추가
        ACCESS_EXPIRES_IN: Joi.string().default('1m'), // 액세스 만료시간 검증 추가
      }),
    }),
    // EventEmitterModule.forRoot(), // 이벤트 시스템 활성화
    TypeOrmModule.forRootAsync(typeOrmModuleOptions),
    // JwtModule.registerAsync({
    //   imports: [ConfigModule],
    //   inject: [ConfigService],
    //   useFactory: async (configService: ConfigService) => ({
    //     secret: configService.get<string>('ACCESS_SECRET_KEY'),
    //     signOptions: {
    //       expiresIn: configService.get<string>('ACCESS_EXPIRES_IN'),
    //     },
    //   }),
    // }),
    // ServeStaticModule.forRoot({
    //   rootPath: join(__dirname, '..', 'dist', 'public'),
    //   serveRoot: '/', //  루트 URL에서 정적 파일 제공
    // }),

   UsersModule,
   PostsModule,
   CommentsModule,
   AuthModule,
   AchievementsModule,
   GamesModule,
   StatisticsModule,
   UsersAchievementsModule,
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}
profile
Node.js 7기

0개의 댓글

관련 채용 정보