@startuml analytics-대시보드조회-캐시미스 !theme mono title Analytics Service - 대시보드 조회 (Cache MISS + 외부 API 병렬 호출) 내부 시퀀스\n(UFR-ANAL-010: 실시간 성과분석 대시보드 조회) participant "AnalyticsController" as Controller participant "AnalyticsService" as Service participant "CacheService" as Cache participant "AnalyticsRepository" as Repository participant "ExternalChannelService" as ChannelService participant "ROICalculator" as Calculator participant "CircuitBreaker" as CB participant "Redis" as Redis database "Analytics DB" as DB -> Controller: GET /api/events/{id}/analytics activate Controller Controller -> Service: getDashboardData(eventId, userId) activate Service Service -> Cache: get("analytics:dashboard:{eventId}") activate Cache Cache -> Redis: GET analytics:dashboard:{eventId} activate Redis Redis --> Cache: **Cache MISS** (null) deactivate Redis Cache --> Service: null (캐시 미스) deactivate Cache note right of Service **Cache MISS 처리** - 데이터 통합 작업 시작 - 로컬 DB 조회 + 외부 API 병렬 호출 end note ||| == 1. Analytics DB 조회 (로컬 데이터) == Service -> Repository: getEventStats(eventId) activate Repository Repository -> DB: SELECT event_stats\nWHERE event_id = ? activate DB DB --> Repository: EventStatsEntity\n- totalParticipants\n- estimatedROI\n- salesGrowthRate deactivate DB Repository --> Service: EventStats deactivate Repository note right of Service **로컬 데이터 확보** - 총 참여자 수 - 예상 ROI (DB 캐시) - 매출 증가율 (POS 연동) end note ||| == 2. 외부 채널 API 병렬 호출 (Circuit Breaker 적용) == note right of Service **병렬 처리 시작** - CompletableFuture 3개 생성 - 우리동네TV, 지니TV, SNS APIs 동시 호출 - Circuit Breaker 적용 (채널별 독립) end note par 외부 API 병렬 호출 Service -> ChannelService: getWooriTVStats(eventId) activate ChannelService ChannelService -> CB: execute("wooriTV", () -> callAPI()) activate CB note right of CB **Circuit Breaker** - State: CLOSED (정상) - Failure Rate: 50% 초과 시 OPEN - Timeout: 10초 end note CB -> CB: 외부 API 호출\nGET /stats/{eventId} alt Circuit Breaker CLOSED (정상) CB --> ChannelService: ChannelStats\n- views: 5000\n- clicks: 1200 deactivate CB ChannelService --> Service: WooriTVStats deactivate ChannelService else Circuit Breaker OPEN (장애) CB -> CB: **Fallback 실행**\n캐시된 이전 데이터 반환 note right of CB Fallback 전략: - Redis에서 이전 통계 조회 - 없으면 기본값 (0) 반환 - 알림: "일부 채널 데이터 로딩 실패" end note CB --> ChannelService: Fallback 데이터 deactivate CB ChannelService --> Service: WooriTVStats (Fallback) deactivate ChannelService end else Service -> ChannelService: getGenieTVStats(eventId) activate ChannelService ChannelService -> CB: execute("genieTV", () -> callAPI()) activate CB CB -> CB: 외부 API 호출\nGET /campaign/{id}/stats alt 정상 응답 CB --> ChannelService: ChannelStats\n- adViews: 10000\n- clicks: 500 deactivate CB ChannelService --> Service: GenieTVStats deactivate ChannelService else Timeout (10초 초과) CB -> CB: **Timeout 처리**\n기본값 반환 note right of CB Timeout 발생: - 리소스 점유 방지 - Fallback으로 기본값 (0) 설정 - 알림: "지니TV 데이터 로딩 지연" end note CB --> ChannelService: 기본값 (0) deactivate CB ChannelService --> Service: GenieTVStats (기본값) deactivate ChannelService end else Service -> ChannelService: getSNSStats(eventId) activate ChannelService ChannelService -> CB: execute("SNS", () -> callAPIs()) activate CB note right of CB **SNS APIs 통합 호출** - Instagram API - Naver Blog API - Kakao Channel API - 3개 API 병렬 호출 end note CB -> CB: 외부 APIs 호출\n(Instagram, Naver, Kakao) CB --> ChannelService: SNSStats\n- Instagram: likes 300, comments 50\n- Naver: views 2000\n- Kakao: shares 100 deactivate CB ChannelService --> Service: SNSStats deactivate ChannelService end ||| == 3. 데이터 통합 및 ROI 계산 == Service -> Service: mergeChannelStats(\n wooriTV, genieTV, sns\n) note right of Service **데이터 통합** - 총 노출 수 = 외부 채널 노출 합계 - 총 참여자 수 = Analytics DB - 채널별 전환율 = 참여자 수 / 노출 수 end note Service -> Calculator: calculateROI(\n eventStats, channelStats\n) activate Calculator note right of Calculator **ROI 계산 로직** 총 비용 = 경품 비용 + 플랫폼 비용 예상 수익 = 매출 증가액 + 신규 고객 LTV ROI = (수익 - 비용) / 비용 × 100 end note Calculator --> Service: ROIData\n- roi: 250%\n- totalCost: 100만원\n- totalRevenue: 350만원\n- breakEvenPoint: 달성 deactivate Calculator Service -> Service: buildDashboardData(\n eventStats, channelStats, roiData\n) note right of Service **대시보드 데이터 구조 생성** - 4개 요약 카드 - 채널별 성과 차트 데이터 - 시간대별 참여 추이 - 참여자 프로필 분석 - 비교 분석 (업종 평균, 이전 이벤트) end note ||| == 4. Redis 캐싱 및 응답 == Service -> Cache: set(\n "analytics:dashboard:{eventId}",\n dashboardData,\n TTL=300\n) activate Cache Cache -> Redis: SET analytics:dashboard:{eventId}\nvalue={통합 데이터}\nEX 300 activate Redis Redis --> Cache: OK deactivate Redis Cache --> Service: OK deactivate Cache note right of Service **캐싱 완료** - TTL: 300초 (5분) - 다음 조회 시 Cache HIT - 예상 크기: 5KB end note Service --> Controller: DashboardResponse\n(200 OK) deactivate Service Controller --> : 200 OK\nDashboard Data (JSON) deactivate Controller note over Controller, DB **Cache MISS 시나리오 성능** - 응답 시간: 약 3초 - Analytics DB 조회: 0.1초 - 외부 API 병렬 호출: 2초 (병렬 처리) - ROI 계산: 0.05초 - Redis 캐싱: 0.01초 - 직렬화/HTTP: 0.84초 end note @enduml