kt-event-marketing/design/backend/api/content-service-api.yaml
2025-10-22 16:37:32 +09:00

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