# KT AI 기반 소상공인 이벤트 자동 생성 서비스 - 논리 아키텍처 ## 문서 정보 - **작성일**: 2025-10-21 - **최종 수정일**: 2025-10-22 - **버전**: 2.0 (CQRS + Event-Driven 전환) - **작성자**: System Architect - **관련 문서**: - [유저스토리](../../userstory.md) - [아키텍처 패턴](../../pattern/architecture-pattern.md) - [UI/UX 설계서](../../uiux/uiux.md) ## 버전 이력 - **v1.0** (2025-10-21): 초기 마이크로서비스 아키텍처 설계 - **v2.0** (2025-10-22): CQRS 패턴 및 Event-Driven 아키텍처 전환, Resilience 패턴 전면 적용 --- ## 목차 1. [개요](#1-개요) 2. [서비스 아키텍처](#2-서비스-아키텍처) 3. [주요 사용자 플로우](#3-주요-사용자-플로우) 4. [데이터 흐름 및 캐싱 전략](#4-데이터-흐름-및-캐싱-전략) 5. [확장성 및 성능 고려사항](#5-확장성-및-성능-고려사항) 6. [보안 고려사항](#6-보안-고려사항) 7. [논리 아키텍처 다이어그램](#7-논리-아키텍처-다이어그램) --- ## 1. 개요 ### 1.1 설계 원칙 본 논리 아키텍처는 다음 원칙을 기반으로 설계되었습니다: #### 유저스토리 기반 설계 - 20개 유저스토리와 정확히 매칭 - 불필요한 추가 기능 배제 - 비즈니스 요구사항 우선 반영 #### CQRS (Command Query Responsibility Segregation) - **읽기/쓰기 분리**: Command Service와 Query Service로 책임 분리 - **독립적 확장**: 읽기와 쓰기 부하에 따라 독립적으로 확장 - **성능 최적화**: Query Service는 읽기 최적화 데이터 모델 사용 - **이벤트 소싱 준비**: 도메인 이벤트 기반 상태 동기화 #### Event-Driven 아키텍처 - **비동기 메시징**: Event Bus(Kafka/SQS)를 통한 서비스 간 통신 - **느슨한 결합**: 서비스 간 직접 의존성 제거 - **확장성**: 이벤트 구독자 추가로 기능 확장 용이 - **장애 격리**: 이벤트 발행/구독 실패 시 서비스 독립성 유지 #### Resilience 패턴 적용 - **Circuit Breaker**: 외부 API 장애 시 빠른 실패 및 복구 (Hystrix/Resilience4j) - **Retry Pattern**: 일시적 장애 시 자동 재시도 (지수 백오프) - **Timeout Pattern**: 응답 시간 제한으로 리소스 점유 방지 - **Bulkhead Pattern**: 리소스 격리로 장애 전파 차단 - **Fallback Pattern**: 장애 시 대체 로직 실행 (캐시 응답 등) ### 1.2 핵심 컴포넌트 정의 #### Command Services (쓰기 전용) 1. **User Service**: 사용자 인증 및 매장정보 관리 - 회원가입/로그인 (JWT 발급) - 프로필 수정 - 사업자번호 검증 (외부 API 연동) 2. **Event Command Service**: 이벤트 생성/수정/삭제 - 이벤트 생성 플로우 오케스트레이션 - 도메인 이벤트 발행 (EventCreated, EventPublished) - 이벤트 상태 변경 3. **Participation Command Service**: 참여 및 당첨자 관리 - 참여 접수 및 검증 - 당첨자 추첨 실행 - 도메인 이벤트 발행 (ParticipantRegistered, WinnerSelected) #### Query Services (읽기 전용) 1. **Event Query Service**: 이벤트 조회 최적화 - 이벤트 목록/상세 조회 - 이벤트 검색 및 필터링 - 읽기 최적화 데이터 모델 (비정규화) 2. **Participation Query Service**: 참여자/당첨자 조회 - 참여자 목록 조회 - 당첨자 조회 - 읽기 최적화 집계 데이터 3. **Analytics Query Service**: 실시간 성과 분석 - 대시보드 데이터 조회 - 채널별 성과 집계 - ROI 계산 및 분석 #### Async Services (비동기 처리) 1. **AI Service**: AI 기반 이벤트 추천 - Job Queue를 통한 비동기 처리 - Circuit Breaker 적용 (외부 AI API) - 결과 캐싱 (Redis) 2. **Content Service**: SNS 이미지 생성 - Job Queue를 통한 비동기 처리 - Circuit Breaker 적용 (외부 이미지 API) - CDN 업로드 및 캐싱 3. **Distribution Service**: 다중 채널 배포 - Event Bus를 통한 EventPublished 구독 - 병렬 배포 및 Circuit Breaker 적용 - 배포 완료 이벤트 발행 (DistributionCompleted) #### Event Bus (Kafka/SQS) - **도메인 이벤트 발행/구독**: 서비스 간 비동기 통신 - **이벤트 종류**: - EventCreated: 이벤트 생성 시 - EventPublished: 이벤트 배포 승인 시 - ParticipantRegistered: 참여자 등록 시 - WinnerSelected: 당첨자 선정 시 - DistributionCompleted: 배포 완료 시 - **보장 수준**: At-Least-Once Delivery #### Job Queue (RabbitMQ) - **장시간 비동기 작업**: AI 추천, 이미지 생성 - **Priority Queue**: 작업 우선순위 관리 - **Dead Letter Queue**: 실패 작업 처리 #### Data Layer - **Redis Cache**: 세션, AI 결과, 이미지 URL, 대시보드 캐싱 - **PostgreSQL**: 서비스별 독립 데이터베이스 - User DB, Event Write DB, Event Read DB, Participation Write DB, Participation Read DB, Analytics DB - **읽기 전용 복제본**: Query Service 성능 최적화 #### External Systems - **국세청 API**: 사업자번호 검증 - **AI APIs**: Claude/GPT-4 (트렌드 분석) - **이미지 생성 APIs**: Stable Diffusion/DALL-E - **배포 채널 APIs**: 우리동네TV, 링고비즈, 지니TV, SNS APIs --- ## 2. 서비스 아키텍처 ### 2.1 CQRS 패턴 적용 #### 설계 원칙 - **Command와 Query 분리**: 쓰기와 읽기 책임을 독립된 서비스로 분리 - **독립적 확장**: 읽기/쓰기 부하에 따라 독립적으로 스케일링 - **최적화된 데이터 모델**: Query Service는 비정규화된 읽기 최적화 모델 사용 - **이벤트 동기화**: Command Service가 발행한 도메인 이벤트로 Query Service 동기화 ### 2.2 Command Services (쓰기 전용) #### User Service **핵심 책임**: - 회원가입/로그인 (JWT 토큰 발급) - 프로필 수정 (매장 정보 포함) - 사업자번호 검증 (국세청 API 연동) - 세션 관리 **관련 유저스토리**: UFR-USER-010, 020, 030, 040 **Resilience 패턴**: - **Circuit Breaker**: 국세청 API 호출 시 (실패율 5% 초과 시 Open) - **Retry**: 최대 3회 재시도 (지수 백오프: 1초, 2초, 4초) - **Timeout**: 5초 - **Fallback**: 사업자번호 검증 스킵 (수동 확인 안내) **데이터 저장**: - User DB: users, stores 테이블 - Redis: 세션 정보 (TTL 7일), 사업자번호 검증 결과 (TTL 7일) #### Event Command Service **핵심 책임**: - 이벤트 생성/수정/삭제 - 이벤트 생성 플로우 오케스트레이션 - 도메인 이벤트 발행 (EventCreated, EventPublished) **관련 유저스토리**: UFR-EVENT-010, 020, 030, 040, 050, 060, 070 **도메인 이벤트**: 1. **EventCreated**: 이벤트 생성 완료 시 - Payload: eventId, storeId, title, objective, createdAt - 구독자: Event Query Service, Analytics Query Service 2. **EventPublished**: 이벤트 배포 승인 시 - Payload: eventId, distributionChannels, publishedAt - 구독자: Distribution Service **주요 플로우**: 1. 이벤트 목적 선택 → Event DB 저장 2. AI 추천 요청 → Job Queue 발행 3. 이미지 생성 요청 → Job Queue 발행 4. 배포 승인 → EventPublished 이벤트 발행 **데이터 저장**: - Event Write DB: events, event_objectives, event_prizes 테이블 #### Participation Command Service **핵심 책임**: - 이벤트 참여 접수 및 검증 - 당첨자 추첨 실행 - 도메인 이벤트 발행 (ParticipantRegistered, WinnerSelected) **관련 유저스토리**: UFR-PART-010, 020, 030 **도메인 이벤트**: 1. **ParticipantRegistered**: 참여자 등록 시 - Payload: participantId, eventId, phoneNumber, registeredAt - 구독자: Participation Query Service, Analytics Query Service 2. **WinnerSelected**: 당첨자 선정 시 - Payload: winnerId, eventId, selectedAt - 구독자: Participation Query Service **주요 기능**: - 중복 참여 체크 (전화번호 기반) - 난수 기반 무작위 추첨 - 매장 방문 고객 가산점 적용 **데이터 저장**: - Participation Write DB: participants, winners 테이블 ### 2.3 Query Services (읽기 전용) #### Event Query Service **핵심 책임**: - 이벤트 목록/상세 조회 - 이벤트 검색 및 필터링 - 읽기 최적화 데이터 제공 **이벤트 구독**: - **EventCreated**: 읽기 DB에 이벤트 데이터 동기화 **데이터 모델**: - **비정규화**: 조인 없이 단일 쿼리로 조회 가능 - **인덱스 최적화**: storeId, status, createdAt **데이터 저장**: - Event Read DB: events_view (비정규화 테이블) #### Participation Query Service **핵심 책임**: - 참여자 목록 조회 - 당첨자 조회 - 집계 데이터 제공 **이벤트 구독**: - **ParticipantRegistered**: 참여자 데이터 동기화 - **WinnerSelected**: 당첨자 데이터 동기화 **데이터 모델**: - **집계 테이블**: 이벤트별 참여자 수, 당첨자 수 사전 계산 **데이터 저장**: - Participation Read DB: participants_view, winners_view, event_participant_stats #### Analytics Query Service **핵심 책임**: - 실시간 성과 대시보드 - 채널별 성과 분석 - ROI 계산 **관련 유저스토리**: UFR-ANAL-010 **이벤트 구독**: - **EventCreated**: 이벤트 기본 정보 동기화 - **ParticipantRegistered**: 참여자 수 실시간 업데이트 - **DistributionCompleted**: 배포 통계 업데이트 **Resilience 패턴**: - **Circuit Breaker**: 외부 채널 API 조회 시 - **Fallback**: 캐시된 이전 데이터 반환 - **Cache-Aside**: Redis 캐싱 (TTL 5분) **데이터 통합**: - Event Query Service: 이벤트 정보 - Participation Query Service: 참여자/당첨자 데이터 - Distribution Service: 배포 통계 - 외부 APIs: 우리동네TV, 지니TV, SNS 통계 **데이터 저장**: - Analytics DB: event_stats, channel_stats - Redis: 대시보드 데이터 (TTL 5분) ### 2.4 Async Services (비동기 처리) #### AI Service **핵심 책임**: - 업종/지역/시즌 트렌드 분석 - 3가지 이벤트 기획안 자동 생성 - 예상 성과 계산 **관련 유저스토리**: UFR-AI-010 **Resilience 패턴**: - **Circuit Breaker**: AI API 호출 시 (실패율 10% 초과 시 Open) - **Timeout**: 30초 - **Fallback**: 캐시된 이전 추천 결과 + 안내 메시지 - **Cache-Aside**: Redis 캐싱 (TTL 24시간) **처리 시간**: - 캐시 HIT: 0.1초 - 캐시 MISS: 10초 이내 (비동기 Job 처리) **데이터 저장**: - Redis: AI 추천 결과 (TTL 24시간) - Redis: Job 상태 정보 (TTL 1시간) #### Content Service **핵심 책임**: - 3가지 스타일 SNS 이미지 자동 생성 - 플랫폼별 이미지 최적화 - 이미지 편집 기능 **관련 유저스토리**: UFR-CONT-010, 020 **Resilience 패턴**: - **Circuit Breaker**: 이미지 생성 API 호출 시 - **Timeout**: 20초 - **Fallback**: 기본 템플릿 이미지 제공 - **Cache-Aside**: Redis 캐싱 (TTL 7일) **처리 시간**: - 캐시 HIT: 0.1초 - 캐시 MISS: 5초 이내 (비동기 Job 처리) **데이터 저장**: - Redis: 이미지 생성 결과 (CDN URL, TTL 7일) - CDN: 생성된 이미지 파일 #### Distribution Service **핵심 책임**: - 다중 채널 동시 배포 - 배포 상태 모니터링 - 도메인 이벤트 발행 (DistributionCompleted) **관련 유저스토리**: UFR-DIST-010, 020 **이벤트 구독**: - **EventPublished**: 배포 작업 시작 트리거 **도메인 이벤트**: - **DistributionCompleted**: 배포 완료 시 - Payload: eventId, distributedChannels, completedAt - 구독자: Analytics Query Service **Resilience 패턴**: - **Circuit Breaker**: 각 외부 채널 API별 독립 적용 - **Retry**: 최대 3회 재시도 (지수 백오프) - **Bulkhead**: 채널별 스레드 풀 격리 (장애 전파 방지) - **Fallback**: 실패 채널 스킵 + 알림 **처리 시간**: 1분 이내 (모든 채널 배포 완료) **데이터 저장**: - Event Read DB: distribution_logs 테이블 ### 2.5 Event-Driven 통신 전략 #### Event Bus 아키텍처 **기술 스택**: Kafka 또는 AWS SQS **보장 수준**: At-Least-Once Delivery **메시지 포맷**: JSON #### 도메인 이벤트 정의 | 이벤트명 | 발행자 | 구독자 | Payload | 용도 | |---------|--------|--------|---------|------| | **EventCreated** | Event Command | Event Query
Analytics Query | eventId, storeId, title, objective, createdAt | 이벤트 생성 동기화 | | **EventPublished** | Event Command | Distribution Service | eventId, distributionChannels, publishedAt | 배포 작업 트리거 | | **ParticipantRegistered** | Participation Command | Participation Query
Analytics Query | participantId, eventId, phoneNumber, registeredAt | 참여자 등록 동기화 | | **WinnerSelected** | Participation Command | Participation Query | winnerId, eventId, selectedAt | 당첨자 선정 동기화 | | **DistributionCompleted** | Distribution Service | Analytics Query | eventId, distributedChannels, completedAt | 배포 완료 통계 업데이트 | #### 통신 패턴별 설계 **1. Event-Driven 통신 (비동기 메시징)** - **사용 시나리오**: 서비스 간 상태 동기화, 느슨한 결합 필요 시 - **장점**: - 서비스 독립성 보장 - 장애 격리 - 확장 용이 - **단점**: - 최종 일관성 (Eventual Consistency) - 디버깅 복잡도 증가 **2. Job Queue 통신 (비동기 작업)** - **사용 시나리오**: 장시간 작업 (AI 추천, 이미지 생성) - **기술 스택**: RabbitMQ - **패턴**: Asynchronous Request-Reply - **처리 플로우**: 1. Command Service → Job Queue: Job 발행 2. Async Service → Job Queue: Job 수신 및 처리 3. Client → Command Service: Job 상태 폴링 (5초 간격) 4. Async Service → Redis: 결과 캐싱 5. Command Service → Client: 완료 응답 **3. Query Service 간 통신** - **사용 시나리오**: Analytics Query가 다른 Query Service 데이터 필요 시 - **패턴**: Cache-Aside - **통신 방식**: REST API (HTTP/JSON) - **특징**: 읽기 전용이므로 직접 호출 허용 #### Cache-Aside 전략 | 서비스 | 캐시 키 패턴 | TTL | 히트율 목표 | 효과 | |--------|-------------|-----|-----------|------| | AI Service | `ai:recommendation:{업종}:{지역}:{목적}` | 24시간 | 80% | 10초 → 0.1초 (99% 개선) | | Content Service | `content:image:{이벤트ID}:{스타일}` | 7일 | 80% | 5초 → 0.1초 (98% 개선) | | User Service | `user:business:{사업자번호}` | 7일 | 90% | - | | Analytics Query | `analytics:dashboard:{이벤트ID}` | 5분 | 95% | 3초 → 0.5초 (83% 개선) | #### Resilience 패턴 적용 **1. Circuit Breaker 패턴** - **적용 대상**: 모든 외부 API 호출 - **라이브러리**: Resilience4j 또는 Hystrix - **설정**: ```yaml circuit-breaker: failure-rate-threshold: 50% # 실패율 50% 초과 시 Open slow-call-rate-threshold: 50% # 느린 호출 50% 초과 시 Open slow-call-duration-threshold: 5s # 5초 초과 시 느린 호출로 간주 wait-duration-in-open-state: 30s # Open 상태 30초 유지 후 Half-Open permitted-calls-in-half-open: 3 # Half-Open 상태에서 3개 요청 테스트 ``` **2. Retry 패턴** - **적용 대상**: 일시적 장애가 예상되는 외부 API - **재시도 전략**: 지수 백오프 (Exponential Backoff) - **설정**: ```yaml retry: max-attempts: 3 # 최대 3회 재시도 wait-duration: 1s # 초기 대기 시간 1초 exponential-backoff-multiplier: 2 # 2배씩 증가 (1초, 2초, 4초) retry-exceptions: - java.net.SocketTimeoutException - java.net.ConnectException ``` **3. Timeout 패턴** - **적용 대상**: 모든 외부 API 호출 - **설정**: | 서비스 | Timeout | 이유 | |--------|---------|------| | User Service (국세청 API) | 5초 | 빠른 검증 필요 | | AI Service (AI API) | 30초 | 복잡한 분석 작업 | | Content Service (이미지 API) | 20초 | 이미지 생성 시간 고려 | | Distribution Service (채널 APIs) | 10초 | 빠른 배포 필요 | **4. Bulkhead 패턴** - **적용 대상**: Distribution Service (다중 채널 배포) - **목적**: 채널별 리소스 격리로 장애 전파 차단 - **설정**: ```yaml bulkhead: max-concurrent-calls: 10 # 채널당 최대 10개 동시 호출 max-wait-duration: 0s # 대기 없이 즉시 실패 ``` **5. Fallback 패턴** - **적용 대상**: 모든 외부 API 호출 - **전략**: | 서비스 | Fallback 전략 | |--------|---------------| | User Service | 사업자번호 검증 스킵 (수동 확인 안내) | | AI Service | 캐시된 이전 추천 결과 + 안내 메시지 | | Content Service | 기본 템플릿 이미지 제공 | | Distribution Service | 실패 채널 스킵 + 알림 | | Analytics Query | 캐시된 이전 데이터 반환 | #### 이벤트 순서 보장 - **Kafka Partition Key**: eventId 기준으로 파티션 할당 - **동일 이벤트의 모든 이벤트**: 동일 파티션 → 순서 보장 - **다른 이벤트**: 독립적 처리 → 병렬 처리 가능 #### 이벤트 재처리 (At-Least-Once) - **멱등성 보장**: 구독자는 동일 이벤트 중복 처리 시 멱등성 유지 - **방법**: 이벤트 ID 기반 중복 체크 (Redis Set 사용) --- ## 3. 주요 사용자 플로우 ### 3.1 이벤트 생성 플로우 (CQRS + Event-Driven) ``` 1. [이벤트 목적 선택] ┌─────────────────────────────────────────────────────────────┐ │ Client → Event Command Service │ │ - POST /api/events (목적, 매장 정보) │ │ - Event Write DB에 저장 │ │ - EventCreated 이벤트 발행 → Event Bus │ └─────────────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────────┐ │ Event Bus → Event Query Service │ │ - EventCreated 이벤트 구독 │ │ - Event Read DB에 동기화 (비정규화) │ └─────────────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────────┐ │ Event Bus → Analytics Query Service │ │ - EventCreated 이벤트 구독 │ │ - Analytics DB에 기본 통계 초기화 │ └─────────────────────────────────────────────────────────────┘ 2. [AI 이벤트 추천] ┌─────────────────────────────────────────────────────────────┐ │ Client → Event Command Service │ │ - POST /api/events/{id}/ai-recommendations │ │ - Job Queue 발행 (AI 작업 요청) │ │ - Job ID 즉시 반환 (0.1초) │ └─────────────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────────┐ │ AI Service (Background) │ │ - Job Queue 구독 │ │ - Redis 캐시 확인 (Cache-Aside) │ │ - 캐시 MISS: Claude API 호출 (10초) [Circuit Breaker] │ │ - 결과 캐싱 (TTL 24시간) │ │ - Job 상태 완료로 업데이트 │ └─────────────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────────┐ │ Client (Polling) │ │ - GET /api/jobs/{id} (5초 간격) │ │ - 완료 시: AI 추천 결과 반환 (3가지 옵션) │ └─────────────────────────────────────────────────────────────┘ 3. [SNS 이미지 생성] ┌─────────────────────────────────────────────────────────────┐ │ Client → Event Command Service │ │ - POST /api/events/{id}/content-generation │ │ - Job Queue 발행 (이미지 생성 요청) │ │ - Job ID 즉시 반환 (0.1초) │ └─────────────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────────┐ │ Content Service (Background) │ │ - Job Queue 구독 │ │ - Redis 캐시 확인 │ │ - 캐시 MISS: Stable Diffusion API (5초) [Circuit Breaker] │ │ - 이미지 CDN 업로드 │ │ - CDN URL 캐싱 (TTL 7일) │ │ - Job 상태 완료로 업데이트 │ └─────────────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────────┐ │ Client (Polling) │ │ - GET /api/jobs/{id} (3초 간격) │ │ - 완료 시: 3가지 스타일 이미지 URL 반환 │ └─────────────────────────────────────────────────────────────┘ 4. [최종 승인 및 배포] ┌─────────────────────────────────────────────────────────────┐ │ Client → Event Command Service │ │ - POST /api/events/{id}/publish │ │ - Event 상태 변경 (DRAFT → PUBLISHED) │ │ - EventPublished 이벤트 발행 → Event Bus │ └─────────────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────────┐ │ Event Bus → Distribution Service │ │ - EventPublished 이벤트 구독 │ │ - 다중 채널 병렬 배포 시작 [Circuit Breaker + Bulkhead] │ │ * 우리동네TV API (영상 업로드) [Retry: 3회] │ │ * 링고비즈 API (연결음 업데이트) [Retry: 3회] │ │ * 지니TV API (광고 등록) [Retry: 3회] │ │ * SNS APIs (Instagram, Naver, Kakao) [Retry: 3회] │ │ - 배포 완료: DistributionCompleted 이벤트 발행 │ └─────────────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────────┐ │ Event Bus → Analytics Query Service │ │ - DistributionCompleted 이벤트 구독 │ │ - Analytics DB 배포 통계 업데이트 │ │ - 대시보드 캐시 무효화 (다음 조회 시 갱신) │ └─────────────────────────────────────────────────────────────┘ ``` ### 3.2 고객 참여 플로우 (Event-Driven) ``` 1. [이벤트 참여] ┌─────────────────────────────────────────────────────────────┐ │ Client → Participation Command Service │ │ - POST /api/events/{id}/participate │ │ - 중복 참여 체크 (전화번호 기반) │ │ - Participation Write DB에 저장 │ │ - ParticipantRegistered 이벤트 발행 → Event Bus │ │ - 응모 번호 즉시 반환 │ └─────────────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────────┐ │ Event Bus → Participation Query Service │ │ - ParticipantRegistered 이벤트 구독 │ │ - Participation Read DB에 동기화 │ │ - 이벤트별 참여자 수 집계 테이블 업데이트 │ └─────────────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────────┐ │ Event Bus → Analytics Query Service │ │ - ParticipantRegistered 이벤트 구독 │ │ - 실시간 참여자 수 증가 │ │ - 대시보드 캐시 무효화 │ └─────────────────────────────────────────────────────────────┘ 2. [당첨자 추첨] ┌─────────────────────────────────────────────────────────────┐ │ Client → Participation Command Service │ │ - POST /api/events/{id}/draw-winners │ │ - 난수 기반 무작위 추첨 │ │ - Winners Write DB에 저장 │ │ - WinnerSelected 이벤트 발행 → Event Bus │ └─────────────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────────┐ │ Event Bus → Participation Query Service │ │ - WinnerSelected 이벤트 구독 │ │ - Winners Read DB에 동기화 │ └─────────────────────────────────────────────────────────────┘ ``` ### 3.3 성과 분석 플로우 (Query Service + Event 구독) ``` 1. [실시간 대시보드 조회] ┌─────────────────────────────────────────────────────────────┐ │ Client → Analytics Query Service │ │ - GET /api/events/{id}/analytics │ │ - Redis 캐시 확인 (TTL 5분) │ │ * 캐시 HIT: 즉시 반환 (0.5초) │ │ * 캐시 MISS: 아래 데이터 통합 │ └─────────────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────────┐ │ Analytics Query Service (데이터 통합) │ │ - Analytics DB: 이벤트 통계 조회 │ │ - Event Query Service: 이벤트 정보 조회 (REST) │ │ - Participation Query Service: 참여자/당첨자 조회 (REST) │ │ - 외부 APIs: 채널별 노출/클릭 수 [Circuit Breaker + Fallback] │ │ * 우리동네TV API (조회수) │ │ * 지니TV API (광고 노출 수) │ │ * SNS APIs (좋아요, 댓글, 공유 수) │ │ - Redis 캐싱 (TTL 5분) │ │ - 대시보드 데이터 반환 │ └─────────────────────────────────────────────────────────────┘ 2. [실시간 업데이트 (Event 구독)] ┌─────────────────────────────────────────────────────────────┐ │ Analytics Query Service (Background) │ │ - EventCreated 구독: 이벤트 기본 정보 초기화 │ │ - ParticipantRegistered 구독: 참여자 수 실시간 증가 │ │ - DistributionCompleted 구독: 배포 채널 통계 업데이트 │ │ - 캐시 무효화: 다음 조회 시 최신 데이터 갱신 │ └─────────────────────────────────────────────────────────────┘ ``` ### 3.4 플로우 특징 #### CQRS 이점 - **Command Service**: 쓰기 작업에 집중, 트랜잭션 보장 - **Query Service**: 읽기 최적화 데이터 모델, 빠른 조회 - **독립적 확장**: 읽기/쓰기 부하에 따라 독립 스케일링 #### Event-Driven 이점 - **느슨한 결합**: 서비스 간 직접 의존성 제거 - **장애 격리**: 한 서비스 장애가 다른 서비스에 영향 없음 - **확장 용이**: 새로운 구독자 추가로 기능 확장 - **비동기 처리**: 사용자 응답 시간 단축 #### Resilience 이점 - **Circuit Breaker**: 외부 API 장애 시 빠른 실패 및 복구 - **Retry**: 일시적 장애 자동 복구 - **Fallback**: 장애 시에도 서비스 지속 (Graceful Degradation) - **Bulkhead**: 리소스 격리로 장애 전파 차단 --- ## 4. 데이터 흐름 및 캐싱 전략 ### 4.1 데이터 흐름 #### 읽기 플로우 (Cache-Aside 패턴) ``` 1. Application → Cache 확인 - Cache HIT: 캐시된 데이터 즉시 반환 - Cache MISS: 2. Application → Database/External API 조회 3. Database/External API → Application 데이터 반환 4. Application → Cache 데이터 저장 (TTL 설정) 5. Application → Client 데이터 반환 ``` #### 쓰기 플로우 (Write-Through 패턴) ``` 1. Application → Database 쓰기 2. Database → Application 성공 응답 3. Application → Cache 무효화 또는 업데이트 4. Application → Client 성공 응답 ``` ### 4.2 캐싱 전략 #### Redis 캐시 구조 | 서비스 | 캐시 키 패턴 | 데이터 타입 | TTL | 예상 크기 | 히트율 목표 | |--------|-------------|-----------|-----|----------|-----------| | User | `user:session:{token}` | String | 7일 | 1KB | - | | User | `user:business:{사업자번호}` | String | 7일 | 0.5KB | 90% | | AI | `ai:recommendation:{업종}:{지역}:{목적}` | Hash | 24시간 | 10KB | 80% | | Content | `content:image:{이벤트ID}:{스타일}` | String | 7일 | 0.2KB (URL) | 80% | | Analytics | `analytics:dashboard:{이벤트ID}` | Hash | 5분 | 5KB | 95% | | AI | `job:{jobId}` | Hash | 1시간 | 1KB | - | | Content | `job:{jobId}` | Hash | 1시간 | 1KB | - | #### Redis 메모리 산정 - **예상 동시 사용자**: 100명 - **예상 이벤트 수**: 50개 - **예상 캐시 항목 수**: 10,000개 - **예상 총 메모리**: 약 50MB (운영 환경 2GB 할당) #### 캐시 무효화 전략 - **TTL 기반 자동 만료**: 대부분의 캐시 - **수동 무효화**: 이벤트 수정/삭제 시 관련 캐시 삭제 - **Lazy 무효화**: 데이터 변경 시 다음 조회 시점에 갱신 ### 4.3 데이터베이스 전략 #### 서비스별 독립 데이터베이스 - **User DB**: users, stores - **Event DB**: events, event_objectives, event_prizes, distribution_logs - **Participation DB**: participants, winners - **Analytics DB**: event_stats, channel_stats #### 데이터 일관성 전략 - **Eventual Consistency**: 서비스 간 데이터는 최종 일관성 보장 - **Strong Consistency**: 서비스 내부 트랜잭션은 강한 일관성 보장 - **Saga 패턴**: 이벤트 생성 플로우 (보상 트랜잭션) --- ## 5. 확장성 및 성능 고려사항 ### 5.1 수평 확장 전략 #### 서비스별 확장 전략 | 서비스 | 초기 인스턴스 | 확장 조건 | 최대 인스턴스 | Auto-scaling 메트릭 | |--------|-------------|----------|-------------|-------------------| | User | 2 | CPU > 70% | 5 | CPU, 메모리 | | Event | 2 | CPU > 70% | 10 | CPU, 메모리 | | AI | 1 | Job Queue > 10 | 3 | Queue 길이 | | Content | 1 | Job Queue > 10 | 3 | Queue 길이 | | Distribution | 2 | CPU > 70% | 5 | CPU, 메모리 | | Participation | 1 | CPU > 70% | 3 | CPU, 메모리 | | Analytics | 1 | CPU > 70% | 3 | CPU, 메모리 | #### Redis Cluster - **초기 구성**: 3 노드 (Master 3, Replica 3) - **확장**: 노드 추가를 통한 수평 확장 - **HA**: Redis Sentinel을 통한 자동 Failover #### Database Replication - **Primary-Replica 구조**: 읽기 부하 분산 - **읽기 확장**: Read Replica 추가 (필요 시) - **쓰기 확장**: Sharding (Phase 2 이후) ### 5.2 성능 목표 #### 응답 시간 목표 | 기능 | 목표 시간 | 캐시 HIT | 캐시 MISS | |------|----------|---------|----------| | 로그인 | 0.5초 | - | - | | 이벤트 목록 조회 | 0.3초 | - | - | | AI 트렌드 분석 + 추천 | 0.1초 | ✅ | 10초 (비동기) | | SNS 이미지 생성 | 0.1초 | ✅ | 5초 (비동기) | | 다중 채널 배포 | 1분 | - | - | | 대시보드 로딩 | 0.5초 | ✅ | 3초 | #### 처리량 목표 - **동시 사용자**: 100명 (MVP 목표) - **API 요청**: 1,000 req/min - **AI 작업**: 10 jobs/min - **이미지 생성**: 10 jobs/min ### 5.3 성능 최적화 기법 #### Frontend 최적화 - **Code Splitting**: 페이지별 번들 분할 - **Lazy Loading**: 차트 라이브러리 지연 로딩 - **CDN**: 정적 자산 CDN 배포 - **Compression**: Gzip/Brotli 압축 #### Backend 최적화 - **Connection Pooling**: 데이터베이스 연결 풀 관리 - **Query Optimization**: 인덱스 최적화, N+1 쿼리 방지 - **Batch Processing**: 대량 데이터 일괄 처리 - **Pagination**: 목록 조회 페이지네이션 #### Cache 최적화 - **Multi-Level Caching**: Browser Cache → CDN → Redis → Database - **Cache Warming**: 자주 사용되는 데이터 사전 로딩 - **Cache Preloading**: 피크 시간 전 캐시 준비 --- ## 6. 보안 고려사항 ### 6.1 인증 및 인가 #### JWT 기반 인증 - **토큰 발급**: User Service에서 로그인 시 JWT 토큰 발급 - **토큰 검증**: API Gateway에서 모든 요청의 JWT 토큰 검증 - **토큰 저장**: Redis에 세션 정보 저장 (TTL 7일) - **토큰 갱신**: Refresh Token 패턴 (선택) #### 역할 기반 접근 제어 (RBAC) - **역할**: OWNER (매장 사장님), CUSTOMER (이벤트 참여자) - **권한 관리**: API별 필요 역할 정의 - **API Gateway 검증**: 요청자의 역할 확인 ### 6.2 데이터 보안 #### 민감 정보 암호화 - **비밀번호**: bcrypt 해싱 (Cost Factor: 10) - **사업자번호**: AES-256 암호화 저장 - **개인정보**: 전화번호 마스킹 (010-****-1234) #### 전송 보안 - **HTTPS**: 모든 통신 TLS 1.3 암호화 - **API Key**: 외부 API 호출 시 안전한 Key 관리 (AWS Secrets Manager) #### 데이터 접근 통제 - **Database**: 서비스별 독립 계정, 최소 권한 원칙 - **Redis**: 비밀번호 설정, ACL 적용 - **백업**: 암호화된 백업 저장 ### 6.3 보안 모니터링 #### 위협 탐지 - **Rate Limiting**: API Gateway에서 사용자당 100 req/min - **Brute Force 방지**: 로그인 5회 실패 시 계정 잠금 (삭제됨, 향후 추가 가능) - **SQL Injection 방지**: Prepared Statement 사용 - **XSS 방지**: 입력 데이터 Sanitization #### 로깅 및 감사 - **Access Log**: 모든 API 요청 로깅 - **Audit Log**: 민감 작업 (로그인, 이벤트 생성, 당첨자 추첨) 감사 로그 - **중앙집중식 로깅**: ELK Stack 또는 CloudWatch Logs --- ## 7. 논리 아키텍처 다이어그램 논리 아키텍처 다이어그램은 별도 Mermaid 파일로 작성되었습니다. **파일 위치**: `logical-architecture.mmd` **다이어그램 확인 방법**: 1. https://mermaid.live/edit 접속 2. `logical-architecture.mmd` 파일 내용 붙여넣기 3. 다이어그램 시각적 확인 **다이어그램 구성**: - Client Layer: Web/Mobile Client - Gateway Layer: API Gateway - Service Layer: 7개 마이크로서비스 - Data Layer: Redis Cache, Message Queue, Databases - External APIs: 7개 외부 API **의존성 표현**: - 실선 화살표 (→): 동기적 의존성 - 점선 화살표 (-.->): 비동기 의존성 또는 캐시 접근 - 화살표 레이블: 의존성 목적 명시 --- ## 부록 ### A. 참고 문서 - [유저스토리](../../userstory.md) - [아키텍처 패턴](../../pattern/architecture-pattern.md) - [UI/UX 설계서](../../uiux/uiux.md) - [클라우드 디자인 패턴](../../../claude/cloud-design-patterns.md) ### B. 주요 결정사항 1. **CQRS 패턴 채택**: 읽기/쓰기 책임 분리로 독립적 확장 및 성능 최적화 2. **Event-Driven 아키텍처 채택**: Event Bus(Kafka/SQS)를 통한 서비스 간 느슨한 결합 3. **도메인 이벤트 정의**: 5개 핵심 이벤트로 서비스 간 상태 동기화 4. **Resilience 패턴 전면 적용**: Circuit Breaker, Retry, Timeout, Bulkhead, Fallback 5. **At-Least-Once Delivery**: 이벤트 보장 수준 및 멱등성 설계 6. **Cache-Aside 패턴**: AI/이미지 생성 결과 캐싱으로 응답 시간 90% 개선 7. **Job Queue 분리**: RabbitMQ로 장시간 비동기 작업 처리 8. **서비스별 독립 Database**: Command/Query별 독립 DB로 CQRS 지원 ### C. 향후 개선 방안 (Phase 2 이후) 1. **Event Sourcing 완전 적용**: 모든 상태 변경을 이벤트로 저장하여 시간 여행 및 감사 추적 강화 2. **Saga 패턴 적용**: 복잡한 분산 트랜잭션 보상 로직 체계화 3. **Service Mesh 도입**: Istio를 통한 서비스 간 통신 관찰성 및 보안 강화 4. **Database Sharding**: Event/Participation Write DB 샤딩으로 쓰기 확장성 개선 5. **WebSocket 기반 실시간 푸시**: 대시보드 실시간 업데이트 (폴링 대체) 6. **GraphQL API Gateway**: 클라이언트 맞춤형 데이터 조회 최적화 7. **Dead Letter Queue 고도화**: 실패 이벤트 재처리 및 알림 자동화 --- **문서 버전**: 2.0 **최종 수정일**: 2025-10-22 **작성자**: System Architect **변경 사항**: CQRS 패턴 및 Event-Driven 아키텍처 전환, Resilience 패턴 전면 적용