@startuml 성과분석플로우_외부시퀀스 !theme mono title 성과 분석 플로우 - 외부 시퀀스 다이어그램\n(UFR-ANAL-010: 실시간 성과분석 대시보드 조회) actor "소상공인" as User participant "Frontend" as FE participant "API Gateway" as GW participant "Analytics Service" as Analytics participant "Redis Cache\n(TTL 5분)" as Redis participant "Analytics DB" as AnalyticsDB participant "Kafka\n(Event Topics)" as Kafka box "외부 시스템" #LightGray participant "우리동네TV API" as WooriAPI participant "지니TV API" as GenieAPI participant "SNS APIs\n(Instagram/Naver/Kakao)" as SNSAPI end box == 1. 대시보드 조회 - Cache HIT 시나리오 == User -> FE: 성과분석 대시보드 접근\n(Bottom Nav "분석" 탭 클릭) activate FE FE -> GW: GET /api/events/{id}/analytics\n+ Authorization: Bearer {token} activate GW GW -> GW: JWT 토큰 검증 GW -> Analytics: GET /api/events/{id}/analytics activate Analytics Analytics -> Redis: GET analytics:dashboard:{eventId} activate Redis Redis --> Analytics: **Cache HIT**\n캐시된 대시보드 데이터 반환 deactivate Redis note right of Analytics **Cache-Aside 패턴** - TTL: 5분 - 예상 크기: 5KB - 히트율 목표: 95% - 응답 시간: 0.5초 end note Analytics --> GW: 200 OK\n대시보드 데이터 (JSON) deactivate Analytics GW --> FE: 200 OK\n대시보드 데이터 deactivate GW FE -> FE: 대시보드 렌더링\n- 4개 요약 카드\n- 채널별 성과 차트\n- 시간대별 참여 추이 FE --> User: 실시간 대시보드 표시 deactivate FE == 2. 대시보드 조회 - Cache MISS 시나리오 == User -> FE: 대시보드 새로고침\n또는 첫 조회 activate FE FE -> GW: GET /api/events/{id}/analytics activate GW GW -> Analytics: GET /api/events/{id}/analytics activate Analytics Analytics -> Redis: GET analytics:dashboard:{eventId} activate Redis Redis --> Analytics: **Cache MISS**\nnull 반환 deactivate Redis note right of Analytics **데이터 통합 작업 시작** - Analytics DB 조회 - 외부 채널 API 병렬 호출 - Circuit Breaker 적용 end note ||| == 2.1. Analytics DB 조회 (로컬 데이터) == Analytics -> AnalyticsDB: SELECT event_stats\nWHERE event_id = {id} activate AnalyticsDB AnalyticsDB --> Analytics: 이벤트 통계\n- 총 참여자 수\n- 예상 ROI\n- 매출 증가율 deactivate AnalyticsDB ||| == 2.2. 외부 채널 API 병렬 호출 (Circuit Breaker 적용) == par 병렬 채널 API 호출 Analytics -> WooriAPI: GET /stats/{eventId}\n+ API Key\n[Circuit Breaker] activate WooriAPI alt Circuit Breaker CLOSED (정상) WooriAPI --> Analytics: 200 OK\n- 노출 수: 5,000\n- 조회 수: 1,200 deactivate WooriAPI note right of Analytics **Resilience 패턴** - Circuit Breaker: 실패율 50% 초과 시 Open - Timeout: 10초 - Retry: 최대 3회 (지수 백오프) - Fallback: 캐시된 이전 데이터 반환 end note else Circuit Breaker OPEN (장애) Analytics -> Analytics: **Fallback 실행**\n캐시된 이전 데이터 사용 note right of Analytics Circuit Breaker OPEN 상태 - 빠른 실패로 응답 시간 단축 - 30초 후 Half-Open으로 전환 end note end else Analytics -> GenieAPI: GET /campaign/{eventId}/stats\n+ API Key\n[Circuit Breaker] activate GenieAPI alt 정상 응답 GenieAPI --> Analytics: 200 OK\n- 광고 노출 수: 10,000\n- 클릭 수: 500 deactivate GenieAPI else Timeout (10초 초과) Analytics -> Analytics: **Timeout 처리**\n기본값 반환 (0) note right of Analytics Timeout 발생 - 리소스 점유 방지 - Fallback으로 기본값 설정 end note end else Analytics -> SNSAPI: GET /posts/{eventId}/insights\n+ Access Token\n[Circuit Breaker] activate SNSAPI SNSAPI --> Analytics: 200 OK\n- Instagram: 좋아요 300, 댓글 50\n- Naver: 조회 수 2,000\n- Kakao: 공유 수 100 deactivate SNSAPI end ||| == 2.3. 데이터 통합 및 ROI 계산 == Analytics -> Analytics: 데이터 통합 및 계산\n- 총 노출 수 = 외부 채널 노출 합계\n- 총 참여자 수 = Analytics DB\n- ROI 계산 = (수익 - 비용) / 비용 × 100\n- 채널별 전환율 계산 note right of Analytics **ROI 계산 로직** 총 비용 = 경품 비용 + 플랫폼 비용 예상 수익 = 매출 증가액 + 신규 고객 LTV 투자 대비 수익률 = (수익 - 비용) / 비용 × 100 end note ||| == 2.4. Redis 캐싱 및 응답 == Analytics -> Redis: SET analytics:dashboard:{eventId}\nvalue={통합 데이터}\nTTL=300초 (5분) activate Redis Redis --> Analytics: OK deactivate Redis Analytics --> GW: 200 OK\n대시보드 데이터 (JSON)\n{\n 총참여자: 1,234,\n 총노출: 17,200,\n ROI: 250%,\n 채널별성과: [...]\n} deactivate Analytics GW --> FE: 200 OK\n대시보드 데이터 deactivate GW FE -> FE: 대시보드 렌더링\n- 4개 요약 카드 표시\n- 채널별 성과 차트\n- 시간대별 참여 추이\n- 참여자 프로필 분석 FE --> User: 실시간 대시보드 표시\n(응답 시간: 3초) deactivate FE ||| == 3. 실시간 업데이트 (Background Event 구독) == note over Analytics, Kafka **Analytics Service는 항상 Background에서 Kafka Event Topics를 구독하여 실시간으로 통계를 업데이트합니다** end note Kafka -> Analytics: **EventCreated** 이벤트\n{eventId, storeId, title, objective} activate Analytics Analytics -> AnalyticsDB: INSERT INTO event_stats\n이벤트 기본 정보 초기화 activate AnalyticsDB AnalyticsDB --> Analytics: OK deactivate AnalyticsDB Analytics -> Redis: DEL analytics:dashboard:{eventId}\n캐시 무효화 activate Redis Redis --> Analytics: OK deactivate Redis deactivate Analytics ...참여자 등록 시... Kafka -> Analytics: **ParticipantRegistered** 이벤트\n{participantId, eventId, phoneNumber} activate Analytics Analytics -> AnalyticsDB: UPDATE event_stats\nSET participant_count = participant_count + 1\nWHERE event_id = {eventId} activate AnalyticsDB AnalyticsDB --> Analytics: OK deactivate AnalyticsDB Analytics -> Redis: DEL analytics:dashboard:{eventId}\n캐시 무효화 (다음 조회 시 갱신) activate Redis Redis --> Analytics: OK deactivate Redis deactivate Analytics ...배포 완료 시... Kafka -> Analytics: **DistributionCompleted** 이벤트\n{eventId, distributedChannels, completedAt} activate Analytics Analytics -> AnalyticsDB: INSERT INTO channel_stats\n배포 채널 통계 저장 activate AnalyticsDB AnalyticsDB --> Analytics: OK deactivate AnalyticsDB Analytics -> Redis: DEL analytics:dashboard:{eventId}\n캐시 무효화 activate Redis Redis --> Analytics: OK deactivate Redis deactivate Analytics note right of Analytics **실시간 업데이트 메커니즘** - EventCreated: 이벤트 기본 정보 초기화 - ParticipantRegistered: 참여자 수 실시간 증가 - DistributionCompleted: 배포 채널 통계 업데이트 - 캐시 무효화: 다음 조회 시 최신 데이터 갱신 end note @enduml