Files
kt-event-marketing-fe/design/backend/api/content-service-api.yaml
T
cherry2250 3f6e005026 초기 프로젝트 설정 및 설계 문서 추가
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-24 10:10:16 +09:00

1159 lines
36 KiB
YAML

openapi: 3.0.3
info:
title: Content Service API
version: 1.0.0
description: |
# KT AI 기반 소상공인 이벤트 자동 생성 서비스 - Content Service API
## 주요 기능
- **SNS 이미지 생성** (UFR-CONT-010): AI 기반 이벤트 이미지 자동 생성
- **콘텐츠 편집** (UFR-CONT-020): 생성된 이미지 조회, 재생성, 삭제
- **3가지 스타일**: 심플(SIMPLE), 화려한(FANCY), 트렌디(TRENDY)
- **3개 플랫폼 최적화**: Instagram (1080x1080), Naver (800x600), Kakao (800x800)
- **Redis 캐싱**: TTL 7일, 동일 eventDraftId 재요청 시 캐시 반환
- **CDN 이미지 저장**: Azure Blob Storage 기반
## 비동기 처리 아키텍처
### Kafka Job Consumer
**Topic**: `image-generation-job`
**처리 흐름**:
1. Kafka에서 이미지 생성 Job 수신 (EventService에서 발행)
2. Redis에서 AI Service 이벤트 데이터 조회
3. Redis 캐시에서 기존 이미지 확인 (동일 eventDraftId)
4. 외부 이미지 생성 API 호출 (Stable Diffusion / DALL-E)
- **Circuit Breaker**: 5분 타임아웃, 실패율 50% 초과 시 Open
- **Fallback**: Stable Diffusion → DALL-E → 기본 템플릿 이미지
5. 생성된 이미지 CDN(Azure Blob) 업로드
6. Redis에 이미지 URL 저장 (TTL 7일)
7. Job 상태 업데이트 (PENDING → PROCESSING → COMPLETED/FAILED)
**Job Payload Schema**: `ImageGenerationJob` (components/schemas 참조)
## 외부 API 연동
- **Image Generation API**: Stable Diffusion / DALL-E
- **Circuit Breaker**: 5분 타임아웃, 50% 실패율 임계값
- **CDN**: Azure Blob Storage (이미지 업로드)
## 출력 형식
- 스타일별 3개 × 플랫폼별 3개 = **총 9개 이미지** 생성 (현재는 Instagram만)
- CDN URL 반환
contact:
name: Digital Garage Team
email: support@kt-event-marketing.com
servers:
- url: http://localhost:8082
description: Local Development Server
- url: https://dev-api.kt-event-marketing.com/content/v1
description: Development Server
- url: https://api.kt-event-marketing.com/content/v1
description: Production Server
tags:
- name: Job Status
description: 이미지 생성 작업 상태 조회 (비동기 폴링)
- name: Content Management
description: 생성된 콘텐츠 조회 및 관리 (UFR-CONT-020)
- name: Image Management
description: 이미지 재생성 및 삭제 (UFR-CONT-020)
paths:
/content/images/generate:
post:
tags:
- Job Status
summary: SNS 이미지 생성 요청 (비동기)
description: |
이벤트 정보를 기반으로 3가지 스타일의 SNS 이미지 생성을 비동기로 요청합니다.
## 처리 방식
- **비동기 처리**: Kafka `image-generation-job` 토픽에 Job 발행
- **폴링 조회**: jobId로 생성 상태 조회 (GET /content/images/jobs/{jobId})
- **캐싱**: 동일한 eventDraftId 재요청 시 캐시 반환 (TTL 7일)
## 생성 스타일
1. **심플 스타일 (SIMPLE)**: 깔끔한 디자인, 텍스트 중심
2. **화려한 스타일 (FANCY)**: 눈에 띄는 디자인, 풍부한 색상
3. **트렌디 스타일 (TRENDY)**: 최신 트렌드, MZ세대 타겟
## Resilience 패턴
- Circuit Breaker (5분 타임아웃, 실패율 50% 초과 시 Open)
- Fallback (Stable Diffusion → DALL-E → 기본 템플릿)
operationId: generateImages
x-user-story: UFR-CONT-010
x-controller: ImageGenerationController.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: []
/content/images/jobs/{jobId}:
get:
tags:
- Job Status
summary: 이미지 생성 작업 상태 조회 (폴링)
description: |
jobId로 이미지 생성 상태를 조회합니다.
## 폴링 권장사항
- **폴링 간격**: 2초
- **최대 폴링 시간**: 30초
- **Timeout 후 처리**: 에러 메시지 표시 및 재시도 옵션 제공
## 상태 종류
- **PENDING**: 대기 중 (Kafka Queue에서 대기)
- **PROCESSING**: 생성 중 (AI API 호출 진행)
- **COMPLETED**: 완료 (3가지 이미지 URL 반환)
- **FAILED**: 실패 (에러 메시지 포함, Fallback 이미지 제공)
## 캐싱
- COMPLETED 상태는 Redis 캐싱 (TTL 7일)
- 동일한 eventDraftId 재요청 시 즉시 반환
operationId: getImageGenerationStatus
x-user-story: UFR-CONT-010
x-controller: ImageGenerationController.getJobStatus
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: []
/content/events/{eventDraftId}:
get:
tags:
- Content Management
summary: 이벤트의 생성된 콘텐츠 조회
description: |
특정 이벤트의 생성된 모든 콘텐츠(이미지) 조회
- Redis 캐시에서 조회
- TTL 7일 이내 데이터만 조회 가능
- 캐시 만료 시 404 반환
operationId: getContentByEventId
x-user-story: UFR-CONT-020
x-controller: ContentController.getContentByEventId
parameters:
- name: eventDraftId
in: path
required: true
description: 이벤트 초안 ID
schema:
type: string
example: "evt-draft-12345"
responses:
"200":
description: 콘텐츠 조회 성공
content:
application/json:
schema:
$ref: "#/components/schemas/ContentResponse"
examples:
success:
summary: 콘텐츠 조회 성공
value:
eventDraftId: "evt-draft-12345"
images:
- imageId: "img-12345-simple"
style: "SIMPLE"
url: "https://cdn.kt-event.com/images/evt-draft-12345-simple.png"
platform: "INSTAGRAM"
size:
width: 1080
height: 1080
createdAt: "2025-10-22T14:30:05Z"
- imageId: "img-12345-fancy"
style: "FANCY"
url: "https://cdn.kt-event.com/images/evt-draft-12345-fancy.png"
platform: "INSTAGRAM"
size:
width: 1080
height: 1080
createdAt: "2025-10-22T14:30:10Z"
- imageId: "img-12345-trendy"
style: "TRENDY"
url: "https://cdn.kt-event.com/images/evt-draft-12345-trendy.png"
platform: "INSTAGRAM"
size:
width: 1080
height: 1080
createdAt: "2025-10-22T14:30:15Z"
totalCount: 3
createdAt: "2025-10-22T14:30:00Z"
expiresAt: "2025-10-29T14:30:00Z"
"404":
description: 콘텐츠를 찾을 수 없음 (생성 중이거나 만료됨)
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
examples:
notFound:
summary: 콘텐츠 없음
value:
code: "CONTENT_NOT_FOUND"
message: "해당 이벤트의 콘텐츠를 찾을 수 없습니다."
timestamp: "2025-10-22T14:30:00Z"
"500":
description: 서버 내부 오류
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
security:
- BearerAuth: []
/content/events/{eventDraftId}/images:
get:
tags:
- Content Management
summary: 이벤트의 이미지 목록 조회 (필터링)
description: |
특정 이벤트의 모든 생성 이미지 목록 조회
- 스타일별, 플랫폼별 필터링 지원
operationId: getImages
x-user-story: UFR-CONT-020
x-controller: ContentController.getImages
parameters:
- name: eventDraftId
in: path
required: true
description: 이벤트 초안 ID
schema:
type: string
example: "evt-draft-12345"
- name: style
in: query
required: false
description: 이미지 스타일 필터
schema:
type: string
enum: [SIMPLE, FANCY, TRENDY]
example: "SIMPLE"
- name: platform
in: query
required: false
description: 플랫폼 필터
schema:
type: string
enum: [INSTAGRAM, NAVER_BLOG, KAKAO_CHANNEL]
example: "INSTAGRAM"
responses:
"200":
description: 이미지 목록 조회 성공
content:
application/json:
schema:
type: object
properties:
eventDraftId:
type: string
totalCount:
type: integer
images:
type: array
items:
$ref: "#/components/schemas/GeneratedImage"
examples:
allImages:
summary: 전체 이미지 조회
value:
eventDraftId: "evt-draft-12345"
totalCount: 3
images:
- imageId: "img-12345-simple"
style: "SIMPLE"
url: "https://cdn.kt-event.com/images/evt-draft-12345-simple.png"
platform: "INSTAGRAM"
size:
width: 1080
height: 1080
createdAt: "2025-10-22T14:30:05Z"
"404":
description: 이미지를 찾을 수 없음
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
security:
- BearerAuth: []
/content/images/{imageId}:
get:
tags:
- Image Management
summary: 특정 이미지 상세 조회
description: 이미지 ID로 특정 이미지의 상세 정보 조회
operationId: getImageById
x-user-story: UFR-CONT-020
x-controller: ContentController.getImageById
parameters:
- name: imageId
in: path
required: true
description: 이미지 ID
schema:
type: string
example: "img-12345-simple"
responses:
"200":
description: 이미지 조회 성공
content:
application/json:
schema:
$ref: "#/components/schemas/GeneratedImage"
examples:
success:
summary: 이미지 조회 성공
value:
imageId: "img-12345-simple"
style: "SIMPLE"
url: "https://cdn.kt-event.com/images/evt-draft-12345-simple.png"
platform: "INSTAGRAM"
size:
width: 1080
height: 1080
createdAt: "2025-10-22T14:30:05Z"
"404":
description: 이미지를 찾을 수 없음
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
security:
- BearerAuth: []
delete:
tags:
- Image Management
summary: 생성된 이미지 삭제
description: |
특정 이미지 삭제
- Redis 캐시에서 제거
- CDN 이미지는 유지 (비용 고려)
operationId: deleteImage
x-user-story: UFR-CONT-020
x-controller: ContentController.deleteImage
parameters:
- name: imageId
in: path
required: true
description: 이미지 ID
schema:
type: string
example: "img-12345-simple"
responses:
"204":
description: 이미지 삭제 성공
"404":
description: 이미지를 찾을 수 없음
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
security:
- BearerAuth: []
/content/images/{imageId}/regenerate:
post:
tags:
- Image Management
summary: 이미지 재생성 요청
description: |
특정 이미지를 재생성 (콘텐츠 편집)
- 동일한 스타일/플랫폼으로 재생성
- 프롬프트 수정 가능
- 비동기 처리 (Kafka Job 발행)
operationId: regenerateImage
x-user-story: UFR-CONT-020
x-controller: ContentController.regenerateImage
parameters:
- name: imageId
in: path
required: true
description: 이미지 ID
schema:
type: string
example: "img-12345-simple"
requestBody:
required: false
description: 재생성 옵션 (선택사항)
content:
application/json:
schema:
$ref: "#/components/schemas/ImageRegenerationRequest"
examples:
modifyPrompt:
summary: 프롬프트 수정
value:
content: "밝은 분위기로 변경"
changeStyle:
summary: 스타일 변경
value:
style: "FANCY"
responses:
"202":
description: 재생성 요청 접수 (비동기 처리)
content:
application/json:
schema:
type: object
required:
- message
- jobId
- estimatedTime
properties:
message:
type: string
example: "이미지 재생성 요청이 접수되었습니다"
jobId:
type: string
example: "job-regen-abc123"
estimatedTime:
type: integer
description: 예상 소요 시간 (초)
example: 10
"404":
description: 원본 이미지를 찾을 수 없음
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
"503":
description: 이미지 생성 서비스 장애 (Circuit Breaker Open)
content:
application/json:
schema:
$ref: "#/components/schemas/CircuitBreakerErrorResponse"
security:
- BearerAuth: []
components:
securitySchemes:
BearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
description: JWT 토큰을 Authorization 헤더에 포함 (Bearer {token})
schemas:
# ========================================
# Kafka Job Schema (비동기 처리)
# ========================================
ImageGenerationJob:
type: object
description: |
**Kafka Topic**: `image-generation-job`
Event Service에서 발행하여 Content Service가 소비하는 Job Payload
- Content Service의 Kafka Consumer가 처리
- 비동기 이미지 생성 작업 수행
required:
- jobId
- eventDraftId
- eventInfo
properties:
jobId:
type: string
description: Job ID (작업 추적용)
example: "job-img-abc123"
eventDraftId:
type: string
description: 이벤트 초안 ID
example: "evt-draft-12345"
eventInfo:
type: object
description: 이벤트 정보 (AI Service에서 생성)
required:
- title
- giftName
properties:
title:
type: string
description: 이벤트 제목
example: "봄맞이 커피 할인 이벤트"
giftName:
type: string
description: 경품명
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"
styles:
type: array
description: 생성할 스타일 목록 (기본값 전체)
items:
type: string
enum: [SIMPLE, FANCY, TRENDY]
example: ["SIMPLE", "FANCY", "TRENDY"]
platforms:
type: array
description: 생성할 플랫폼 목록 (기본값 Instagram)
items:
type: string
enum: [INSTAGRAM, NAVER_BLOG, KAKAO_CHANNEL]
example: ["INSTAGRAM"]
priority:
type: integer
description: 우선순위 (1-10, 높을수록 우선)
minimum: 1
maximum: 10
example: 5
requestedAt:
type: string
format: date-time
description: 요청 시각
example: "2025-10-22T14:00:00Z"
# ========================================
# Request 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
# ========================================
# Content Management Schemas (UFR-CONT-020)
# ========================================
ContentResponse:
type: object
description: 이벤트의 생성된 콘텐츠 전체 정보
required:
- eventDraftId
- images
- totalCount
- createdAt
- expiresAt
properties:
eventDraftId:
type: string
description: 이벤트 초안 ID
example: "evt-draft-12345"
images:
type: array
description: 생성된 이미지 목록
items:
$ref: "#/components/schemas/ImageDetail"
totalCount:
type: integer
description: 총 이미지 개수
example: 3
createdAt:
type: string
format: date-time
description: 콘텐츠 생성 시각
example: "2025-10-22T14:30:00Z"
expiresAt:
type: string
format: date-time
description: 캐시 만료 시각 (TTL 7일)
example: "2025-10-29T14:30:00Z"
ImageDetail:
type: object
description: 상세 이미지 정보 (생성 시각 포함)
required:
- imageId
- style
- url
- platform
- size
- createdAt
properties:
imageId:
type: string
description: 이미지 ID
example: "img-12345-simple"
style:
type: string
enum: [SIMPLE, FANCY, TRENDY]
description: 이미지 스타일
example: "SIMPLE"
url:
type: string
format: uri
description: CDN 이미지 URL (Azure Blob Storage)
example: "https://cdn.kt-event.com/images/evt-draft-12345-simple.png"
platform:
type: string
enum: [INSTAGRAM, NAVER_BLOG, KAKAO_CHANNEL]
description: 플랫폼
example: "INSTAGRAM"
size:
type: object
required:
- width
- height
properties:
width:
type: integer
description: 이미지 너비 (픽셀)
example: 1080
height:
type: integer
description: 이미지 높이 (픽셀)
example: 1080
createdAt:
type: string
format: date-time
description: 이미지 생성 시각
example: "2025-10-22T14:30:05Z"
fallbackUsed:
type: boolean
description: Fallback 이미지 사용 여부
example: false
ImageRegenerationRequest:
type: object
description: 이미지 재생성 요청 (콘텐츠 편집)
properties:
content:
type: string
description: 수정된 프롬프트 (선택사항)
example: "밝은 분위기로 변경"
style:
type: string
description: 변경할 스타일 (선택사항)
enum: [SIMPLE, FANCY, TRENDY]
example: "FANCY"
CircuitBreakerErrorResponse:
type: object
description: Circuit Breaker 오류 응답 (외부 API 장애)
required:
- code
- message
- timestamp
- circuitBreakerState
properties:
code:
type: string
description: 에러 코드
example: "IMAGE_GENERATION_SERVICE_UNAVAILABLE"
message:
type: string
description: 에러 메시지
example: "이미지 생성 서비스가 일시적으로 사용 불가능합니다"
timestamp:
type: string
format: date-time
description: 에러 발생 시각
example: "2025-10-22T14:30:00Z"
circuitBreakerState:
type: string
enum: [OPEN, HALF_OPEN, CLOSED]
description: Circuit Breaker 상태
example: "OPEN"
fallbackAvailable:
type: boolean
description: Fallback 이미지 사용 가능 여부
example: true
fallbackImageUrl:
type: string
format: uri
description: Fallback 템플릿 이미지 URL (사용 가능한 경우)
example: "https://cdn.kt-event.com/templates/default_event.png"
retryAfter:
type: integer
description: 재시도 가능 시간 (초)
example: 300