kt-event-marketing-fe/design/backend/api/distribution-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

652 lines
21 KiB
YAML

openapi: 3.0.3
info:
title: Distribution Service API
description: |
KT AI 기반 소상공인 이벤트 자동 생성 서비스의 다중 채널 배포 관리 API
## 주요 기능
- 다중 채널 동시 배포 (우리동네TV, 링고비즈, 지니TV, SNS)
- 배포 상태 실시간 모니터링
- Circuit Breaker 기반 장애 격리
- Retry 패턴 및 Fallback 처리
## 배포 채널
- **우리동네TV**: 영상 콘텐츠 업로드
- **링고비즈**: 연결음 업데이트
- **지니TV**: 광고 등록
- **SNS**: Instagram, Naver Blog, Kakao Channel
## Resilience 패턴
- Circuit Breaker: 채널별 독립적 장애 격리
- Retry: 지수 백오프 (1s, 2s, 4s) 최대 3회
- Bulkhead: 리소스 격리
- Fallback: 실패 채널 스킵 및 알림
version: 1.0.0
contact:
name: Digital Garage Team
email: support@kt-event-marketing.com
servers:
- url: http://localhost:8085
description: Local Development Server
- url: https://dev-api.kt-event-marketing.com/distribution/v1
description: Development Server
- url: https://api.kt-event-marketing.com/distribution/v1
description: Production Server
tags:
- name: Distribution
description: 다중 채널 배포 관리
- name: Monitoring
description: 배포 상태 모니터링
paths:
/distribution/distribute:
post:
tags:
- Distribution
summary: 다중 채널 배포 요청
description: |
이벤트 콘텐츠를 선택된 채널들에 동시 배포합니다.
## 처리 흐름
1. 배포 요청 검증 (이벤트 ID, 채널 목록, 콘텐츠 데이터)
2. 채널별 병렬 배포 실행 (1분 이내 완료 목표)
3. Circuit Breaker로 장애 채널 격리
4. 실패 시 Retry (지수 백오프: 1s, 2s, 4s)
5. Fallback: 실패 채널 스킵 및 알림
6. 배포 결과 집계 및 로그 저장
7. DistributionCompleted 이벤트 Kafka 발행
## Resilience 처리
- 각 채널별 독립적인 Circuit Breaker 적용
- 최대 3회 재시도 (지수 백오프)
- 일부 채널 실패 시에도 성공 채널은 유지
- 실패 채널 정보는 응답에 포함
x-user-story: UFR-DIST-010
x-controller: DistributionController
operationId: distributeToChannels
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/DistributionRequest'
examples:
multiChannel:
summary: 다중 채널 배포 예시
value:
eventId: "evt-12345"
channels:
- type: "WOORIDONGNE_TV"
config:
radius: "1km"
timeSlots:
- "weekday_evening"
- "weekend_lunch"
- type: "INSTAGRAM"
config:
scheduledTime: "2025-11-01T10:00:00Z"
- type: "NAVER_BLOG"
config:
scheduledTime: "2025-11-01T10:30:00Z"
contentUrls:
instagram: "https://cdn.example.com/images/event-instagram.jpg"
naverBlog: "https://cdn.example.com/images/event-naver.jpg"
kakaoChannel: "https://cdn.example.com/images/event-kakao.jpg"
responses:
'200':
description: 배포 완료
content:
application/json:
schema:
$ref: '#/components/schemas/DistributionResponse'
examples:
allSuccess:
summary: 모든 채널 배포 성공
value:
distributionId: "dist-12345"
eventId: "evt-12345"
status: "COMPLETED"
completedAt: "2025-11-01T09:00:00Z"
results:
- channel: "WOORIDONGNE_TV"
status: "SUCCESS"
distributionId: "wtv-uuid-12345"
estimatedViews: 1000
message: "배포 완료"
- channel: "INSTAGRAM"
status: "SUCCESS"
postUrl: "https://instagram.com/p/generated-post-id"
postId: "ig-post-12345"
message: "게시 완료"
- channel: "NAVER_BLOG"
status: "SUCCESS"
postUrl: "https://blog.naver.com/store123/generated-post"
message: "게시 완료"
'400':
description: 잘못된 요청
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
examples:
invalidEventId:
summary: 유효하지 않은 이벤트 ID
value:
error: "BAD_REQUEST"
message: "유효하지 않은 이벤트 ID입니다"
timestamp: "2025-11-01T09:00:00Z"
noChannels:
summary: 선택된 채널 없음
value:
error: "BAD_REQUEST"
message: "최소 1개 이상의 채널을 선택해야 합니다"
timestamp: "2025-11-01T09:00:00Z"
'404':
description: 이벤트를 찾을 수 없음
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
examples:
eventNotFound:
summary: 존재하지 않는 이벤트
value:
error: "NOT_FOUND"
message: "이벤트를 찾을 수 없습니다: evt-12345"
timestamp: "2025-11-01T09:00:00Z"
'500':
description: 서버 내부 오류
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
examples:
internalError:
summary: 서버 오류
value:
error: "INTERNAL_SERVER_ERROR"
message: "배포 처리 중 오류가 발생했습니다"
timestamp: "2025-11-01T09:00:00Z"
/distribution/{eventId}/status:
get:
tags:
- Monitoring
summary: 배포 상태 조회
description: |
특정 이벤트의 배포 상태를 실시간으로 조회합니다.
## 조회 정보
- 전체 배포 상태 (진행중, 완료, 부분성공, 실패)
- 채널별 배포 상태 및 결과
- 실패 채널 상세 정보 (오류 유형, 재시도 횟수)
- 배포 시작/완료 시간 및 소요 시간
- 외부 채널 ID 및 배포 URL
## 상태 값
- **IN_PROGRESS**: 배포 진행 중
- **COMPLETED**: 모든 채널 배포 완료
- **PARTIAL_SUCCESS**: 일부 채널 배포 성공
- **FAILED**: 모든 채널 배포 실패
x-user-story: UFR-DIST-020
x-controller: DistributionController
operationId: getDistributionStatus
parameters:
- name: eventId
in: path
required: true
description: 이벤트 ID
schema:
type: string
example: "evt-12345"
responses:
'200':
description: 배포 상태 조회 성공
content:
application/json:
schema:
$ref: '#/components/schemas/DistributionStatusResponse'
examples:
completed:
summary: 배포 완료 상태
value:
eventId: "evt-12345"
overallStatus: "COMPLETED"
completedAt: "2025-11-01T09:00:00Z"
channels:
- channel: "WOORIDONGNE_TV"
status: "COMPLETED"
distributionId: "wtv-uuid-12345"
estimatedViews: 1500
completedAt: "2025-11-01T09:00:00Z"
- channel: "RINGO_BIZ"
status: "COMPLETED"
updateTimestamp: "2025-11-01T09:00:00Z"
- channel: "GENIE_TV"
status: "COMPLETED"
adId: "gtv-uuid-12345"
impressionSchedule:
- "2025-11-01 18:00-20:00"
- "2025-11-02 12:00-14:00"
- channel: "INSTAGRAM"
status: "COMPLETED"
postUrl: "https://instagram.com/p/generated-post-id"
postId: "ig-post-12345"
- channel: "NAVER_BLOG"
status: "COMPLETED"
postUrl: "https://blog.naver.com/store123/generated-post"
- channel: "KAKAO_CHANNEL"
status: "COMPLETED"
messageId: "kakao-msg-12345"
inProgress:
summary: 배포 진행중 상태
value:
eventId: "evt-12345"
overallStatus: "IN_PROGRESS"
startedAt: "2025-11-01T08:58:00Z"
channels:
- channel: "WOORIDONGNE_TV"
status: "COMPLETED"
distributionId: "wtv-uuid-12345"
estimatedViews: 1500
- channel: "INSTAGRAM"
status: "IN_PROGRESS"
progress: 50
- channel: "NAVER_BLOG"
status: "PENDING"
partialFailure:
summary: 일부 채널 실패 상태
value:
eventId: "evt-12345"
overallStatus: "PARTIAL_FAILURE"
completedAt: "2025-11-01T09:00:00Z"
channels:
- channel: "WOORIDONGNE_TV"
status: "COMPLETED"
distributionId: "wtv-uuid-12345"
estimatedViews: 1500
- channel: "INSTAGRAM"
status: "FAILED"
errorMessage: "Instagram API 타임아웃"
retries: 3
lastRetryAt: "2025-11-01T08:59:30Z"
- channel: "NAVER_BLOG"
status: "COMPLETED"
postUrl: "https://blog.naver.com/store123/generated-post"
'404':
description: 배포 이력을 찾을 수 없음
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
examples:
notFound:
summary: 배포 이력 없음
value:
error: "NOT_FOUND"
message: "배포 이력을 찾을 수 없습니다: evt-12345"
timestamp: "2025-11-01T09:00:00Z"
'500':
description: 서버 내부 오류
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
components:
schemas:
DistributionRequest:
type: object
required:
- eventId
- channels
- contentUrls
properties:
eventId:
type: string
description: 이벤트 ID
example: "evt-12345"
channels:
type: array
description: 배포할 채널 목록
minItems: 1
items:
$ref: '#/components/schemas/ChannelConfig'
contentUrls:
type: object
description: 플랫폼별 콘텐츠 URL
properties:
wooridongneTV:
type: string
description: 우리동네TV 영상 URL (15초)
example: "https://cdn.example.com/videos/event-15s.mp4"
ringoBiz:
type: string
description: 링고비즈 연결음 파일 URL
example: "https://cdn.example.com/audio/ringtone.mp3"
genieTV:
type: string
description: 지니TV 광고 영상 URL
example: "https://cdn.example.com/videos/event-ad.mp4"
instagram:
type: string
description: Instagram 이미지 URL (1080x1080)
example: "https://cdn.example.com/images/event-instagram.jpg"
naverBlog:
type: string
description: Naver Blog 이미지 URL (800x600)
example: "https://cdn.example.com/images/event-naver.jpg"
kakaoChannel:
type: string
description: Kakao Channel 이미지 URL (800x800)
example: "https://cdn.example.com/images/event-kakao.jpg"
ChannelConfig:
type: object
required:
- type
properties:
type:
type: string
description: 채널 타입
enum:
- WOORIDONGNE_TV
- RINGO_BIZ
- GENIE_TV
- INSTAGRAM
- NAVER_BLOG
- KAKAO_CHANNEL
example: "INSTAGRAM"
config:
type: object
description: 채널별 설정 (채널에 따라 다름)
additionalProperties: true
example:
scheduledTime: "2025-11-01T10:00:00Z"
caption: "이벤트 안내"
hashtags:
- "이벤트"
- "할인"
DistributionResponse:
type: object
required:
- distributionId
- eventId
- status
- results
properties:
distributionId:
type: string
description: 배포 ID
example: "dist-12345"
eventId:
type: string
description: 이벤트 ID
example: "evt-12345"
status:
type: string
description: 전체 배포 상태
enum:
- PENDING
- IN_PROGRESS
- COMPLETED
- PARTIAL_FAILURE
- FAILED
example: "COMPLETED"
startedAt:
type: string
format: date-time
description: 배포 시작 시각
example: "2025-11-01T08:59:00Z"
completedAt:
type: string
format: date-time
description: 배포 완료 시각
example: "2025-11-01T09:00:00Z"
results:
type: array
description: 채널별 배포 결과
items:
$ref: '#/components/schemas/ChannelResult'
ChannelResult:
type: object
required:
- channel
- status
properties:
channel:
type: string
description: 채널 타입
enum:
- WOORIDONGNE_TV
- RINGO_BIZ
- GENIE_TV
- INSTAGRAM
- NAVER_BLOG
- KAKAO_CHANNEL
example: "INSTAGRAM"
status:
type: string
description: 채널별 배포 상태
enum:
- PENDING
- IN_PROGRESS
- SUCCESS
- FAILED
example: "SUCCESS"
distributionId:
type: string
description: 채널별 배포 ID (우리동네TV, 지니TV)
example: "wtv-uuid-12345"
estimatedViews:
type: integer
description: 예상 노출 수 (우리동네TV, 지니TV)
example: 1500
updateTimestamp:
type: string
format: date-time
description: 업데이트 완료 시각 (링고비즈)
example: "2025-11-01T09:00:00Z"
adId:
type: string
description: 광고 ID (지니TV)
example: "gtv-uuid-12345"
impressionSchedule:
type: array
description: 노출 스케줄 (지니TV)
items:
type: string
example:
- "2025-11-01 18:00-20:00"
- "2025-11-02 12:00-14:00"
postUrl:
type: string
description: 게시물 URL (Instagram, Naver Blog)
example: "https://instagram.com/p/generated-post-id"
postId:
type: string
description: 게시물 ID (Instagram)
example: "ig-post-12345"
messageId:
type: string
description: 메시지 ID (Kakao Channel)
example: "kakao-msg-12345"
message:
type: string
description: 결과 메시지
example: "배포 완료"
errorMessage:
type: string
description: 오류 메시지 (실패 시)
example: "Instagram API 타임아웃"
retries:
type: integer
description: 재시도 횟수
example: 0
lastRetryAt:
type: string
format: date-time
description: 마지막 재시도 시각
example: "2025-11-01T08:59:30Z"
DistributionStatusResponse:
type: object
required:
- eventId
- overallStatus
- channels
properties:
eventId:
type: string
description: 이벤트 ID
example: "evt-12345"
overallStatus:
type: string
description: 전체 배포 상태
enum:
- PENDING
- IN_PROGRESS
- COMPLETED
- PARTIAL_FAILURE
- FAILED
- NOT_FOUND
example: "COMPLETED"
startedAt:
type: string
format: date-time
description: 배포 시작 시각
example: "2025-11-01T08:59:00Z"
completedAt:
type: string
format: date-time
description: 배포 완료 시각
example: "2025-11-01T09:00:00Z"
channels:
type: array
description: 채널별 배포 상태
items:
$ref: '#/components/schemas/ChannelStatus'
ChannelStatus:
type: object
required:
- channel
- status
properties:
channel:
type: string
description: 채널 타입
enum:
- WOORIDONGNE_TV
- RINGO_BIZ
- GENIE_TV
- INSTAGRAM
- NAVER_BLOG
- KAKAO_CHANNEL
example: "INSTAGRAM"
status:
type: string
description: 채널별 배포 상태
enum:
- PENDING
- IN_PROGRESS
- COMPLETED
- FAILED
example: "COMPLETED"
progress:
type: integer
description: 진행률 (0-100, IN_PROGRESS 상태일 때)
minimum: 0
maximum: 100
example: 75
distributionId:
type: string
description: 채널별 배포 ID
example: "wtv-uuid-12345"
estimatedViews:
type: integer
description: 예상 노출 수
example: 1500
updateTimestamp:
type: string
format: date-time
description: 업데이트 완료 시각
example: "2025-11-01T09:00:00Z"
adId:
type: string
description: 광고 ID
example: "gtv-uuid-12345"
impressionSchedule:
type: array
description: 노출 스케줄
items:
type: string
example:
- "2025-11-01 18:00-20:00"
postUrl:
type: string
description: 게시물 URL
example: "https://instagram.com/p/generated-post-id"
postId:
type: string
description: 게시물 ID
example: "ig-post-12345"
messageId:
type: string
description: 메시지 ID
example: "kakao-msg-12345"
completedAt:
type: string
format: date-time
description: 완료 시각
example: "2025-11-01T09:00:00Z"
errorMessage:
type: string
description: 오류 메시지
example: "Instagram API 타임아웃"
retries:
type: integer
description: 재시도 횟수
example: 3
lastRetryAt:
type: string
format: date-time
description: 마지막 재시도 시각
example: "2025-11-01T08:59:30Z"
ErrorResponse:
type: object
required:
- error
- message
- timestamp
properties:
error:
type: string
description: 오류 코드
enum:
- BAD_REQUEST
- NOT_FOUND
- INTERNAL_SERVER_ERROR
example: "BAD_REQUEST"
message:
type: string
description: 오류 메시지
example: "유효하지 않은 이벤트 ID입니다"
timestamp:
type: string
format: date-time
description: 오류 발생 시각
example: "2025-11-01T09:00:00Z"
details:
type: object
description: 추가 오류 정보 (선택 사항)
additionalProperties: true