@startuml distribution-배포상태조회 !theme mono title Distribution Service - 배포 상태 조회 (UFR-DIST-020) actor "소상공인" as User participant "Frontend" as FE participant "API Gateway" as Gateway participant "Distribution\nREST API" as API participant "Distribution\nController" as Controller participant "Distribution\nService" as Service participant "Redis Cache" as Cache database "Event DB" as DB participant "Circuit Breaker\nManager" as CB == 배포 상태 조회 요청 == User -> FE: 이벤트 상세 화면\n배포 상태 섹션 확인 activate FE FE -> Gateway: GET /api/distribution/{eventId}/status activate Gateway Gateway -> Gateway: JWT 토큰 검증 Gateway -> API: GET /distribution/{eventId}/status activate API API -> Controller: getDistributionStatus(eventId) activate Controller Controller -> Service: fetchDistributionStatus(eventId) activate Service == Cache-Aside 패턴 적용 == Service -> Cache: 캐시 조회\nkey: distribution:{eventId} activate Cache alt 캐시 HIT Cache --> Service: 캐시된 배포 상태\n{status, results[], cachedAt} deactivate Cache note over Service: 캐시 TTL: 1시간\n빠른 응답 (0.1초) Service --> Controller: DistributionStatus\n{eventId, status, channelResults[]} deactivate Service else 캐시 MISS Cache --> Service: null (캐시 없음) deactivate Cache == 데이터베이스에서 배포 이력 조회 == Service -> DB: SELECT * FROM distribution_logs\nWHERE event_id = :eventId\nORDER BY created_at DESC\nLIMIT 1 activate DB alt 배포 이력 존재 DB --> Service: DistributionLog\n{id, eventId, status, createdAt, completedAt} deactivate DB Service -> DB: SELECT * FROM distribution_channel_logs\nWHERE distribution_log_id = :logId activate DB DB --> Service: List\n{channel, status, distributionId, postUrl, retries, error} deactivate DB == 실시간 채널 상태 확인 (선택적) == note over Service: 진행중(IN_PROGRESS) 상태일 때만\n외부 API로 실시간 상태 확인 alt 배포 진행중 (IN_PROGRESS) loop 각 채널별 상태 확인 Service -> CB: checkCircuitBreaker(channel) alt Circuit Breaker CLOSED CB --> Service: 요청 허용 alt 우리동네TV Service -> DB: SELECT distribution_id FROM distribution_channel_logs\nWHERE channel = 'WooridongneTV' DB --> Service: distributionId note over Service: Timeout: 5초\nCircuit Breaker 적용 Service -> "외부 APIs": GET /api/status/{distributionId} activate "외부 APIs" alt 성공 "외부 APIs" --> Service: 200 OK\n{status: COMPLETED, views: 1500} deactivate "외부 APIs" Service -> DB: UPDATE distribution_channel_logs\nSET status = 'COMPLETED', views = 1500 else 실패 (Timeout/Error) "외부 APIs" --> Service: 500 Error or Timeout deactivate "외부 APIs" Service -> CB: recordFailure(channel) note over Service: Circuit Breaker 실패율 증가\n50% 초과 시 Circuit Open end end note over Service: 다른 채널(링고비즈, 지니TV, SNS)도\n동일한 패턴으로 상태 확인 else Circuit Breaker OPEN CB --> Service: 서킷 오픈 상태\n(외부 API 호출 스킵) note over Service: Fallback: DB 저장 상태 사용\n30초 후 Half-Open 전환 end end == 배포 완료 여부 판단 == Service -> Service: 모든 채널 상태 확인\n완료/실패 여부 판단 alt 모든 채널 완료 Service -> DB: UPDATE distribution_logs\nSET status = 'COMPLETED', completed_at = NOW() else 일부 실패 Service -> DB: UPDATE distribution_logs\nSET status = 'PARTIAL_FAILURE' end end == 배포 상태 응답 준비 == Service -> Service: 채널별 상태 집계\n{channel, status, distributionId, postUrl, views, error} Service -> Cache: 배포 상태 캐싱\nkey: distribution:{eventId}\nvalue: {status, results[]}\nTTL: 1시간 Service --> Controller: DistributionStatus\n{eventId, status, channelResults[]} deactivate Service else 배포 이력 없음 DB --> Service: null deactivate DB Service --> Controller: DistributionStatus\n{eventId, status: NOT_FOUND} deactivate Service end end == 응답 반환 == Controller --> API: DistributionStatusResponse\n{eventId, status, channelResults[]} deactivate Controller API --> Gateway: 200 OK\n{eventId, overallStatus, channels[]} deactivate API Gateway --> FE: 배포 상태 응답\n{overallStatus, channels[]} deactivate Gateway == 프론트엔드 화면 표시 == FE -> FE: 채널별 상태 표시\n- 대기중: 회색\n- 진행중: 파란색\n- 완료: 초록색\n- 실패: 빨간색 FE --> User: 배포 상태 시각화\n채널별 세부 정보 표시 deactivate FE note over User: 배포 상태 정보\n- 우리동네TV: 완료 (배포ID, 조회수)\n- 링고비즈: 완료 (업데이트 시각)\n- 지니TV: 완료 (광고ID, 스케줄)\n- SNS: 완료 (포스팅 URL) == 재시도 기능 (실패한 채널) == alt 실패한 채널 존재 User -> FE: "재시도" 버튼 클릭 FE -> Gateway: POST /api/distribution/{eventId}/retry\n{channels: [failed_channel_list]} Gateway -> API: 재시도 요청 API -> Controller: retryDistribution(eventId, channels) Controller -> Service: retryFailedChannels(eventId, channels) activate Service note over Service: 실패한 채널만\n다시 배포 시도\n(동일한 Circuit Breaker/Retry 적용) Service -> DB: 새로운 배포 시도 로그 생성 Service -> Cache: 캐시 무효화 Service --> Controller: 재시도 완료\n{retryStatus} deactivate Service Controller --> API: RetryResponse API --> Gateway: 200 OK Gateway --> FE: 재시도 결과 FE --> User: "재시도가 완료되었습니다" end == 실시간 업데이트 (선택적) == note over FE: Frontend는 5초마다\nPolling 또는 WebSocket으로\n배포 상태 자동 갱신\n(Phase 2에서 WebSocket 적용 가능) @enduml