@startuml 이벤트생성플로우
!theme mono

title 이벤트 생성 플로우 - 외부 시퀀스 다이어그램

actor "소상공인" as User
participant "Frontend" as FE
participant "API Gateway" as Gateway
participant "Event Service" as Event
participant "User Service" as UserSvc
participant "AI Service" as AI
participant "Content Service" as Content
participant "Distribution Service" as Dist
participant "Kafka" as Kafka
database "Event DB" as EventDB
database "User DB" as UserDB
database "Redis" as Redis
participant "외부 AI API" as AIApi
participant "이미지 생성 API" as ImageApi
participant "배포 채널 APIs" as ChannelApis

== 1. 이벤트 목적 선택 (UFR-EVENT-020) ==
User -> FE: 이벤트 목적 선택
FE -> Gateway: GET /api/users/{userId}/store\n회원 및 매장정보 조회
activate Gateway
Gateway -> UserSvc: GET /api/users/{userId}/store\n회원 및 매장정보 조회
activate UserSvc
UserSvc -> UserDB: 사용자 및 매장 정보 조회
activate UserDB
UserDB --> UserSvc: 사용자, 매장 정보 반환
deactivate UserDB
UserSvc --> Gateway: 200 OK\n{userId, storeName, industry, address}
deactivate UserSvc
Gateway --> FE: 200 OK\n{userId, storeName, industry, address}
deactivate Gateway
FE -> Gateway: POST /events/purposes\n{목적, userId, storeName, industry, address}
Gateway -> Event: 이벤트 목적 저장 요청
Event -> Redis: 이벤트 목적 정보 저장\nKey: draft:event:{eventDraftId}\n(목적, 매장정보 저장)\nTTL: 24시간
activate Redis
Redis --> Event: 저장 완료
deactivate Redis
Event --> Gateway: 저장 완료\n{eventDraftId}
Gateway --> FE: 200 OK
FE --> User: AI 추천 화면으로 이동

== 2. AI 이벤트 추천 - 비동기 처리 (UFR-EVENT-030) ==
User -> FE: AI 추천 요청
FE -> Gateway: POST /api/events/{eventDraftId}/ai-recommendations\n{목적, 업종, 지역}
Gateway -> Event: AI 추천 요청 전달
Event -> Kafka: Publish to ai-job-topic\n{jobId, eventDraftId, 목적, 업종, 지역}
Event --> Gateway: Job 생성 완료\n{jobId, status: PENDING}
Gateway --> FE: 202 Accepted\n{jobId}
FE --> User: "AI가 분석 중입니다..." (로딩)

note over AI: Kafka Consumer\nai 이벤트 생성 topic 구독
Kafka --> AI: Consume Job Message\n{jobId, eventDraftId, ...}

AI -> AIApi: 트렌드 분석 및 이벤트 추천 요청\n{목적, 업종, 지역, 매장정보}\n[Circuit Breaker, Timeout: 5분]
AIApi --> AI: 3가지 추천안 + 트렌드 요약\n(예: "여름철 시원한 음료 선호도 증가")
AI -> Redis: AI 추천 결과 저장\nKey: ai:event:{eventDraftId}\n(3가지 추천안, 트렌드 요약)\nTTL: 24시간
Redis --> AI: 저장 완료
AI -> Redis: Job 상태 업데이트\n(상태를 COMPLETED로 변경)
note over AI, Redis: AI 추천 정보는 Redis에 저장\n- Content Service가 읽기 위함\n- 최종 승인 시 Event DB에 영구 저장

group Polling으로 상태 확인
    loop 상태 확인 (최대 30초)
        FE -> Gateway: GET /jobs/{jobId}/status
        Gateway -> Event: Job 상태 조회
        Event -> Redis: Job 상태 조회\n(jobId로 상태 및 결과 조회)
        Redis --> Event: {status, result}

        alt Job 완료
            Event --> Gateway: 200 OK\n{status: COMPLETED, recommendations, trendSummary}
            Gateway --> FE: 추천 결과 및 트렌드 요약 반환
            FE --> User: 트렌드 요약 표시\n3가지 추천안 표시\n(제목/경품 수정 가능)
        else Job 진행중
            Event --> Gateway: 200 OK\n{status: PENDING/PROCESSING}
            Gateway --> FE: 진행중 상태
            note over FE: 2초 후 재요청
        end
    end
end

User -> FE: 추천안 선택\n(제목/경품 커스텀)
FE -> Gateway: PUT /events/drafts/{eventDraftId}\n{선택한 추천안, 커스텀 정보}
Gateway -> Event: 선택 저장
Event -> Redis: 선택한 추천안 저장\nKey: draft:event:{eventDraftId}\n(이벤트 초안 업데이트)\nTTL: 24시간
activate Redis
Redis --> Event: 업데이트 완료
deactivate Redis
Event --> Gateway: 200 OK
Gateway --> FE: 저장 완료
FE --> User: 콘텐츠 생성 화면으로 이동

== 3. SNS 이미지 생성 - 비동기 처리 (UFR-CONT-010) ==
User -> FE: 이미지 생성 요청
FE -> Gateway: POST /api/content/images/{eventDraftId}/generate
Gateway -> Content: 이미지 생성 요청
Content -> Content: Job 생성\n{jobId, eventDraftId, status: PENDING}
Content --> Gateway: Job 생성 완료\n{jobId, status: PENDING}
Gateway --> FE: 202 Accepted\n{jobId}
FE --> User: "이미지 생성 중..." (로딩)

note over Content: 백그라운드 워커\nRedis 폴링 또는 스케줄러

Content -> Redis: AI 이벤트 데이터 읽기\nKey: ai:event:{eventDraftId}
activate Redis
Redis --> Content: AI 추천 결과\n{선택된 추천안, 이벤트 정보}
deactivate Redis

note over Content: inner sequence 참조:\ncontent-이미지생성.puml

par 심플 스타일
    Content -> ImageApi: 심플 스타일 생성 요청\n[Circuit Breaker, Timeout: 5분]
    ImageApi --> Content: 심플 이미지 URL
else 화려한 스타일
    Content -> ImageApi: 화려한 스타일 생성 요청\n[Circuit Breaker, Timeout: 5분]
    ImageApi --> Content: 화려한 이미지 URL
else 트렌디 스타일
    Content -> ImageApi: 트렌디 스타일 생성 요청\n[Circuit Breaker, Timeout: 5분]
    ImageApi --> Content: 트렌디 이미지 URL
end

Content -> Redis: 이미지 URL 저장\nKey: content:image:{eventDraftId}\n{심플, 화려, 트렌디 URL}\nTTL: 7일
activate Redis
Redis --> Content: 저장 완료
deactivate Redis
Content -> Redis: Job 상태 업데이트\n(상태를 COMPLETED로 변경)
note over Content, Redis: 이미지 URL은 Redis에 저장\n- 최종 승인 시 Event DB에 영구 저장

group Polling으로 상태 확인
    loop 상태 확인 (최대 30초)
        FE -> Gateway: GET /api/content/jobs/{jobId}/status
        Gateway -> Content: Job 상태 조회
        Content -> Redis: Job 상태 조회\n(jobId로 상태 및 이미지 URL 조회)
        Redis --> Content: {status, imageUrls}

        alt Job 완료
            Content --> Gateway: 200 OK\n{status: COMPLETED, imageUrls}
            Gateway --> FE: 이미지 URL 반환
            FE --> User: 3가지 스타일 카드 표시
        else Job 진행중
            Content --> Gateway: 200 OK\n{status: PENDING/PROCESSING}
            Gateway --> FE: 진행중 상태
            note over FE: 2초 후 재요청
        end
    end
end

User -> FE: 스타일 선택 및 편집
FE -> Gateway: PUT /events/drafts/{eventDraftId}/content\n{선택한 이미지, 편집내용}
Gateway -> Event: 콘텐츠 선택 저장
Event -> Redis: 선택한 콘텐츠 저장\nKey: draft:event:{eventDraftId}\n(이벤트 초안 업데이트)\nTTL: 24시간
activate Redis
Redis --> Event: 업데이트 완료
deactivate Redis
Event --> Gateway: 200 OK
Gateway --> FE: 저장 완료
FE --> User: 배포 채널 선택 화면으로 이동

== 4. 최종 승인 및 다중 채널 배포 - 동기 처리 (UFR-EVENT-050) ==
User -> FE: 배포 채널 선택\n최종 승인 요청
FE -> Gateway: POST /api/events/{eventDraftId}/publish\n{선택 채널 목록}
Gateway -> Event: 최종 승인 및 배포 처리

note over Event: Redis 데이터를 Event DB에 영구 저장

Event -> Redis: 이벤트 초안 조회\nKey: draft:event:{eventDraftId}
activate Redis
Redis --> Event: 이벤트 초안 데이터\n(목적, 매장정보, 추천안, 콘텐츠)
deactivate Redis

Event -> Redis: AI 추천 결과 조회\nKey: ai:event:{eventDraftId}
activate Redis
Redis --> Event: AI 추천 결과
deactivate Redis

Event -> Redis: 이미지 URL 조회\nKey: content:image:{eventDraftId}
activate Redis
Redis --> Event: 이미지 URL 목록
deactivate Redis

Event -> EventDB: 이벤트 정보 영구 저장\n(목적, 매장정보, AI 추천, 이미지 URL, 배포 채널 포함)
EventDB --> Event: 저장 완료

Event -> EventDB: 이벤트 상태 변경\n(DRAFT → APPROVED로 업데이트)
EventDB --> Event: 상태 변경 완료
Event -> Kafka: Publish to event-topic\nEventCreated\n{eventId, 이벤트정보}

note over Event: 동기 호출로 배포 진행\ninner sequence 참조:\ndistribution-다중채널배포.puml
Event -> Dist: REST API - 배포 요청\nPOST /api/distribution/distribute\n{eventId, channels[], contentUrls}

note over Dist: Sprint 2: Mock 처리\n- 외부 API 호출 없음\n- 모든 배포 즉시 성공 처리\n- 배포 로그만 DB 기록

Dist -> EventDB: 배포 이력 초기화\n(이벤트ID, 상태: PENDING)
EventDB --> Dist: 배포 이력 ID
Dist -> EventDB: 배포 이력 상태 업데이트\n(상태: IN_PROGRESS)

note over Dist: 다중 채널 Mock 배포\n(내부 처리 상세는 inner sequence 참조)

par 우리동네TV
    alt 우리동네TV 선택
        Dist -> Dist: Mock 처리\n(즉시 성공)
        Dist -> EventDB: 채널 로그 저장\n(우리동네TV, 성공,\n배포ID, 예상노출수)
    end
else 링고비즈
    alt 링고비즈 선택
        Dist -> Dist: Mock 처리\n(즉시 성공)
        Dist -> EventDB: 채널 로그 저장\n(링고비즈, 성공,\n업데이트 시각)
    end
else 지니TV
    alt 지니TV 선택
        Dist -> Dist: Mock 처리\n(즉시 성공)
        Dist -> EventDB: 채널 로그 저장\n(지니TV, 성공,\n광고ID, 스케줄)
    end
else Instagram
    alt Instagram 선택
        Dist -> Dist: Mock 처리\n(즉시 성공)
        Dist -> EventDB: 채널 로그 저장\n(Instagram, 성공,\npostUrl, postId)
    end
else Naver Blog
    alt Naver Blog 선택
        Dist -> Dist: Mock 처리\n(즉시 성공)
        Dist -> EventDB: 채널 로그 저장\n(NaverBlog, 성공,\npostUrl)
    end
else Kakao Channel
    alt Kakao Channel 선택
        Dist -> Dist: Mock 처리\n(즉시 성공)
        Dist -> EventDB: 채널 로그 저장\n(KakaoChannel, 성공,\nmessageId)
    end
end

note over Dist: 모든 채널 배포 완료 (즉시 처리)

Dist -> EventDB: 배포 이력 상태 업데이트\n(상태: COMPLETED, 완료일시)

Dist -> Kafka: Publish to event-topic\nDistributionCompleted\n{eventId, channels[], results[], completedAt}

Dist --> Event: REST API 동기 응답\n200 OK\n{distributionId, status: COMPLETED, results[]}

Event -> EventDB: 이벤트 상태 업데이트\n(APPROVED → ACTIVE로 변경)
EventDB --> Event: 업데이트 완료

Event --> Gateway: 200 OK\n{eventId, 배포결과}
Gateway --> FE: 배포 완료
FE --> User: "이벤트가 배포되었습니다"\n대시보드로 이동

note over Event, Dist: Sprint 2 제약사항\n- 외부 API 호출 없음 (Mock)\n- 모든 배포 즉시 성공 처리\n- Circuit Breaker 미구현\n- Retry 로직 미구현\n\nSprint 3 이후 구현 예정\n- 실제 외부 채널 API 연동\n- Circuit Breaker 패턴\n- Retry 및 실패 처리

@enduml
