graph TB
    subgraph Main Application
        AppModule[App Module]
        AppController[App Controller]
        AppService[App Service]
    end

    subgraph Quiz Module
        QuizMod[Quiz Module]
        QuizController[Quiz Controller]
        QuizSetController[QuizSet Controller]
        QuizService[Quiz Service]
        QuizRepo[Quiz Repository]
        QuizSetRepo[QuizSet Repository]
    end

    subgraph QuizZone Module
        QuizZoneMod[QuizZone Module]
        QuizZoneController[QuizZone Controller]
        QuizZoneService[QuizZone Service]
        QuizZoneRepo[QuizZone Repository]
    end

    subgraph Play Module
        PlayMod[Play Module]
        PlayGateway[Play Gateway]
        PlayService[Play Service]
    end

    subgraph Chat Module
        ChatMod[Chat Module]
        ChatController[Chat Controller]
        ChatService[Chat Service]
        ChatRepo[Chat Memory Repository]
    end

    subgraph Core
        SessionWsAdapter[Session WebSocket Adapter]
        Logger[Winston Logger]
        TypeORM[TypeORM]
    end

    %% Module Dependencies
    AppModule --> QuizMod
    AppModule --> QuizZoneMod
    AppModule --> PlayMod
    AppModule --> ChatMod
    
    %% Quiz Module Dependencies
    QuizMod --> QuizController
    QuizMod --> QuizSetController
    QuizMod --> QuizService
    QuizService --> QuizRepo
    QuizService --> QuizSetRepo
    
    %% QuizZone Module Dependencies
    QuizZoneMod --> QuizZoneController
    QuizZoneMod --> QuizZoneService
    QuizZoneService --> QuizZoneRepo
    QuizZoneService --> QuizService
    QuizZoneService --> ChatService
    
    %% Play Module Dependencies
    PlayMod --> PlayGateway
    PlayMod --> PlayService
    PlayService --> QuizZoneService
    PlayService --> ChatService
    
    %% Chat Module Dependencies
    ChatMod --> ChatController
    ChatMod --> ChatService
    ChatService --> ChatRepo
    
    %% Core Dependencies
    AppModule --> SessionWsAdapter
    AppModule --> Logger
    AppModule --> TypeORM

장점

  1. 모듈화가 잘 되어있음
  2. 의존성 주입 활용
  3. WebSocket 아키텍처

단점

  1. 데이터 일관성 취약
  2. 에러 처리 일관성 부족
  3. 비즈니스 로직 복잡도

개선점

  1. 데이터 계층 개선

    // 현재: In-memory Repository
    export class ChatRepositoryMemory {
        constructor(@Inject('ChatStorage') private readonly data: Map<string, ChatMessage[]>) {}
    }
    
    // 개선: Repository 인터페이스와 구현 분리
    export interface IChatRepository {
        save(message: ChatMessage): Promise<void>;
        findByRoom(roomId: string): Promise<ChatMessage[]>;
    }
    
    // 구현은 Memory, Redis, DB 등으로 유연하게 변경 가능
    
    
  2. 도메인 로직 분리

    // 현재: 서비스에 모든 로직이 집중
    export class PlayService {
        async submit(quizZoneId: string, clientId: string, submittedQuiz: SubmittedQuiz) {
            // 복잡한 제출 로직...
        }
    }
    
    // 개선: 도메인 객체로 로직 분리
    export class Quiz {
        submit(answer: string, submittedAt: number): SubmitResult {
            // 퀴즈 제출 관련 도메인 로직
        }
    }
    
  3. 글로벌 예외 처리 추가

    @Catch()
    export class GlobalExceptionFilter implements ExceptionFilter {
        catch(exception: unknown, host: ArgumentsHost) {
            const ctx = host.switchToHttp();
            const response = ctx.getResponse<Response>();
    
            if (exception instanceof DomainException) {
                // 도메인 예외 처리
            } else if (exception instanceof InfrastructureException) {
                // 인프라 예외 처리
            }
        }
    }
    
    
  4. 캐싱 전략 도입

    // Redis 캐싱 레이어 추가
    @Injectable()
    export class QuizZoneCacheService {
        constructor(
            @Inject(CACHE_MANAGER) private cacheManager: Cache,
            private quizZoneService: QuizZoneService,
        ) {}
    
        async getQuizZone(id: string): Promise<QuizZone> {
            const cached = await this.cacheManager.get(`quizzone:${id}`);
            if (cached) return cached;
    
            const quizZone = await this.quizZoneService.findOne(id);
            await this.cacheManager.set(`quizzone:${id}`, quizZone);
            return quizZone;
        }
    }
    
    
  5. 이벤트 기반 아키텍처 도입

    // 이벤트 발행/구독 패턴 도입
    export class QuizEventPublisher {
        @Inject(EventEmitter2)
        private eventEmitter: EventEmitter2;
    
        publishQuizSubmitted(quizId: string, submission: QuizSubmission) {
            this.eventEmitter.emit('quiz.submitted', { quizId, submission });
        }
    }
    
    
  6. 메트릭스 & 모니터링 추가

    // 프로메테우스 메트릭스 추가
    @Injectable()
    export class QuizMetricsService {
        private submitLatency = new Histogram({
            name: 'quiz_submit_latency',
            help: 'Quiz submission latency in seconds',
        });
    
        recordSubmitLatency(duration: number) {
            this.submitLatency.observe(duration);
        }
    }
    
    

이러한 개선을 통해: