mirror of
https://github.com/ktds-dg0501/kt-event-marketing.git
synced 2025-12-06 22:06:23 +00:00
주요 변경사항: - event-이미지생성요청.puml: Kafka 제거, ContentService 내부 Job 관리로 변경 - event-이미지결과조회.puml: ContentService 패턴으로 업데이트 - event-AI추천요청.puml: Gateway 패턴 추가, 한글화 아키텍처 구분: - AI 추천: Kafka 사용 (ai-job-topic) - 이미지 생성: 내부 Job 관리 (Kafka 사용 안 함) 모든 파일: - Gateway 패턴 적용 - 레이어 아키텍처 (<<API Layer>>, <<Business Layer>>) - 한글 요청/응답 - Redis 키 패턴 표준화 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
127 lines
3.8 KiB
Plaintext
127 lines
3.8 KiB
Plaintext
@startuml event-AI추천요청
|
|
!theme mono
|
|
|
|
title Event Service - AI 추천 요청 (Kafka Job 발행) (UFR-EVENT-030)
|
|
|
|
actor Client
|
|
participant "API Gateway" as Gateway
|
|
participant "EventController" as Controller <<API Layer>>
|
|
participant "EventService" as Service <<Business Layer>>
|
|
participant "JobService" as JobSvc <<Business Layer>>
|
|
participant "EventRepository" as Repo <<Data Layer>>
|
|
participant "Redis Cache" as Cache <<E>>
|
|
database "Event DB" as DB <<E>>
|
|
participant "Kafka Producer" as Kafka <<E>>
|
|
|
|
note over Controller, Kafka
|
|
**UFR-EVENT-030: AI 이벤트 추천 요청**
|
|
- Kafka 비동기 Job 발행
|
|
- AI Service가 Kafka 구독하여 처리
|
|
- 트렌드 분석 + 3가지 추천안 생성
|
|
- 처리 시간: 평균 2분 이내
|
|
end note
|
|
|
|
Client -> Gateway: POST /api/events/{eventDraftId}/ai-recommendations\n{"objective": "신규 고객 유치",\n"industry": "음식점",\n"region": "서울 강남구"}
|
|
activate Gateway
|
|
|
|
Gateway -> Controller: POST /api/events/{eventDraftId}/ai-recommendations
|
|
activate Controller
|
|
|
|
Controller -> Controller: 요청 검증\n(필수 필드, 목적 유효성)
|
|
|
|
Controller -> Service: requestAIRecommendation(eventDraftId, userId)
|
|
activate Service
|
|
|
|
== 1단계: 이벤트 초안 조회 및 검증 ==
|
|
|
|
Service -> Repo: findById(eventDraftId)
|
|
activate Repo
|
|
Repo -> DB: 이벤트 초안 조회\n(초안ID로 이벤트 목적,\n매장 정보 조회)
|
|
activate DB
|
|
DB --> Repo: EventDraft 엔티티\n{목적, 매장명, 업종, 주소}
|
|
deactivate DB
|
|
Repo --> Service: EventDraft entity
|
|
deactivate Repo
|
|
|
|
Service -> Service: 소유권 검증\nvalidateOwnership(userId, eventDraft)
|
|
|
|
alt 소유권 없음
|
|
Service --> Controller: throw ForbiddenException\n("권한이 없습니다")
|
|
Controller --> Gateway: 403 Forbidden\n{"code": "EVENT_003",\n"message": "권한이 없습니다"}
|
|
deactivate Service
|
|
deactivate Controller
|
|
Gateway --> Client: 403 Forbidden
|
|
deactivate Gateway
|
|
|
|
else 소유권 확인
|
|
|
|
== 2단계: Kafka Job 생성 ==
|
|
|
|
Service -> JobSvc: createAIJob(eventDraft)
|
|
activate JobSvc
|
|
|
|
JobSvc -> JobSvc: Job ID 생성 (UUID)
|
|
|
|
JobSvc -> Cache: Job 상태 저장\nKey: job:{jobId}\nValue: {status: PENDING,\neventDraftId, type: AI_RECOMMEND,\ncreatedAt}\nTTL: 1시간
|
|
activate Cache
|
|
Cache --> JobSvc: 저장 완료
|
|
deactivate Cache
|
|
|
|
== 3단계: Kafka 이벤트 발행 ==
|
|
|
|
JobSvc -> Kafka: 이벤트 발행\nTopic: ai-job-topic\nPayload: {jobId, eventDraftId,\nobjective, industry,\nregion, storeInfo}
|
|
activate Kafka
|
|
note right of Kafka
|
|
**Kafka Topic**
|
|
- Topic: ai-job-topic
|
|
- Consumer: AI Service
|
|
- Consumer Group: ai-service-group
|
|
|
|
**Payload**
|
|
{
|
|
"jobId": "UUID",
|
|
"eventDraftId": "UUID",
|
|
"objective": "신규 고객 유치",
|
|
"industry": "음식점",
|
|
"region": "서울 강남구",
|
|
"storeInfo": {...}
|
|
}
|
|
end note
|
|
Kafka --> JobSvc: ACK (발행 확인)
|
|
deactivate Kafka
|
|
|
|
JobSvc --> Service: JobResponse\n{jobId, status: PENDING}
|
|
deactivate JobSvc
|
|
|
|
== 4단계: 응답 반환 ==
|
|
|
|
Service --> Controller: JobResponse\n{jobId, status: PENDING}
|
|
deactivate Service
|
|
|
|
Controller --> Gateway: 202 Accepted\n{"jobId": "job-uuid-123",\n"status": "PENDING",\n"message": "AI가 분석 중입니다"}
|
|
deactivate Controller
|
|
|
|
Gateway --> Client: 202 Accepted\nAI 분석 시작
|
|
deactivate Gateway
|
|
|
|
note over Service, Kafka
|
|
**AI Service 비동기 처리**
|
|
- Kafka 구독: ai-job-topic
|
|
- 트렌드 분석 (업종, 지역 기반)
|
|
- 3가지 추천안 생성 (저/중/고 비용)
|
|
- 결과: Redis에 저장 (TTL: 24시간)
|
|
- 상세: ai-트렌드분석및추천.puml 참조
|
|
|
|
**처리 시간**
|
|
- 평균: 2분 이내
|
|
- P95: 4분 이내
|
|
- Timeout: 5분
|
|
|
|
**결과 조회**
|
|
- 폴링 방식: GET /api/jobs/{jobId}/status
|
|
- 간격: 2초, 최대 30초
|
|
end note
|
|
end
|
|
|
|
@enduml
|