kt-event-marketing-fe/design/backend/api/content-service-api.yaml
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
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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