mirror of
https://github.com/ktds-dg0501/kt-event-marketing.git
synced 2025-12-06 13:26:23 +00:00
549 lines
18 KiB
YAML
549 lines
18 KiB
YAML
openapi: 3.0.3
|
|
info:
|
|
title: Content Service API
|
|
description: |
|
|
KT AI 기반 소상공인 이벤트 자동 생성 서비스 - Content Service API
|
|
|
|
## 주요 기능
|
|
- SNS 이미지 생성 (UFR-CONT-010)
|
|
- 3가지 스타일 이미지 자동 생성 (심플, 화려한, 트렌디)
|
|
- AI 기반 이미지 생성 (Stable Diffusion / DALL-E)
|
|
- Circuit Breaker 및 Fallback 패턴 적용
|
|
- Redis 캐싱 (TTL 7일)
|
|
|
|
## 비동기 처리 방식
|
|
- Kafka 기반 Job 처리
|
|
- 폴링 방식으로 결과 조회
|
|
- Event Service와 느슨한 결합
|
|
|
|
version: 1.0.0
|
|
contact:
|
|
name: Content Service Team
|
|
email: content-team@kt.com
|
|
|
|
servers:
|
|
- url: https://api.kt-event.com/v1
|
|
description: Production Server
|
|
- url: https://api-dev.kt-event.com/v1
|
|
description: Development Server
|
|
|
|
tags:
|
|
- name: Images
|
|
description: SNS 이미지 생성 및 조회
|
|
|
|
paths:
|
|
/api/content/images/generate:
|
|
post:
|
|
tags:
|
|
- Images
|
|
summary: SNS 이미지 생성 요청
|
|
description: |
|
|
이벤트 정보를 기반으로 3가지 스타일의 SNS 이미지 생성을 비동기로 요청합니다.
|
|
|
|
## 처리 방식
|
|
- **비동기 처리**: Kafka image-job 토픽에 Job 발행
|
|
- **폴링 조회**: jobId로 생성 상태 조회 (GET /api/content/images/{jobId})
|
|
- **캐싱**: 동일한 eventDraftId 재요청 시 캐시 반환 (TTL 7일)
|
|
|
|
## 생성 스타일
|
|
1. **심플 스타일**: 깔끔한 디자인, 텍스트 중심
|
|
2. **화려한 스타일**: 눈에 띄는 디자인, 풍부한 색상
|
|
3. **트렌디 스타일**: 최신 트렌드, MZ세대 타겟
|
|
|
|
## Resilience 패턴
|
|
- Circuit Breaker (실패율 50% 초과 시 Open)
|
|
- Fallback (Stable Diffusion → DALL-E → 기본 템플릿)
|
|
- Timeout (20초)
|
|
|
|
operationId: generateImages
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ImageGenerationRequest'
|
|
examples:
|
|
basicEvent:
|
|
summary: 기본 이벤트
|
|
value:
|
|
eventDraftId: "evt-draft-12345"
|
|
eventInfo:
|
|
title: "봄맞이 커피 할인 이벤트"
|
|
giftName: "아메리카노 1+1"
|
|
brandColor: "#FF5733"
|
|
logoUrl: "https://cdn.example.com/logo.png"
|
|
withoutLogo:
|
|
summary: 로고 없는 이벤트
|
|
value:
|
|
eventDraftId: "evt-draft-67890"
|
|
eventInfo:
|
|
title: "신메뉴 출시 기념 경품 추첨"
|
|
giftName: "스타벅스 기프티콘 5000원권"
|
|
brandColor: "#00704A"
|
|
|
|
responses:
|
|
'202':
|
|
description: |
|
|
이미지 생성 요청이 성공적으로 접수되었습니다.
|
|
jobId를 사용하여 생성 상태를 폴링 조회하세요.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ImageGenerationAcceptedResponse'
|
|
examples:
|
|
accepted:
|
|
summary: 요청 접수 성공
|
|
value:
|
|
jobId: "job-img-abc123"
|
|
eventDraftId: "evt-draft-12345"
|
|
status: "PENDING"
|
|
estimatedCompletionTime: 5
|
|
message: "이미지 생성 요청이 접수되었습니다. jobId로 결과를 조회하세요."
|
|
|
|
'400':
|
|
description: 잘못된 요청 (필수 필드 누락, 유효하지 않은 데이터)
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorResponse'
|
|
examples:
|
|
missingField:
|
|
summary: 필수 필드 누락
|
|
value:
|
|
code: "BAD_REQUEST"
|
|
message: "eventInfo.title은 필수 항목입니다."
|
|
timestamp: "2025-10-22T14:30:00Z"
|
|
invalidColor:
|
|
summary: 유효하지 않은 색상 코드
|
|
value:
|
|
code: "BAD_REQUEST"
|
|
message: "brandColor는 HEX 색상 코드 형식이어야 합니다."
|
|
timestamp: "2025-10-22T14:30:00Z"
|
|
|
|
'429':
|
|
description: 요청 제한 초과 (Rate Limiting)
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorResponse'
|
|
examples:
|
|
rateLimitExceeded:
|
|
summary: 요청 제한 초과
|
|
value:
|
|
code: "RATE_LIMIT_EXCEEDED"
|
|
message: "요청 한도를 초과했습니다. 1분 후 다시 시도하세요."
|
|
timestamp: "2025-10-22T14:30:00Z"
|
|
retryAfter: 60
|
|
|
|
'500':
|
|
description: 서버 내부 오류
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorResponse'
|
|
examples:
|
|
internalError:
|
|
summary: 서버 내부 오류
|
|
value:
|
|
code: "INTERNAL_SERVER_ERROR"
|
|
message: "이미지 생성 요청 처리 중 오류가 발생했습니다."
|
|
timestamp: "2025-10-22T14:30:00Z"
|
|
|
|
security:
|
|
- BearerAuth: []
|
|
|
|
/api/content/images/{jobId}:
|
|
get:
|
|
tags:
|
|
- Images
|
|
summary: 이미지 생성 상태 및 결과 조회
|
|
description: |
|
|
jobId로 이미지 생성 상태를 조회합니다.
|
|
|
|
## 폴링 권장사항
|
|
- **폴링 간격**: 2초
|
|
- **최대 폴링 시간**: 30초
|
|
- **Timeout 후 처리**: 에러 메시지 표시 및 재시도 옵션 제공
|
|
|
|
## 상태 종류
|
|
- **PENDING**: 대기 중 (Kafka Queue에서 대기)
|
|
- **PROCESSING**: 생성 중 (AI API 호출 진행)
|
|
- **COMPLETED**: 완료 (3가지 이미지 URL 반환)
|
|
- **FAILED**: 실패 (에러 메시지 포함)
|
|
|
|
## 캐싱
|
|
- COMPLETED 상태는 Redis 캐싱 (TTL 7일)
|
|
- 동일한 eventDraftId 재요청 시 즉시 반환
|
|
|
|
operationId: getImageGenerationStatus
|
|
parameters:
|
|
- name: jobId
|
|
in: path
|
|
required: true
|
|
description: 이미지 생성 Job ID
|
|
schema:
|
|
type: string
|
|
example: "job-img-abc123"
|
|
|
|
responses:
|
|
'200':
|
|
description: 이미지 생성 상태 조회 성공
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ImageGenerationStatusResponse'
|
|
examples:
|
|
pending:
|
|
summary: 대기 중
|
|
value:
|
|
jobId: "job-img-abc123"
|
|
status: "PENDING"
|
|
message: "이미지 생성 대기 중입니다."
|
|
estimatedCompletionTime: 5
|
|
|
|
processing:
|
|
summary: 생성 중
|
|
value:
|
|
jobId: "job-img-abc123"
|
|
status: "PROCESSING"
|
|
message: "AI가 이벤트에 어울리는 이미지를 생성하고 있어요..."
|
|
estimatedCompletionTime: 3
|
|
|
|
completed:
|
|
summary: 생성 완료
|
|
value:
|
|
jobId: "job-img-abc123"
|
|
status: "COMPLETED"
|
|
message: "이미지 생성이 완료되었습니다."
|
|
images:
|
|
- style: "SIMPLE"
|
|
url: "https://cdn.kt-event.com/images/evt-draft-12345-simple.png"
|
|
platform: "INSTAGRAM"
|
|
size:
|
|
width: 1080
|
|
height: 1080
|
|
- style: "FANCY"
|
|
url: "https://cdn.kt-event.com/images/evt-draft-12345-fancy.png"
|
|
platform: "INSTAGRAM"
|
|
size:
|
|
width: 1080
|
|
height: 1080
|
|
- style: "TRENDY"
|
|
url: "https://cdn.kt-event.com/images/evt-draft-12345-trendy.png"
|
|
platform: "INSTAGRAM"
|
|
size:
|
|
width: 1080
|
|
height: 1080
|
|
completedAt: "2025-10-22T14:30:05Z"
|
|
fromCache: false
|
|
|
|
completedFromCache:
|
|
summary: 캐시에서 반환
|
|
value:
|
|
jobId: "job-img-def456"
|
|
status: "COMPLETED"
|
|
message: "이미지 생성이 완료되었습니다. (캐시)"
|
|
images:
|
|
- style: "SIMPLE"
|
|
url: "https://cdn.kt-event.com/images/evt-draft-12345-simple.png"
|
|
platform: "INSTAGRAM"
|
|
size:
|
|
width: 1080
|
|
height: 1080
|
|
- style: "FANCY"
|
|
url: "https://cdn.kt-event.com/images/evt-draft-12345-fancy.png"
|
|
platform: "INSTAGRAM"
|
|
size:
|
|
width: 1080
|
|
height: 1080
|
|
- style: "TRENDY"
|
|
url: "https://cdn.kt-event.com/images/evt-draft-12345-trendy.png"
|
|
platform: "INSTAGRAM"
|
|
size:
|
|
width: 1080
|
|
height: 1080
|
|
completedAt: "2025-10-22T14:28:00Z"
|
|
fromCache: true
|
|
|
|
failed:
|
|
summary: 생성 실패
|
|
value:
|
|
jobId: "job-img-abc123"
|
|
status: "FAILED"
|
|
message: "이미지 생성에 실패했습니다."
|
|
error:
|
|
code: "IMAGE_GENERATION_FAILED"
|
|
detail: "외부 AI API 응답 시간 초과. 기본 템플릿으로 대체되었습니다."
|
|
completedAt: "2025-10-22T14:30:25Z"
|
|
|
|
'404':
|
|
description: Job ID를 찾을 수 없음
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorResponse'
|
|
examples:
|
|
notFound:
|
|
summary: Job ID 없음
|
|
value:
|
|
code: "NOT_FOUND"
|
|
message: "Job ID를 찾을 수 없습니다."
|
|
timestamp: "2025-10-22T14:30:00Z"
|
|
|
|
'500':
|
|
description: 서버 내부 오류
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorResponse'
|
|
examples:
|
|
internalError:
|
|
summary: 서버 내부 오류
|
|
value:
|
|
code: "INTERNAL_SERVER_ERROR"
|
|
message: "상태 조회 중 오류가 발생했습니다."
|
|
timestamp: "2025-10-22T14:30:00Z"
|
|
|
|
security:
|
|
- BearerAuth: []
|
|
|
|
components:
|
|
securitySchemes:
|
|
BearerAuth:
|
|
type: http
|
|
scheme: bearer
|
|
bearerFormat: JWT
|
|
description: JWT 토큰을 Authorization 헤더에 포함 (Bearer {token})
|
|
|
|
schemas:
|
|
ImageGenerationRequest:
|
|
type: object
|
|
required:
|
|
- eventDraftId
|
|
- eventInfo
|
|
properties:
|
|
eventDraftId:
|
|
type: string
|
|
description: |
|
|
이벤트 초안 ID (Event Service에서 발급)
|
|
동일한 eventDraftId로 재요청 시 캐시된 이미지 반환
|
|
example: "evt-draft-12345"
|
|
|
|
eventInfo:
|
|
type: object
|
|
required:
|
|
- title
|
|
- giftName
|
|
properties:
|
|
title:
|
|
type: string
|
|
description: 이벤트 제목 (최대 50자)
|
|
minLength: 1
|
|
maxLength: 50
|
|
example: "봄맞이 커피 할인 이벤트"
|
|
|
|
giftName:
|
|
type: string
|
|
description: 경품명 (최대 30자)
|
|
minLength: 1
|
|
maxLength: 30
|
|
example: "아메리카노 1+1"
|
|
|
|
brandColor:
|
|
type: string
|
|
description: |
|
|
브랜드 컬러 (HEX 색상 코드)
|
|
사용자 프로필에서 가져오거나 기본값 사용
|
|
pattern: '^#[0-9A-Fa-f]{6}$'
|
|
example: "#FF5733"
|
|
|
|
logoUrl:
|
|
type: string
|
|
format: uri
|
|
description: |
|
|
로고 이미지 URL (선택)
|
|
업로드된 경우에만 제공
|
|
example: "https://cdn.example.com/logo.png"
|
|
|
|
ImageGenerationAcceptedResponse:
|
|
type: object
|
|
required:
|
|
- jobId
|
|
- eventDraftId
|
|
- status
|
|
- message
|
|
properties:
|
|
jobId:
|
|
type: string
|
|
description: 이미지 생성 Job ID (폴링 조회에 사용)
|
|
example: "job-img-abc123"
|
|
|
|
eventDraftId:
|
|
type: string
|
|
description: 이벤트 초안 ID
|
|
example: "evt-draft-12345"
|
|
|
|
status:
|
|
type: string
|
|
enum: [PENDING]
|
|
description: 초기 상태는 항상 PENDING
|
|
example: "PENDING"
|
|
|
|
estimatedCompletionTime:
|
|
type: integer
|
|
description: 예상 완료 시간 (초)
|
|
example: 5
|
|
|
|
message:
|
|
type: string
|
|
description: 응답 메시지
|
|
example: "이미지 생성 요청이 접수되었습니다. jobId로 결과를 조회하세요."
|
|
|
|
ImageGenerationStatusResponse:
|
|
type: object
|
|
required:
|
|
- jobId
|
|
- status
|
|
- message
|
|
properties:
|
|
jobId:
|
|
type: string
|
|
description: 이미지 생성 Job ID
|
|
example: "job-img-abc123"
|
|
|
|
status:
|
|
type: string
|
|
enum: [PENDING, PROCESSING, COMPLETED, FAILED]
|
|
description: |
|
|
Job 상태
|
|
- PENDING: 대기 중
|
|
- PROCESSING: 생성 중
|
|
- COMPLETED: 완료
|
|
- FAILED: 실패
|
|
example: "COMPLETED"
|
|
|
|
message:
|
|
type: string
|
|
description: 상태 메시지
|
|
example: "이미지 생성이 완료되었습니다."
|
|
|
|
estimatedCompletionTime:
|
|
type: integer
|
|
description: 예상 완료 시간 (초, PENDING/PROCESSING 상태에서만)
|
|
example: 3
|
|
|
|
images:
|
|
type: array
|
|
description: 생성된 이미지 배열 (COMPLETED 상태에서만)
|
|
items:
|
|
$ref: '#/components/schemas/GeneratedImage'
|
|
|
|
completedAt:
|
|
type: string
|
|
format: date-time
|
|
description: 완료 시각 (COMPLETED/FAILED 상태에서만)
|
|
example: "2025-10-22T14:30:05Z"
|
|
|
|
fromCache:
|
|
type: boolean
|
|
description: 캐시에서 반환 여부 (COMPLETED 상태에서만)
|
|
example: false
|
|
|
|
error:
|
|
$ref: '#/components/schemas/JobError'
|
|
|
|
GeneratedImage:
|
|
type: object
|
|
required:
|
|
- style
|
|
- url
|
|
- platform
|
|
- size
|
|
properties:
|
|
style:
|
|
type: string
|
|
enum: [SIMPLE, FANCY, TRENDY]
|
|
description: |
|
|
이미지 스타일
|
|
- SIMPLE: 심플 스타일 (깔끔한 디자인, 텍스트 중심)
|
|
- FANCY: 화려한 스타일 (눈에 띄는 디자인, 풍부한 색상)
|
|
- TRENDY: 트렌디 스타일 (최신 트렌드, MZ세대 타겟)
|
|
example: "SIMPLE"
|
|
|
|
url:
|
|
type: string
|
|
format: uri
|
|
description: CDN 이미지 URL
|
|
example: "https://cdn.kt-event.com/images/evt-draft-12345-simple.png"
|
|
|
|
platform:
|
|
type: string
|
|
enum: [INSTAGRAM, NAVER_BLOG, KAKAO_CHANNEL]
|
|
description: |
|
|
플랫폼별 최적화
|
|
- INSTAGRAM: 1080x1080
|
|
- NAVER_BLOG: 800x600
|
|
- KAKAO_CHANNEL: 800x800
|
|
example: "INSTAGRAM"
|
|
|
|
size:
|
|
type: object
|
|
required:
|
|
- width
|
|
- height
|
|
properties:
|
|
width:
|
|
type: integer
|
|
description: 이미지 너비 (픽셀)
|
|
example: 1080
|
|
|
|
height:
|
|
type: integer
|
|
description: 이미지 높이 (픽셀)
|
|
example: 1080
|
|
|
|
JobError:
|
|
type: object
|
|
required:
|
|
- code
|
|
- detail
|
|
description: Job 실패 시 에러 정보 (FAILED 상태에서만)
|
|
properties:
|
|
code:
|
|
type: string
|
|
description: 에러 코드
|
|
example: "IMAGE_GENERATION_FAILED"
|
|
|
|
detail:
|
|
type: string
|
|
description: 상세 에러 메시지
|
|
example: "외부 AI API 응답 시간 초과. 기본 템플릿으로 대체되었습니다."
|
|
|
|
ErrorResponse:
|
|
type: object
|
|
required:
|
|
- code
|
|
- message
|
|
- timestamp
|
|
properties:
|
|
code:
|
|
type: string
|
|
description: 에러 코드
|
|
example: "BAD_REQUEST"
|
|
|
|
message:
|
|
type: string
|
|
description: 에러 메시지
|
|
example: "eventInfo.title은 필수 항목입니다."
|
|
|
|
timestamp:
|
|
type: string
|
|
format: date-time
|
|
description: 에러 발생 시각
|
|
example: "2025-10-22T14:30:00Z"
|
|
|
|
retryAfter:
|
|
type: integer
|
|
description: 재시도 대기 시간 (초, Rate Limiting 에러에서만)
|
|
example: 60
|