mirror of
https://github.com/ktds-dg0501/kt-event-marketing.git
synced 2025-12-06 22:06:23 +00:00
주요 변경사항: - User Service 사업자번호 검증 로직 삭제 (국세청 API 제거) - User Service → Event Service 회원정보 제공 API 추가 - Redis 기반 서비스 간 데이터 공유 구조로 변경 - AI Service → Redis 저장 → Content Service 읽기 - Participation Service 참여자 목록 조회 기능 추가 - WinnerSelected 이벤트 토픽 제거 (3개 토픽으로 축소) - Redis → Event DB 저장 로직 추가 (이벤트 publish 시) - AI/Content Service Timeout 5분으로 변경 (30초/20초 → 300초) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
870 lines
40 KiB
Markdown
870 lines
40 KiB
Markdown
# 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 패턴 전면 적용
|
|
- **v2.1** (2025-10-22): 서비스 구조 간소화, Kafka 통합 (Event Bus + Job Queue), Distribution 비동기 처리
|
|
- **v2.2** (2025-10-22): Distribution Service 동기 호출 전환 (REST API 직접 호출)
|
|
|
|
---
|
|
|
|
## 목차
|
|
1. [개요](#1-개요)
|
|
2. [서비스 아키텍처](#2-서비스-아키텍처)
|
|
3. [주요 사용자 플로우](#3-주요-사용자-플로우)
|
|
4. [데이터 흐름 및 캐싱 전략](#4-데이터-흐름-및-캐싱-전략)
|
|
5. [확장성 및 성능 고려사항](#5-확장성-및-성능-고려사항)
|
|
6. [보안 고려사항](#6-보안-고려사항)
|
|
7. [논리 아키텍처 다이어그램](#7-논리-아키텍처-다이어그램)
|
|
|
|
---
|
|
|
|
## 1. 개요
|
|
|
|
### 1.1 설계 원칙
|
|
|
|
본 논리 아키텍처는 다음 원칙을 기반으로 설계되었습니다:
|
|
|
|
#### 유저스토리 기반 설계
|
|
- 20개 유저스토리와 정확히 매칭
|
|
- 불필요한 추가 기능 배제
|
|
- 비즈니스 요구사항 우선 반영
|
|
|
|
#### Event-Driven 아키텍처
|
|
- **Kafka 기반 통합**: Event Bus와 Job Queue를 Kafka로 통합
|
|
- **비동기 메시징**: Kafka Topics를 통한 서비스 간 통신
|
|
- **느슨한 결합**: 서비스 간 직접 의존성 제거
|
|
- **확장성**: 이벤트 구독자 추가로 기능 확장 용이
|
|
- **장애 격리**: 이벤트 발행/구독 실패 시 서비스 독립성 유지
|
|
|
|
#### Kafka 통합 전략
|
|
- **Event Topics**: 도메인 이벤트 발행/구독 (EventCreated, ParticipantRegistered 등)
|
|
- **Job Topics**: 비동기 작업 요청/처리 (ai 이벤트 생성, 이미지 생성)
|
|
- **단일 메시징 플랫폼**: 운영 복잡도 감소 및 일관된 메시지 처리
|
|
|
|
#### Resilience 패턴 적용
|
|
- **Circuit Breaker**: 외부 API 장애 시 빠른 실패 및 복구 (Hystrix/Resilience4j)
|
|
- **Retry Pattern**: 일시적 장애 시 자동 재시도 (지수 백오프)
|
|
- **Timeout Pattern**: 응답 시간 제한으로 리소스 점유 방지
|
|
- **Bulkhead Pattern**: 리소스 격리로 장애 전파 차단
|
|
- **Fallback Pattern**: 장애 시 대체 로직 실행 (캐시 응답 등)
|
|
|
|
### 1.2 핵심 컴포넌트 정의
|
|
|
|
#### Core Services
|
|
1. **User Service**: 사용자 인증 및 매장정보 관리
|
|
- 회원가입/로그인 (JWT 발급)
|
|
- 프로필 CRUD
|
|
- Event Service로 회원정보 제공
|
|
|
|
2. **Event Service**: 이벤트 전체 생명주기 관리
|
|
- 이벤트 생성/수정/삭제/조회
|
|
- 이벤트 생성 플로우 오케스트레이션
|
|
- Kafka Job 발행 (AI, 이미지)
|
|
- Distribution Service 동기 호출 (배포)
|
|
- Kafka Event 발행 (EventCreated)
|
|
|
|
3. **Participation Service**: 참여 및 당첨자 관리
|
|
- 참여 접수 및 중복 체크
|
|
- 참여자 목록 조회
|
|
- 당첨자 추첨 및 조회
|
|
- Kafka Event 발행 (ParticipantRegistered)
|
|
|
|
4. **Analytics Service**: 실시간 성과 분석 및 대시보드
|
|
- 대시보드 데이터 조회 (Redis 캐싱)
|
|
- Kafka Event 구독 (EventCreated, ParticipantRegistered, DistributionCompleted)
|
|
- 외부 채널 통계 수집 (Circuit Breaker + Fallback)
|
|
- ROI 계산 및 성과 분석
|
|
|
|
#### Async Services (비동기 처리)
|
|
1. **AI Service**: AI 기반 이벤트 추천
|
|
- Kafka Job 구독 (ai 이벤트 생성)
|
|
- 외부 AI API 호출 (Circuit Breaker, Timeout 5분)
|
|
- 결과 Redis 저장 (TTL 24시간)
|
|
|
|
2. **Content Service**: SNS 이미지 생성
|
|
- Redis에서 AI 데이터 읽기
|
|
- 외부 이미지 생성 API 호출 (Circuit Breaker, Timeout 5분)
|
|
- 생성된 이미지 Redis 저장 (CDN URL, TTL 7일)
|
|
|
|
3. **Distribution Service**: 다중 채널 배포 (동기)
|
|
- REST API 제공 (Event Service에서 호출)
|
|
- 병렬 배포 (Circuit Breaker, Retry, Bulkhead)
|
|
- Kafka Event 발행 (DistributionCompleted)
|
|
|
|
#### Kafka (통합 메시징 플랫폼)
|
|
**Event Topics** (도메인 이벤트):
|
|
- **EventCreated**: 이벤트 생성 시
|
|
- **ParticipantRegistered**: 참여자 등록 시
|
|
- **DistributionCompleted**: 배포 완료 시
|
|
|
|
**Job Topics** (비동기 작업):
|
|
- **ai 이벤트 생성**: AI 추천 작업
|
|
- **이미지 생성**: 이미지 생성 작업
|
|
|
|
**특징**:
|
|
- At-Least-Once Delivery 보장
|
|
- Partition Key 기반 순서 보장
|
|
- Dead Letter Queue 지원
|
|
|
|
#### Data Layer
|
|
- **Redis Cache**: 세션, AI 결과, 이미지 URL, 대시보드 캐싱
|
|
- **PostgreSQL**: 서비스별 독립 데이터베이스
|
|
- User DB, Event DB, Participation DB, Analytics DB
|
|
|
|
#### External Systems
|
|
- **AI APIs**: Claude/GPT-4 (트렌드 분석)
|
|
- **이미지 생성 APIs**: Stable Diffusion/DALL-E
|
|
- **배포 채널 APIs**: 우리동네TV, 링고비즈, 지니TV, SNS APIs (비동기 배포)
|
|
|
|
---
|
|
|
|
## 2. 서비스 아키텍처
|
|
|
|
### 2.1 서비스별 책임
|
|
|
|
#### User Service
|
|
**핵심 책임**:
|
|
- 회원가입/로그인 (JWT 토큰 발급)
|
|
- 프로필 CRUD (매장 정보 포함)
|
|
- 세션 관리
|
|
- Event Service로 회원정보 제공
|
|
|
|
**관련 유저스토리**: UFR-USER-010, 020, 030, 040
|
|
|
|
**서비스 간 호출**:
|
|
- **Event Service**: 회원정보 조회 API 제공 (매장 정보 포함)
|
|
|
|
**데이터 저장**:
|
|
- User DB: users, stores 테이블
|
|
- Redis: 세션 정보 (TTL 7일)
|
|
|
|
#### Event Service
|
|
**핵심 책임**:
|
|
- 이벤트 생성/수정/삭제/조회
|
|
- 이벤트 생성 플로우 오케스트레이션
|
|
- Kafka Job 발행 (AI, 이미지, 배포)
|
|
- Kafka Event 발행 (EventCreated)
|
|
|
|
**관련 유저스토리**: UFR-EVENT-010, 020, 030, 040, 050, 060, 070
|
|
|
|
**Kafka 이벤트 발행**:
|
|
1. **EventCreated**: 이벤트 생성 완료 시
|
|
- Payload: eventId, storeId, title, objective, createdAt
|
|
- 구독자: Analytics Service
|
|
|
|
**Kafka Job 발행**:
|
|
1. **ai 이벤트 생성**: AI 추천 요청
|
|
2. **이미지 생성**: 이미지 생성 요청
|
|
|
|
**서비스 간 호출**:
|
|
- **Distribution Service**: 다중 채널 배포 (동기 호출, Circuit Breaker 적용)
|
|
|
|
**주요 플로우**:
|
|
1. 이벤트 목적 선택 → Event DB 저장 → EventCreated 발행
|
|
2. AI 추천 요청 → ai 이벤트 생성 발행
|
|
3. 이미지 생성 요청 → 이미지 생성 발행
|
|
4. 배포 승인 → Distribution Service 동기 호출
|
|
|
|
**데이터 저장**:
|
|
- Event DB: events, event_objectives, event_prizes 테이블
|
|
|
|
#### Participation Service
|
|
**핵심 책임**:
|
|
- 이벤트 참여 접수 및 검증
|
|
- 참여자 목록 조회
|
|
- 당첨자 추첨 및 조회
|
|
- Kafka Event 발행 (ParticipantRegistered)
|
|
|
|
**관련 유저스토리**: UFR-PART-010, 020, 030
|
|
|
|
**Kafka 이벤트 발행**:
|
|
1. **ParticipantRegistered**: 참여자 등록 시
|
|
- Payload: participantId, eventId, phoneNumber, registeredAt
|
|
- 구독자: Analytics Service
|
|
|
|
**주요 기능**:
|
|
- 중복 참여 체크 (전화번호 기반)
|
|
- 참여자 목록 조회 (페이지네이션 지원)
|
|
- 난수 기반 무작위 추첨
|
|
- 매장 방문 고객 가산점 적용
|
|
- 당첨자 조회
|
|
|
|
**데이터 저장**:
|
|
- Participation DB: participants, winners 테이블
|
|
|
|
#### Analytics Service
|
|
**핵심 책임**:
|
|
- 실시간 성과 대시보드 조회
|
|
- 채널별 성과 분석 및 통계
|
|
- ROI 계산 및 성과 집계
|
|
|
|
**관련 유저스토리**: UFR-ANAL-010
|
|
|
|
**Kafka 이벤트 구독**:
|
|
- **EventCreated**: 이벤트 기본 정보 초기화
|
|
- **ParticipantRegistered**: 참여자 수 실시간 증가
|
|
- **DistributionCompleted**: 배포 완료 통계 업데이트
|
|
|
|
**Resilience 패턴**:
|
|
- **Circuit Breaker**: 외부 채널 API 조회 시 (실패율 50% 초과 시 Open)
|
|
- **Fallback**: 캐시된 이전 데이터 반환
|
|
- **Cache-Aside**: Redis 캐싱 (TTL 5분)
|
|
|
|
**데이터 통합**:
|
|
- Event Service: 이벤트 정보 조회 (DB 직접 또는 REST)
|
|
- Participation Service: 참여자/당첨자 데이터 조회
|
|
- 외부 APIs: 우리동네TV, 지니TV, SNS 통계 수집
|
|
|
|
**데이터 저장**:
|
|
- Analytics DB: event_stats, channel_stats
|
|
- Redis: 대시보드 데이터 (TTL 5분)
|
|
|
|
### 2.2 Async Services (비동기 처리)
|
|
|
|
#### AI Service
|
|
**핵심 책임**:
|
|
- 업종/지역/시즌 트렌드 분석
|
|
- 3가지 이벤트 기획안 자동 생성
|
|
- 예상 성과 계산
|
|
|
|
**관련 유저스토리**: UFR-AI-010
|
|
|
|
**Kafka Job 구독**:
|
|
- **ai 이벤트 생성**: AI 추천 작업 요청
|
|
|
|
**Resilience 패턴**:
|
|
- **Circuit Breaker**: AI API 호출 시 (실패율 50% 초과 시 Open)
|
|
- **Timeout**: 5분 (300초)
|
|
- **Fallback**: 캐시된 이전 추천 결과 + 안내 메시지
|
|
- **Cache-Aside**: Redis 캐싱 (TTL 24시간)
|
|
|
|
**처리 시간**:
|
|
- 캐시 HIT: 0.1초
|
|
- 캐시 MISS: 5분 이내 (비동기 처리)
|
|
|
|
**데이터 저장**:
|
|
- Redis: AI 추천 결과 (TTL 24시간)
|
|
- Redis: Job 상태 정보 (TTL 1시간)
|
|
|
|
#### Content Service
|
|
**핵심 책임**:
|
|
- 3가지 스타일 SNS 이미지 자동 생성
|
|
- 플랫폼별 이미지 최적화
|
|
- 이미지 편집 기능
|
|
|
|
**관련 유저스토리**: UFR-CONT-010, 020
|
|
|
|
**데이터 읽기**:
|
|
- Redis에서 AI Service가 저장한 이벤트 데이터 읽기
|
|
|
|
**Resilience 패턴**:
|
|
- **Circuit Breaker**: 이미지 생성 API 호출 시 (실패율 50% 초과 시 Open)
|
|
- **Timeout**: 5분 (300초)
|
|
- **Fallback**: 기본 템플릿 이미지 제공
|
|
- **Cache-Aside**: Redis 캐싱 (TTL 7일)
|
|
|
|
**처리 시간**:
|
|
- 캐시 HIT: 0.1초
|
|
- 캐시 MISS: 5분 이내 (비동기 처리)
|
|
|
|
**데이터 저장**:
|
|
- Redis: 이미지 생성 결과 (CDN URL, TTL 7일)
|
|
- CDN: 생성된 이미지 파일
|
|
|
|
#### Distribution Service
|
|
**핵심 책임**:
|
|
- 다중 채널 병렬 배포 (동기)
|
|
- 배포 상태 모니터링
|
|
- Kafka Event 발행 (DistributionCompleted)
|
|
|
|
**관련 유저스토리**: UFR-DIST-010, 020
|
|
|
|
**주요 API**:
|
|
- `POST /api/distribution/distribute`: 다중 채널 배포 요청 (Event Service에서 호출)
|
|
|
|
**Kafka 이벤트 발행**:
|
|
- **DistributionCompleted**: 배포 완료 시
|
|
- Payload: eventId, distributedChannels, completedAt
|
|
- 구독자: Analytics Service
|
|
|
|
**Resilience 패턴**:
|
|
- **Circuit Breaker**: 각 외부 채널 API별 독립 적용 (실패율 50% 초과 시 Open)
|
|
- **Retry**: 최대 3회 재시도 (지수 백오프: 1초, 2초, 4초)
|
|
- **Bulkhead**: 채널별 스레드 풀 격리 (장애 전파 방지)
|
|
- **Fallback**: 실패 채널 스킵 + 알림
|
|
|
|
**처리 시간**: 1분 이내 (모든 채널 배포 완료)
|
|
|
|
**배포 채널**:
|
|
- 우리동네TV API (영상 업로드)
|
|
- 링고비즈 API (연결음 업데이트)
|
|
- 지니TV API (TV 광고 등록)
|
|
- SNS APIs (Instagram, Naver, Kakao 자동 포스팅)
|
|
|
|
**데이터 저장**:
|
|
- Event DB: distribution_logs 테이블
|
|
|
|
### 2.3 Kafka 통신 전략
|
|
|
|
#### Kafka 아키텍처
|
|
**기술 스택**: Apache Kafka (Event Topics + Job Topics 통합)
|
|
**보장 수준**: At-Least-Once Delivery
|
|
**메시지 포맷**: JSON
|
|
|
|
#### Event Topics (도메인 이벤트)
|
|
|
|
| 토픽명 | 발행자 | 구독자 | Payload | 용도 |
|
|
|---------|--------|--------|---------|------|
|
|
| **EventCreated** | Event Service | Analytics Service | eventId, storeId, title, objective, createdAt | 이벤트 생성 시 통계 초기화 |
|
|
| **ParticipantRegistered** | Participation Service | Analytics Service | participantId, eventId, phoneNumber, registeredAt | 참여자 등록 시 실시간 통계 업데이트 |
|
|
| **DistributionCompleted** | Distribution Service | Analytics Service | eventId, distributedChannels, completedAt | 배포 완료 시 통계 업데이트 |
|
|
|
|
#### Job Topics (비동기 작업)
|
|
|
|
| 토픽명 | 발행자 | 구독자 | Payload | 용도 |
|
|
|---------|--------|--------|---------|------|
|
|
| **ai 이벤트 생성** | Event Service | AI Service | eventId, objective, industry, region | AI 트렌드 분석 및 이벤트 추천 요청 |
|
|
| **이미지 생성** | Event Service | Content Service | eventId, content, style | SNS 이미지 생성 요청 (3가지 스타일) |
|
|
|
|
#### 통신 패턴별 설계
|
|
|
|
**1. Event Topics (도메인 이벤트)**
|
|
- **사용 시나리오**: 서비스 간 상태 변경 알림 및 동기화
|
|
- **통신 방식**: Kafka Pub/Sub
|
|
- **장점**:
|
|
- 서비스 독립성 보장
|
|
- 장애 격리
|
|
- 확장 용이
|
|
- **단점**:
|
|
- 최종 일관성 (Eventual Consistency)
|
|
- 디버깅 복잡도 증가
|
|
|
|
**2. Job Topics (비동기 작업)**
|
|
- **사용 시나리오**: 장시간 작업 (AI 추천, 이미지 생성)
|
|
- **통신 방식**: Kafka 메시지 큐
|
|
- **패턴**: Asynchronous Request-Reply
|
|
- **처리 플로우**:
|
|
1. Event Service → Kafka Job Topic: Job 발행
|
|
2. Async Service → Kafka: Job 수신 및 처리
|
|
3. Client → Event Service: Job 상태 폴링 (5초 간격)
|
|
4. Async Service → Redis: 결과 캐싱
|
|
5. Event Service → Client: 완료 응답
|
|
|
|
**3. 서비스 간 동기 호출**
|
|
- **사용 시나리오**: 다중 채널 배포 (Distribution Service)
|
|
- **통신 방식**: REST API (HTTP/JSON)
|
|
- **패턴**: Synchronous Request-Reply
|
|
- **처리 플로우**:
|
|
1. Event Service → Distribution Service: POST /api/distribution/distribute
|
|
2. Distribution Service: 다중 채널 병렬 배포 (1분 이내)
|
|
3. Distribution Service → Event Service: 배포 완료 응답
|
|
4. Distribution Service → Kafka: DistributionCompleted 이벤트 발행
|
|
- **Resilience**: Circuit Breaker 적용 (실패율 50% 초과 시 Open)
|
|
|
|
**4. 데이터베이스 직접 조회**
|
|
- **사용 시나리오**: Analytics Service가 이벤트/참여 데이터 필요 시
|
|
- **패턴**: Database-per-Service 원칙 유지, 필요 시 이벤트로 데이터 동기화
|
|
- **통신 방식**: Kafka 이벤트 구독 → Analytics DB 저장 → 로컬 조회
|
|
- **특징**: 서비스 간 직접 API 호출 최소화
|
|
|
|
#### 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 | 이유 |
|
|
|--------|---------|------|
|
|
| AI Service (AI API) | 5분 (300초) | 복잡한 분석 작업 |
|
|
| Content Service (이미지 API) | 5분 (300초) | 이미지 생성 시간 고려 |
|
|
| Distribution Service (채널 APIs) | 10초 | 빠른 배포 필요 |
|
|
|
|
**4. Bulkhead 패턴**
|
|
- **적용 대상**: Distribution Service (다중 채널 배포)
|
|
- **목적**: 채널별 리소스 격리로 장애 전파 차단
|
|
- **설정**:
|
|
```yaml
|
|
bulkhead:
|
|
max-concurrent-calls: 10 # 채널당 최대 10개 동시 호출
|
|
max-wait-duration: 0s # 대기 없이 즉시 실패
|
|
```
|
|
|
|
**5. Fallback 패턴**
|
|
- **적용 대상**: 모든 외부 API 호출
|
|
- **전략**:
|
|
| 서비스 | Fallback 전략 |
|
|
|--------|---------------|
|
|
| AI Service | 캐시된 이전 추천 결과 + 안내 메시지 |
|
|
| Content Service | 기본 템플릿 이미지 제공 |
|
|
| Distribution Service | 실패 채널 스킵 + 알림 |
|
|
| Analytics Service | 캐시된 이전 데이터 반환 |
|
|
|
|
#### 이벤트 순서 보장
|
|
- **Kafka Partition Key**: eventId 기준으로 파티션 할당
|
|
- **동일 이벤트의 모든 이벤트**: 동일 파티션 → 순서 보장
|
|
- **다른 이벤트**: 독립적 처리 → 병렬 처리 가능
|
|
|
|
#### 이벤트 재처리 (At-Least-Once)
|
|
- **멱등성 보장**: 구독자는 동일 이벤트 중복 처리 시 멱등성 유지
|
|
- **방법**: 이벤트 ID 기반 중복 체크 (Redis Set 사용)
|
|
|
|
---
|
|
|
|
## 3. 주요 사용자 플로우
|
|
|
|
### 3.1 이벤트 생성 플로우 (Event-Driven + Kafka)
|
|
|
|
```
|
|
1. [이벤트 목적 선택]
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ Client → Event Service │
|
|
│ - POST /api/events (목적, 매장 정보) │
|
|
│ - Event DB에 저장 │
|
|
│ - EventCreated 이벤트 발행 → Kafka │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ Kafka → Analytics Service │
|
|
│ - EventCreated 이벤트 구독 │
|
|
│ - Analytics DB에 기본 통계 초기화 │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
|
|
2. [AI 이벤트 추천]
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ Client → Event Service │
|
|
│ - POST /api/events/{id}/ai-recommendations │
|
|
│ - Kafka ai 이벤트 생성 토픽 발행 (AI 작업 요청) │
|
|
│ - Job ID 즉시 반환 (0.1초) │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ AI Service (Background) │
|
|
│ - Kafka ai 이벤트 생성 토픽 구독 │
|
|
│ - Redis 캐시 확인 (Cache-Aside) │
|
|
│ - 캐시 MISS: Claude API 호출 (5분) [Circuit Breaker] │
|
|
│ - AI 추천 결과를 Redis에 저장 (TTL 24시간) │
|
|
│ - Job 상태 완료로 업데이트 │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ Client (Polling) │
|
|
│ - GET /api/jobs/{id} (5초 간격) │
|
|
│ - 완료 시: AI 추천 결과 반환 (3가지 옵션) │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
|
|
3. [SNS 이미지 생성]
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ Content Service (Background) │
|
|
│ - Redis에서 AI Service가 저장한 이벤트 데이터 읽기 │
|
|
│ - Redis 캐시 확인 (이미지 생성 여부) │
|
|
│ - 캐시 MISS: Stable Diffusion API (5분) [Circuit Breaker] │
|
|
│ - 이미지 CDN 업로드 │
|
|
│ - 생성된 이미지 URL을 Redis에 저장 (TTL 7일) │
|
|
│ - Job 상태 완료로 업데이트 │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ Client (Polling) │
|
|
│ - GET /api/jobs/{id} (3초 간격) │
|
|
│ - 완료 시: 3가지 스타일 이미지 URL 반환 │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
|
|
4. [최종 승인 및 배포]
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ Client → Event Service │
|
|
│ - POST /api/events/{id}/publish │
|
|
│ - Redis의 이벤트 관련 정보(AI 추천, 이미지 URL)를 조회 │
|
|
│ - Event DB에 이벤트 정보 저장 │
|
|
│ - Event 상태 변경 (DRAFT → PUBLISHED) │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ Event Service → Distribution Service │
|
|
│ - POST /api/distribution/distribute (동기 호출) │
|
|
│ - 다중 채널 병렬 배포 [Circuit Breaker + Bulkhead] │
|
|
│ * 우리동네TV API (영상 업로드) [Retry: 3회] │
|
|
│ * 링고비즈 API (연결음 업데이트) [Retry: 3회] │
|
|
│ * 지니TV API (광고 등록) [Retry: 3회] │
|
|
│ * SNS APIs (Instagram, Naver, Kakao) [Retry: 3회] │
|
|
│ - 배포 완료: DistributionCompleted 이벤트 발행 → Kafka │
|
|
│ - Event Service로 배포 완료 응답 (1분 이내) │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ Kafka → Analytics Service │
|
|
│ - DistributionCompleted 이벤트 구독 │
|
|
│ - Analytics DB 배포 통계 업데이트 │
|
|
│ - 대시보드 캐시 무효화 (다음 조회 시 갱신) │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ Event Service → Client │
|
|
│ - 배포 완료 응답 반환 │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### 3.2 고객 참여 플로우 (Event-Driven)
|
|
|
|
```
|
|
1. [이벤트 참여]
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ Client → Participation Service │
|
|
│ - POST /api/events/{id}/participate │
|
|
│ - 중복 참여 체크 (전화번호 기반) │
|
|
│ - Participation DB에 저장 │
|
|
│ - ParticipantRegistered 이벤트 발행 → Kafka │
|
|
│ - 응모 번호 즉시 반환 │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ Kafka → Analytics Service │
|
|
│ - ParticipantRegistered 이벤트 구독 │
|
|
│ - 실시간 참여자 수 증가 │
|
|
│ - Analytics DB에 참여 통계 업데이트 │
|
|
│ - 대시보드 캐시 무효화 │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
|
|
2. [당첨자 추첨]
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ Client → Participation Service │
|
|
│ - POST /api/events/{id}/draw-winners │
|
|
│ - 난수 기반 무작위 추첨 │
|
|
│ - Winners DB에 저장 │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### 3.3 성과 분석 플로우 (Event-Driven)
|
|
|
|
```
|
|
1. [실시간 대시보드 조회]
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ Client → Analytics Service │
|
|
│ - GET /api/events/{id}/analytics │
|
|
│ - Redis 캐시 확인 (TTL 5분) │
|
|
│ * 캐시 HIT: 즉시 반환 (0.5초) │
|
|
│ * 캐시 MISS: 아래 데이터 통합 │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ Analytics Service (데이터 통합) │
|
|
│ - Analytics DB: 이벤트/참여 통계 조회 (로컬 DB) │
|
|
│ - 외부 APIs: 채널별 노출/클릭 수 [Circuit Breaker + Fallback] │
|
|
│ * 우리동네TV API (조회수) │
|
|
│ * 지니TV API (광고 노출 수) │
|
|
│ * SNS APIs (좋아요, 댓글, 공유 수) │
|
|
│ - Redis 캐싱 (TTL 5분) │
|
|
│ - 대시보드 데이터 반환 │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
|
|
2. [실시간 업데이트 (Event 구독)]
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ Analytics Service (Background) │
|
|
│ - EventCreated 구독: 이벤트 기본 정보 초기화 │
|
|
│ - ParticipantRegistered 구독: 참여자 수 실시간 증가 │
|
|
│ - DistributionCompleted 구독: 배포 채널 통계 업데이트 │
|
|
│ - 캐시 무효화: 다음 조회 시 최신 데이터 갱신 │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### 3.4 플로우 특징
|
|
|
|
#### Kafka 통합 이점
|
|
- **단일 메시징 플랫폼**: Event Bus와 Job Queue를 Kafka로 통합, 운영 복잡도 감소
|
|
- **일관된 메시지 처리**: 모든 비동기 통신이 Kafka를 통해 이루어져 모니터링 및 디버깅 용이
|
|
- **확장성**: Kafka의 높은 처리량으로 대규모 이벤트 처리 지원
|
|
|
|
#### 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 | - |
|
|
| AI | `ai:recommendation:{업종}:{지역}:{목적}` | Hash | 24시간 | 10KB | 80% |
|
|
| AI | `ai:event:{이벤트ID}` | Hash | 24시간 | 10KB | - |
|
|
| 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. 다이어그램 시각적 확인
|
|
|
|
**다이어그램 구성**:
|
|
- Services: 4개 핵심 서비스 (User, Event, Participation, Analytics)
|
|
- Async Services: 3개 비동기 서비스 (AI, Content, Distribution)
|
|
- Kafka: Event Topics + Job Topics 통합 메시징 플랫폼
|
|
- External System: 통합된 외부 시스템 (국세청 API, AI API, 이미지 생성 API, 배포 채널 APIs)
|
|
|
|
**의존성 표현**:
|
|
- 굵은 화살표 (==>): Kafka Event Topics 발행
|
|
- 실선 화살표 (-->): Kafka Job Topics 발행 또는 외부 시스템 호출
|
|
- 점선 화살표 (-.->): Kafka 구독
|
|
|
|
---
|
|
|
|
## 부록
|
|
|
|
### A. 참고 문서
|
|
- [유저스토리](../../userstory.md)
|
|
- [아키텍처 패턴](../../pattern/architecture-pattern.md)
|
|
- [UI/UX 설계서](../../uiux/uiux.md)
|
|
- [클라우드 디자인 패턴](../../../claude/cloud-design-patterns.md)
|
|
|
|
### B. 주요 결정사항
|
|
1. **Kafka 통합 메시징 플랫폼 채택**: Event Bus와 Job Queue를 Kafka로 통합하여 운영 복잡도 감소
|
|
2. **Event-Driven 아키텍처 채택**: Kafka를 통한 서비스 간 느슨한 결합 및 비동기 통신
|
|
3. **도메인 이벤트 정의**: 3개 Event Topics (EventCreated, ParticipantRegistered, DistributionCompleted)
|
|
4. **Job Topics 정의**: 2개 Job Topics (ai 이벤트 생성, 이미지 생성)로 장시간 비동기 작업 처리
|
|
5. **Resilience 패턴 전면 적용**: Circuit Breaker, Retry, Timeout, Bulkhead, Fallback
|
|
6. **At-Least-Once Delivery**: Kafka 메시지 보장 및 멱등성 설계
|
|
7. **Cache-Aside 패턴**: AI/이미지 생성 결과 캐싱으로 응답 시간 90% 개선
|
|
8. **Redis 기반 서비스 간 데이터 공유**: AI Service → Redis → Content Service 데이터 흐름
|
|
9. **Redis to DB 영구 저장**: 이벤트 생성 완료 시 Redis 데이터를 Event DB에 저장
|
|
10. **동기 배포**: Event Service가 Distribution Service를 REST API로 직접 호출하여 다중 채널 배포 동기 처리
|
|
11. **서비스별 독립 Database**: Database-per-Service 패턴으로 서비스 독립성 보장
|
|
12. **장시간 작업 Timeout 조정**: AI/Content Service Timeout을 5분으로 설정하여 복잡한 생성 작업 지원
|
|
|
|
### 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.2
|
|
**최종 수정일**: 2025-10-22
|
|
**작성자**: System Architect
|
|
**변경 사항**: Distribution Service 동기 호출 전환 (REST API 직접 호출)
|