@startuml content-이미지생성
!theme mono

title Content Service - 이미지 생성 내부 시퀀스 (UFR-CONT-010)

actor Client
participant "Kafka\nimage-job\nConsumer" as Consumer
participant "JobHandler" as Handler
participant "CacheManager" as Cache
participant "ImageGenerator" as Generator
participant "ImageStyleFactory" as Factory
participant "StableDiffusion\nAPI Client" as SDClient
participant "DALL-E\nAPI Client" as DALLEClient
participant "Circuit Breaker" as CB
participant "BlobStorage\nUploader" as BlobStorage
participant "JobStatusManager" as JobStatus
database "Redis Cache" as Redis

note over Consumer: Kafka 구독\nimage-job 토픽

== Kafka Job 수신 ==
Consumer -> Handler: Job Message 수신\n{jobId, eventDraftId, eventInfo}
activate Handler

Handler -> Cache: 캐시 조회\nkey: content:image:{eventDraftId}
activate Cache
Cache -> Redis: GET content:image:{eventDraftId}
Redis --> Cache: 캐시 데이터 또는 NULL
Cache --> Handler: 캐시 결과
deactivate Cache

alt 캐시 HIT (기존 이미지 존재)
    Handler -> JobStatus: Job 상태 업데이트\nstatus: COMPLETED (캐시)
    activate JobStatus
    JobStatus -> Redis: SET job:{jobId}\n{status: COMPLETED, imageUrls: [...]}
    JobStatus --> Handler: 업데이트 완료
    deactivate JobStatus
    Handler --> Consumer: 처리 완료 (캐시)
else 캐시 MISS (새로운 이미지 생성)
    Handler -> JobStatus: Job 상태 업데이트\nstatus: PROCESSING
    activate JobStatus
    JobStatus -> Redis: SET job:{jobId}\n{status: PROCESSING}
    JobStatus --> Handler: 업데이트 완료
    deactivate JobStatus

    Handler -> Generator: 3가지 스타일 이미지 생성 요청\n{eventInfo}
    activate Generator

    == 3가지 스타일 병렬 생성 (par 블록) ==
    group parallel
        Generator -> Factory: 심플 프롬프트 생성\n{eventInfo, style: SIMPLE}
        activate Factory
        Factory --> Generator: 심플 프롬프트
        deactivate Factory

        Generator -> CB: Circuit Breaker 체크
        activate CB
        CB --> Generator: State: CLOSED (정상)
        deactivate CB

        Generator -> SDClient: Stable Diffusion API 호출\n{prompt, style: SIMPLE}\nTimeout: 20초
        activate SDClient

        note over SDClient: Circuit Breaker 적용\nRetry: 최대 3회\nTimeout: 20초

        alt API 성공
            SDClient --> Generator: 심플 이미지 데이터
            deactivate SDClient
            Generator -> BlobStorage: Blob 업로드 요청\n{imageData, eventId, style: SIMPLE}\nRetry: 3회, Timeout: 30초
            activate BlobStorage
            note right of BlobStorage: SAS Token 생성\n(유효기간 7일)
            BlobStorage --> Generator: Blob SAS URL (심플)
            deactivate BlobStorage
        else API 실패 (Timeout/Error)
            SDClient --> Generator: 실패 응답
            deactivate SDClient
            Generator -> CB: 실패 기록
            activate CB
            CB -> CB: 실패율 계산
            alt 실패율 > 50%
                CB -> CB: Circuit State: OPEN
            end
            CB --> Generator: Circuit State
            deactivate CB

            Generator -> DALLEClient: Fallback - DALL-E API 호출\n{prompt, style: SIMPLE}\nTimeout: 20초
            activate DALLEClient
            alt Fallback 성공
                DALLEClient --> Generator: 심플 이미지 데이터
                deactivate DALLEClient
                Generator -> BlobStorage: Blob 업로드 요청\n{imageData, eventId, style: SIMPLE}\nRetry: 3회, Timeout: 30초
                activate BlobStorage
                note right of BlobStorage: SAS Token 생성\n(유효기간 7일)
                BlobStorage --> Generator: Blob SAS URL (심플)
                deactivate BlobStorage
            else Fallback 실패
                DALLEClient --> Generator: 실패 응답
                deactivate DALLEClient
                Generator -> Generator: 기본 템플릿 사용\n(심플)
            end
        end

        Generator -> Factory: 화려한 프롬프트 생성\n{eventInfo, style: FANCY}
        activate Factory
        Factory --> Generator: 화려한 프롬프트
        deactivate Factory

        Generator -> CB: Circuit Breaker 체크
        activate CB
        CB --> Generator: State: CLOSED/OPEN
        deactivate CB

        alt Circuit CLOSED
            Generator -> SDClient: Stable Diffusion API 호출\n{prompt, style: FANCY}\nTimeout: 20초
            activate SDClient

            alt API 성공
                SDClient --> Generator: 화려한 이미지 데이터
                deactivate SDClient
                Generator -> BlobStorage: Blob 업로드 요청\n{imageData, eventId, style: FANCY}\nRetry: 3회, Timeout: 30초
                activate BlobStorage
                note right of BlobStorage: SAS Token 생성\n(유효기간 7일)
                BlobStorage --> Generator: Blob SAS URL (화려한)
                deactivate BlobStorage
            else API 실패
                SDClient --> Generator: 실패 응답
                deactivate SDClient
                Generator -> DALLEClient: Fallback - DALL-E API 호출
                activate DALLEClient
                alt Fallback 성공
                    DALLEClient --> Generator: 화려한 이미지 데이터
                    deactivate DALLEClient
                    Generator -> BlobStorage: Blob 업로드\n{imageData, eventId, style: FANCY}\nRetry: 3회, Timeout: 30초
                    activate BlobStorage
                    note right of BlobStorage: SAS Token 생성\n(유효기간 7일)
                    BlobStorage --> Generator: Blob SAS URL (화려한)
                    deactivate BlobStorage
                else Fallback 실패
                    DALLEClient --> Generator: 실패 응답
                    deactivate DALLEClient
                    Generator -> Generator: 기본 템플릿 사용\n(화려한)
                end
            end
        else Circuit OPEN
            Generator -> Generator: Circuit Open\n즉시 기본 템플릿 사용
        end

        Generator -> Factory: 트렌디 프롬프트 생성\n{eventInfo, style: TRENDY}
        activate Factory
        Factory --> Generator: 트렌디 프롬프트
        deactivate Factory

        Generator -> CB: Circuit Breaker 체크
        activate CB
        CB --> Generator: State: CLOSED/OPEN
        deactivate CB

        alt Circuit CLOSED
            Generator -> SDClient: Stable Diffusion API 호출\n{prompt, style: TRENDY}\nTimeout: 20초
            activate SDClient

            alt API 성공
                SDClient --> Generator: 트렌디 이미지 데이터
                deactivate SDClient
                Generator -> BlobStorage: Blob 업로드 요청\n{imageData, eventId, style: TRENDY}\nRetry: 3회, Timeout: 30초
                activate BlobStorage
                note right of BlobStorage: SAS Token 생성\n(유효기간 7일)
                BlobStorage --> Generator: Blob SAS URL (트렌디)
                deactivate BlobStorage
            else API 실패
                SDClient --> Generator: 실패 응답
                deactivate SDClient
                Generator -> DALLEClient: Fallback - DALL-E API 호출
                activate DALLEClient
                alt Fallback 성공
                    DALLEClient --> Generator: 트렌디 이미지 데이터
                    deactivate DALLEClient
                    Generator -> BlobStorage: Blob 업로드\n{imageData, eventId, style: TRENDY}\nRetry: 3회, Timeout: 30초
                    activate BlobStorage
                    note right of BlobStorage: SAS Token 생성\n(유효기간 7일)
                    BlobStorage --> Generator: Blob SAS URL (트렌디)
                    deactivate BlobStorage
                else Fallback 실패
                    DALLEClient --> Generator: 실패 응답
                    deactivate DALLEClient
                    Generator -> Generator: 기본 템플릿 사용\n(트렌디)
                end
            end
        else Circuit OPEN
            Generator -> Generator: Circuit Open\n즉시 기본 템플릿 사용
        end
    end

    Generator --> Handler: 3가지 이미지 URL 반환\n{simple, fancy, trendy}
    deactivate Generator

    == 결과 캐싱 및 Job 완료 ==
    Handler -> Cache: Blob SAS URL 캐싱\nkey: content:image:{eventDraftId}\nTTL: 7일
    activate Cache
    Cache -> Redis: SET content:image:{eventDraftId}\n{simple: SAS_URL, fancy: SAS_URL, trendy: SAS_URL}\nTTL: 604800 (7일)
    Redis --> Cache: 저장 완료
    Cache --> Handler: 캐싱 완료
    deactivate Cache

    Handler -> JobStatus: Job 상태 업데이트\nstatus: COMPLETED
    activate JobStatus
    JobStatus -> Redis: SET job:{jobId}\n{status: COMPLETED, imageUrls: [...]}
    JobStatus --> Handler: 업데이트 완료
    deactivate JobStatus

    Handler --> Consumer: 처리 완료
    note over Handler
        Blob SAS URL은 Redis에만 저장됨
        Event Service는 폴링을 통해
        Redis에서 결과 조회
        SAS Token 유효기간: 7일
    end note
end

deactivate Handler

note over Consumer, Redis
**Resilience 패턴 적용**
- Circuit Breaker: 실패율 50% 초과 시 Open (AI API용)
- AI API Timeout: 20초
- Fallback: Stable Diffusion 실패 시 DALL-E, 모두 실패 시 기본 템플릿
- Blob Storage Retry: 최대 3회 (Exponential Backoff: 1s, 2s, 4s)
- Blob Storage Timeout: 30초 (대용량 이미지 고려)
- Cache-Aside: Redis 캐싱 (TTL 7일)

**처리 시간**
- 캐시 HIT: 0.1초
- 캐시 MISS: 5.2초 이내 (병렬 처리)
  └─ AI 생성: 3-5초 + Blob 업로드: 0.15-0.3초

**병렬 처리**
- 3가지 스타일 동시 생성 (par 블록)
- 독립적인 스레드 풀 사용

**Blob Storage 업로드**
- Azure Blob Storage (Korea Central)
- SAS Token 기반 접근 제어 (읽기 전용)
- SAS Token 유효기간: 7일 (Redis TTL과 동기화)
- Public Access 비활성화 (보안 강화)
- Container: event-images
- URL 형식: https://{account}.blob.core.windows.net/event-images/{id}-{style}.png?{sas_token}

**보안**
- Storage Account Public Access 비활성화
- SAS Token 기반 URL 생성 (읽기 전용 권한)
- Firewall 규칙: K8s Cluster IP만 허용
- HTTPS 강제 (TLS 1.2 이상)
end note

@enduml
