@startuml event-추천결과조회 !theme mono title Event Service - AI 추천 결과 폴링 조회 actor Client participant "API Gateway" as Gateway participant "EventController" as Controller <> participant "EventService" as Service <> participant "JobManager" as JobMgr <> participant "Redis Cache" as Cache <> note over Controller, Cache **폴링 방식 Job 상태 조회** - 최대 30초 동안 폴링 (2초 간격) - Job 상태: PENDING → PROCESSING → COMPLETED - AI 추천 결과: Redis에 저장 (TTL: 24시간) end note Client -> Gateway: GET /api/events/jobs/{jobId}/status activate Gateway Gateway -> Controller: GET /api/events/jobs/{jobId}/status activate Controller Controller -> Service: getJobStatus(jobId) activate Service Service -> JobMgr: getJobStatus(jobId) activate JobMgr JobMgr -> Cache: Job 상태 조회\nKey: job:{jobId} activate Cache alt Job 데이터 존재 Cache --> JobMgr: Job 데이터\n{status, eventDraftId,\ntype, createdAt} deactivate Cache alt status = COMPLETED JobMgr -> Cache: AI 추천 결과 조회\nKey: ai:recommendation:{eventDraftId} activate Cache Cache --> JobMgr: AI 추천 결과\n{트렌드분석, 3가지추천안} deactivate Cache JobMgr --> Service: JobStatusResponse\n{jobId, status: COMPLETED,\nrecommendations: {...}} deactivate JobMgr Service --> Controller: JobStatusResponse\n{status: COMPLETED, recommendations} deactivate Service Controller --> Gateway: 200 OK\n{"status": "COMPLETED",\n"recommendations": [\n {"title": "저비용 추천안",\n "prize": "커피쿠폰",\n "method": "QR코드 스캔",\n "cost": "50만원",\n "roi": "150%"},\n {"title": "중비용 추천안",\n "prize": "상품권",\n "method": "SNS 공유",\n "cost": "100만원",\n "roi": "200%"},\n {"title": "고비용 추천안",\n "prize": "경품 추첨",\n "method": "설문 참여",\n "cost": "200만원",\n "roi": "300%"}\n]} deactivate Controller Gateway --> Client: 200 OK\nAI 추천 결과 반환 deactivate Gateway note right of Client **프론트엔드 처리** - 3가지 추천안 카드 표시 - 사용자가 추천안 선택 - 트렌드 분석 정보 표시 end note else status = PROCESSING 또는 PENDING JobMgr --> Service: JobStatusResponse\n{jobId, status: PROCESSING} deactivate JobMgr Service --> Controller: JobStatusResponse\n{status: PROCESSING} deactivate Service Controller --> Gateway: 200 OK\n{"status": "PROCESSING",\n"message": "AI가 분석 중입니다"} deactivate Controller Gateway --> Client: 200 OK\n진행 중 상태 deactivate Gateway note right of Client **폴링 재시도** - 2초 후 재요청 - 최대 30초 (15회) end note else status = FAILED JobMgr -> Cache: 에러 정보 조회\nKey: job:{jobId}:error activate Cache Cache --> JobMgr: 에러 메시지 deactivate Cache JobMgr --> Service: JobStatusResponse\n{jobId, status: FAILED, error} deactivate JobMgr Service --> Controller: JobStatusResponse\n{status: FAILED, error} deactivate Service Controller --> Gateway: 200 OK\n{"status": "FAILED",\n"error": "AI 분석 실패",\n"message": "다시 시도해주세요"} deactivate Controller Gateway --> Client: 200 OK\n실패 상태 deactivate Gateway note right of Client **실패 처리** - 에러 메시지 표시 - "다시 분석" 버튼 제공 end note end else Job 데이터 없음 Cache --> JobMgr: null (캐시 미스) deactivate Cache JobMgr --> Service: throw NotFoundException\n("Job을 찾을 수 없습니다") deactivate JobMgr Service --> Controller: NotFoundException deactivate Service Controller --> Gateway: 404 Not Found\n{"code": "JOB_001",\n"message": "Job을 찾을 수 없습니다"} deactivate Controller Gateway --> Client: 404 Not Found deactivate Gateway end note over Controller, Cache **폴링 전략** - 간격: 2초 - 최대 시간: 30초 (15회) - Timeout 시: 사용자에게 알림 + "다시 분석" 옵션 **Redis 캐시** - Job 상태: TTL 1시간 - AI 추천 결과: TTL 24시간 **성능 목표** - 평균 AI 분석 시간: 2분 이내 - P95 AI 분석 시간: 4분 이내 end note @enduml