mirror of
https://github.com/ktds-dg0501/kt-event-marketing.git
synced 2025-12-06 10:46:23 +00:00
- 공통 OpenAPI 3.0.3 컨벤션 문서 작성 (design/backend/api/API_CONVENTION.md) - 7개 서비스 API 명세서 표준화 완료: * User Service (8081) * Event Service (8080) * Content Service (8082) * AI Service (8083) * Participation Service (8084) * Distribution Service (8085) * Analytics Service (8086) 주요 변경사항: - API 경로에서 /api prefix 제거 (/api/users → /users) - 서버 URL 패턴 통일 (Local → Dev → Prod) - 연락처 정보 표준화 (Digital Garage Team) - ErrorResponse 스키마 통일 (error → message, details 추가) - securitySchemes 이름 통일 (BearerAuth) - 포트 번호 명확히 할당 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1385 lines
41 KiB
YAML
1385 lines
41 KiB
YAML
openapi: 3.0.3
|
|
info:
|
|
title: Event Service API
|
|
description: |
|
|
KT AI 기반 소상공인 이벤트 자동 생성 서비스 - Event Service API
|
|
|
|
이벤트 전체 생명주기 관리 (생성, 조회, 수정, 배포, 종료)
|
|
- AI 기반 이벤트 추천 및 커스터마이징
|
|
- 이미지 생성 및 편집 오케스트레이션
|
|
- 배포 채널 관리 및 최종 배포
|
|
- 이벤트 상태 관리 (DRAFT, PUBLISHED, ENDED)
|
|
version: 1.0.0
|
|
contact:
|
|
name: Digital Garage Team
|
|
email: support@kt-event-marketing.com
|
|
|
|
servers:
|
|
- url: http://localhost:8080
|
|
description: Local Development Server
|
|
- url: https://dev-api.kt-event-marketing.com/event/v1
|
|
description: Development Server
|
|
- url: https://api.kt-event-marketing.com/event/v1
|
|
description: Production Server
|
|
|
|
security:
|
|
- BearerAuth: []
|
|
|
|
tags:
|
|
- name: Dashboard
|
|
description: 대시보드 및 이벤트 목록 조회
|
|
- name: Event Creation
|
|
description: 이벤트 생성 플로우
|
|
- name: Event Management
|
|
description: 이벤트 수정, 삭제, 종료
|
|
- name: Job Status
|
|
description: 비동기 작업 상태 조회
|
|
|
|
paths:
|
|
/events:
|
|
get:
|
|
tags:
|
|
- Dashboard
|
|
summary: 이벤트 목록 조회
|
|
description: |
|
|
사용자의 이벤트 목록을 조회합니다 (대시보드, 전체보기).
|
|
필터, 검색, 페이징을 지원합니다.
|
|
operationId: getEvents
|
|
x-user-story: UFR-EVENT-010, UFR-EVENT-070
|
|
x-controller: EventController.getEvents
|
|
parameters:
|
|
- name: status
|
|
in: query
|
|
description: 이벤트 상태 필터 (DRAFT, PUBLISHED, ENDED)
|
|
required: false
|
|
schema:
|
|
type: string
|
|
enum: [DRAFT, PUBLISHED, ENDED]
|
|
example: PUBLISHED
|
|
- name: objective
|
|
in: query
|
|
description: 이벤트 목적 필터
|
|
required: false
|
|
schema:
|
|
type: string
|
|
example: 신규 고객 유치
|
|
- name: search
|
|
in: query
|
|
description: 검색어 (이벤트명)
|
|
required: false
|
|
schema:
|
|
type: string
|
|
example: 봄맞이
|
|
- name: page
|
|
in: query
|
|
description: 페이지 번호 (0부터 시작)
|
|
required: false
|
|
schema:
|
|
type: integer
|
|
minimum: 0
|
|
default: 0
|
|
example: 0
|
|
- name: size
|
|
in: query
|
|
description: 페이지 크기
|
|
required: false
|
|
schema:
|
|
type: integer
|
|
minimum: 1
|
|
maximum: 100
|
|
default: 20
|
|
example: 20
|
|
- name: sort
|
|
in: query
|
|
description: 정렬 기준 (createdAt, startDate, endDate)
|
|
required: false
|
|
schema:
|
|
type: string
|
|
enum: [createdAt, startDate, endDate]
|
|
default: createdAt
|
|
example: createdAt
|
|
- name: order
|
|
in: query
|
|
description: 정렬 순서 (asc, desc)
|
|
required: false
|
|
schema:
|
|
type: string
|
|
enum: [asc, desc]
|
|
default: desc
|
|
example: desc
|
|
responses:
|
|
'200':
|
|
description: 이벤트 목록 조회 성공
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/EventListResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'500':
|
|
$ref: '#/components/responses/InternalServerError'
|
|
|
|
/events/{eventId}:
|
|
get:
|
|
tags:
|
|
- Dashboard
|
|
summary: 이벤트 상세 조회
|
|
description: 특정 이벤트의 상세 정보를 조회합니다.
|
|
operationId: getEvent
|
|
x-user-story: UFR-EVENT-060
|
|
x-controller: EventController.getEvent
|
|
parameters:
|
|
- $ref: '#/components/parameters/EventId'
|
|
responses:
|
|
'200':
|
|
description: 이벤트 상세 조회 성공
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/EventDetailResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'500':
|
|
$ref: '#/components/responses/InternalServerError'
|
|
|
|
put:
|
|
tags:
|
|
- Event Management
|
|
summary: 이벤트 수정
|
|
description: |
|
|
기존 이벤트의 정보를 수정합니다.
|
|
DRAFT 상태의 이벤트만 전체 수정 가능하며,
|
|
PUBLISHED 상태에서는 제한적 수정만 가능합니다.
|
|
operationId: updateEvent
|
|
x-user-story: UFR-EVENT-060
|
|
x-controller: EventController.updateEvent
|
|
parameters:
|
|
- $ref: '#/components/parameters/EventId'
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/UpdateEventRequest'
|
|
responses:
|
|
'200':
|
|
description: 이벤트 수정 성공
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/EventDetailResponse'
|
|
'400':
|
|
$ref: '#/components/responses/BadRequest'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'409':
|
|
description: 이벤트 상태로 인해 수정 불가
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorResponse'
|
|
example:
|
|
code: EVENT_NOT_MODIFIABLE
|
|
message: PUBLISHED 상태의 이벤트는 제한적으로만 수정 가능합니다.
|
|
'500':
|
|
$ref: '#/components/responses/InternalServerError'
|
|
|
|
delete:
|
|
tags:
|
|
- Event Management
|
|
summary: 이벤트 삭제
|
|
description: |
|
|
이벤트를 삭제합니다.
|
|
DRAFT 상태의 이벤트만 삭제 가능합니다.
|
|
operationId: deleteEvent
|
|
x-user-story: UFR-EVENT-070
|
|
x-controller: EventController.deleteEvent
|
|
parameters:
|
|
- $ref: '#/components/parameters/EventId'
|
|
responses:
|
|
'204':
|
|
description: 이벤트 삭제 성공
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'409':
|
|
description: 이벤트 상태로 인해 삭제 불가
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorResponse'
|
|
example:
|
|
code: EVENT_NOT_DELETABLE
|
|
message: DRAFT 상태의 이벤트만 삭제 가능합니다.
|
|
'500':
|
|
$ref: '#/components/responses/InternalServerError'
|
|
|
|
/events/objectives:
|
|
post:
|
|
tags:
|
|
- Event Creation
|
|
summary: 이벤트 목적 선택 (Step 1)
|
|
description: |
|
|
이벤트 생성 플로우의 첫 단계입니다.
|
|
사용자가 이벤트 목적을 선택하고 DRAFT 상태의 이벤트를 생성합니다.
|
|
operationId: selectObjective
|
|
x-user-story: UFR-EVENT-020
|
|
x-controller: EventController.selectObjective
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/SelectObjectiveRequest'
|
|
responses:
|
|
'201':
|
|
description: 이벤트 생성 성공 (DRAFT 상태)
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/EventCreatedResponse'
|
|
'400':
|
|
$ref: '#/components/responses/BadRequest'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'500':
|
|
$ref: '#/components/responses/InternalServerError'
|
|
|
|
/events/{eventId}/ai-recommendations:
|
|
post:
|
|
tags:
|
|
- Event Creation
|
|
summary: AI 추천 요청 (Step 2)
|
|
description: |
|
|
AI 서비스에 이벤트 추천 생성을 요청합니다.
|
|
Kafka Job을 발행하고 jobId를 반환합니다.
|
|
Job 상태는 /jobs/{jobId}로 폴링하여 확인합니다.
|
|
operationId: requestAiRecommendations
|
|
x-user-story: UFR-EVENT-030
|
|
x-controller: EventController.requestAiRecommendations
|
|
parameters:
|
|
- $ref: '#/components/parameters/EventId'
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/AiRecommendationRequest'
|
|
responses:
|
|
'202':
|
|
description: AI 추천 요청 접수
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/JobAcceptedResponse'
|
|
'400':
|
|
$ref: '#/components/responses/BadRequest'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'409':
|
|
description: 이벤트 상태가 적절하지 않음
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorResponse'
|
|
example:
|
|
code: INVALID_EVENT_STATE
|
|
message: DRAFT 상태의 이벤트만 AI 추천을 요청할 수 있습니다.
|
|
'500':
|
|
$ref: '#/components/responses/InternalServerError'
|
|
|
|
/events/{eventId}/recommendations:
|
|
put:
|
|
tags:
|
|
- Event Creation
|
|
summary: AI 추천 선택 및 커스터마이징 (Step 2-2)
|
|
description: |
|
|
AI가 생성한 추천 중 하나를 선택하고,
|
|
필요시 이벤트명, 문구, 기간 등을 커스터마이징합니다.
|
|
operationId: selectRecommendation
|
|
x-user-story: UFR-EVENT-030
|
|
x-controller: EventController.selectRecommendation
|
|
parameters:
|
|
- $ref: '#/components/parameters/EventId'
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/SelectRecommendationRequest'
|
|
responses:
|
|
'200':
|
|
description: AI 추천 선택 및 커스터마이징 성공
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/EventDetailResponse'
|
|
'400':
|
|
$ref: '#/components/responses/BadRequest'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'409':
|
|
description: 이벤트 상태가 적절하지 않음
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorResponse'
|
|
example:
|
|
code: INVALID_EVENT_STATE
|
|
message: AI 추천이 완료된 DRAFT 상태의 이벤트만 선택 가능합니다.
|
|
'500':
|
|
$ref: '#/components/responses/InternalServerError'
|
|
|
|
/events/{eventId}/images:
|
|
post:
|
|
tags:
|
|
- Event Creation
|
|
summary: 이미지 생성 요청 (Step 3)
|
|
description: |
|
|
Content Service에 이미지 생성을 요청합니다.
|
|
Kafka Job을 발행하고 jobId를 반환합니다.
|
|
Job 상태는 /jobs/{jobId}로 폴링하여 확인합니다.
|
|
operationId: requestImageGeneration
|
|
x-user-story: UFR-CONT-010
|
|
x-controller: EventController.requestImageGeneration
|
|
parameters:
|
|
- $ref: '#/components/parameters/EventId'
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ImageGenerationRequest'
|
|
responses:
|
|
'202':
|
|
description: 이미지 생성 요청 접수
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/JobAcceptedResponse'
|
|
'400':
|
|
$ref: '#/components/responses/BadRequest'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'409':
|
|
description: 이벤트 상태가 적절하지 않음
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorResponse'
|
|
example:
|
|
code: INVALID_EVENT_STATE
|
|
message: AI 추천이 선택된 DRAFT 상태의 이벤트만 이미지 생성이 가능합니다.
|
|
'500':
|
|
$ref: '#/components/responses/InternalServerError'
|
|
|
|
/events/{eventId}/images/{imageId}/select:
|
|
put:
|
|
tags:
|
|
- Event Creation
|
|
summary: 이미지 선택 (Step 3-2)
|
|
description: |
|
|
생성된 이미지 중 하나를 선택합니다.
|
|
선택된 이미지는 이벤트의 대표 이미지로 설정됩니다.
|
|
operationId: selectImage
|
|
x-user-story: UFR-CONT-010
|
|
x-controller: EventController.selectImage
|
|
parameters:
|
|
- $ref: '#/components/parameters/EventId'
|
|
- name: imageId
|
|
in: path
|
|
description: 이미지 ID
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
example: "550e8400-e29b-41d4-a716-446655440006"
|
|
responses:
|
|
'200':
|
|
description: 이미지 선택 성공
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/EventDetailResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'409':
|
|
description: 이벤트 또는 이미지 상태가 적절하지 않음
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorResponse'
|
|
example:
|
|
code: INVALID_IMAGE_STATE
|
|
message: 해당 이미지는 이 이벤트에 속하지 않습니다.
|
|
'500':
|
|
$ref: '#/components/responses/InternalServerError'
|
|
|
|
/events/{eventId}/images/{imageId}/edit:
|
|
put:
|
|
tags:
|
|
- Event Creation
|
|
summary: 이미지 편집 (Step 3-3)
|
|
description: |
|
|
선택된 이미지를 편집합니다.
|
|
Content Service에 편집 요청을 보내고 새로운 이미지 URL을 받습니다.
|
|
operationId: editImage
|
|
x-user-story: UFR-CONT-020
|
|
x-controller: EventController.editImage
|
|
parameters:
|
|
- $ref: '#/components/parameters/EventId'
|
|
- name: imageId
|
|
in: path
|
|
description: 이미지 ID
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
example: "550e8400-e29b-41d4-a716-446655440006"
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ImageEditRequest'
|
|
responses:
|
|
'200':
|
|
description: 이미지 편집 성공
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ImageEditResponse'
|
|
'400':
|
|
$ref: '#/components/responses/BadRequest'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'409':
|
|
description: 이미지 상태가 적절하지 않음
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorResponse'
|
|
example:
|
|
code: IMAGE_NOT_EDITABLE
|
|
message: 선택된 이미지만 편집 가능합니다.
|
|
'500':
|
|
$ref: '#/components/responses/InternalServerError'
|
|
|
|
/events/{eventId}/channels:
|
|
put:
|
|
tags:
|
|
- Event Creation
|
|
summary: 배포 채널 선택 (Step 4)
|
|
description: |
|
|
이벤트를 배포할 채널을 선택합니다.
|
|
(웹사이트, 카카오톡, Instagram, Facebook 등)
|
|
operationId: selectChannels
|
|
x-user-story: UFR-EVENT-040
|
|
x-controller: EventController.selectChannels
|
|
parameters:
|
|
- $ref: '#/components/parameters/EventId'
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/SelectChannelsRequest'
|
|
responses:
|
|
'200':
|
|
description: 배포 채널 선택 성공
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/EventDetailResponse'
|
|
'400':
|
|
$ref: '#/components/responses/BadRequest'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'409':
|
|
description: 이벤트 상태가 적절하지 않음
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorResponse'
|
|
example:
|
|
code: INVALID_EVENT_STATE
|
|
message: 이미지가 선택된 DRAFT 상태의 이벤트만 채널 선택이 가능합니다.
|
|
'500':
|
|
$ref: '#/components/responses/InternalServerError'
|
|
|
|
/events/{eventId}/publish:
|
|
post:
|
|
tags:
|
|
- Event Creation
|
|
summary: 최종 승인 및 배포 (Step 5)
|
|
description: |
|
|
이벤트를 최종 승인하고 선택된 채널에 배포합니다.
|
|
Distribution Service를 동기 호출하여 배포하고,
|
|
이벤트 상태를 PUBLISHED로 변경합니다.
|
|
Kafka Event (EventCreated)를 발행합니다.
|
|
operationId: publishEvent
|
|
x-user-story: UFR-EVENT-050
|
|
x-controller: EventController.publishEvent
|
|
parameters:
|
|
- $ref: '#/components/parameters/EventId'
|
|
responses:
|
|
'200':
|
|
description: 이벤트 배포 성공
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/EventPublishedResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'409':
|
|
description: 이벤트 상태가 적절하지 않음
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorResponse'
|
|
example:
|
|
code: EVENT_NOT_PUBLISHABLE
|
|
message: 배포 채널이 선택된 DRAFT 상태의 이벤트만 배포 가능합니다.
|
|
'500':
|
|
$ref: '#/components/responses/InternalServerError'
|
|
'503':
|
|
description: Distribution Service 호출 실패
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorResponse'
|
|
example:
|
|
code: DISTRIBUTION_SERVICE_UNAVAILABLE
|
|
message: 배포 서비스를 일시적으로 사용할 수 없습니다.
|
|
|
|
/events/{eventId}/end:
|
|
post:
|
|
tags:
|
|
- Event Management
|
|
summary: 이벤트 조기 종료
|
|
description: |
|
|
진행 중인 이벤트를 조기 종료합니다.
|
|
PUBLISHED 상태의 이벤트만 종료 가능하며,
|
|
종료 시 상태가 ENDED로 변경됩니다.
|
|
operationId: endEvent
|
|
x-user-story: UFR-EVENT-060
|
|
x-controller: EventController.endEvent
|
|
parameters:
|
|
- $ref: '#/components/parameters/EventId'
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/EndEventRequest'
|
|
responses:
|
|
'200':
|
|
description: 이벤트 종료 성공
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/EventDetailResponse'
|
|
'400':
|
|
$ref: '#/components/responses/BadRequest'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'409':
|
|
description: 이벤트 상태로 인해 종료 불가
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorResponse'
|
|
example:
|
|
code: EVENT_NOT_ENDABLE
|
|
message: PUBLISHED 상태의 이벤트만 종료 가능합니다.
|
|
'500':
|
|
$ref: '#/components/responses/InternalServerError'
|
|
|
|
/jobs/{jobId}:
|
|
get:
|
|
tags:
|
|
- Job Status
|
|
summary: Job 상태 폴링
|
|
description: |
|
|
비동기 작업(AI 추천 생성, 이미지 생성)의 상태를 조회합니다.
|
|
클라이언트는 COMPLETED 또는 FAILED가 될 때까지 폴링합니다.
|
|
COMPLETED 시 Redis에서 결과를 조회할 수 있습니다.
|
|
operationId: getJobStatus
|
|
x-user-story: UFR-EVENT-030, UFR-CONT-010
|
|
x-controller: JobController.getJobStatus
|
|
parameters:
|
|
- name: jobId
|
|
in: path
|
|
description: Job ID
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
example: "550e8400-e29b-41d4-a716-446655440005"
|
|
responses:
|
|
'200':
|
|
description: Job 상태 조회 성공
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/JobStatusResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'500':
|
|
$ref: '#/components/responses/InternalServerError'
|
|
|
|
components:
|
|
securitySchemes:
|
|
BearerAuth:
|
|
type: http
|
|
scheme: bearer
|
|
bearerFormat: JWT
|
|
description: |
|
|
JWT Bearer 토큰 인증
|
|
|
|
**형식:** Authorization: Bearer {JWT_TOKEN}
|
|
|
|
**토큰 만료:** 7일
|
|
|
|
**Claims:**
|
|
- userId: 사용자 ID
|
|
- role: 사용자 역할 (OWNER)
|
|
- iat: 발급 시각
|
|
- exp: 만료 시각
|
|
|
|
parameters:
|
|
EventId:
|
|
name: eventId
|
|
in: path
|
|
description: 이벤트 ID
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
example: "550e8400-e29b-41d4-a716-446655440000"
|
|
|
|
schemas:
|
|
EventListResponse:
|
|
type: object
|
|
properties:
|
|
content:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/EventSummary'
|
|
page:
|
|
$ref: '#/components/schemas/PageInfo'
|
|
required:
|
|
- content
|
|
- page
|
|
|
|
EventSummary:
|
|
type: object
|
|
properties:
|
|
eventId:
|
|
type: string
|
|
format: uuid
|
|
description: 이벤트 ID
|
|
example: "550e8400-e29b-41d4-a716-446655440000"
|
|
eventName:
|
|
type: string
|
|
description: 이벤트명
|
|
example: "봄맞이 20% 할인 이벤트"
|
|
objective:
|
|
type: string
|
|
description: 이벤트 목적
|
|
example: "신규 고객 유치"
|
|
status:
|
|
type: string
|
|
enum: [DRAFT, PUBLISHED, ENDED]
|
|
description: 이벤트 상태
|
|
example: "PUBLISHED"
|
|
startDate:
|
|
type: string
|
|
format: date
|
|
description: 시작일
|
|
example: "2025-03-01"
|
|
endDate:
|
|
type: string
|
|
format: date
|
|
description: 종료일
|
|
example: "2025-03-31"
|
|
thumbnailUrl:
|
|
type: string
|
|
format: uri
|
|
description: 썸네일 이미지 URL
|
|
example: "https://cdn.kt-event.com/images/event-thumb-001.jpg"
|
|
createdAt:
|
|
type: string
|
|
format: date-time
|
|
description: 생성일시
|
|
example: "2025-02-15T10:30:00Z"
|
|
required:
|
|
- eventId
|
|
- eventName
|
|
- objective
|
|
- status
|
|
- startDate
|
|
- endDate
|
|
- createdAt
|
|
|
|
EventDetailResponse:
|
|
type: object
|
|
properties:
|
|
eventId:
|
|
type: string
|
|
format: uuid
|
|
description: 이벤트 ID
|
|
example: "550e8400-e29b-41d4-a716-446655440000"
|
|
userId:
|
|
type: string
|
|
format: uuid
|
|
description: 사용자 ID
|
|
example: "550e8400-e29b-41d4-a716-446655440001"
|
|
storeId:
|
|
type: string
|
|
format: uuid
|
|
description: 매장 ID
|
|
example: "550e8400-e29b-41d4-a716-446655440002"
|
|
eventName:
|
|
type: string
|
|
description: 이벤트명
|
|
example: "봄맞이 20% 할인 이벤트"
|
|
objective:
|
|
type: string
|
|
description: 이벤트 목적
|
|
example: "신규 고객 유치"
|
|
description:
|
|
type: string
|
|
description: 이벤트 설명
|
|
example: "봄을 맞이하여 모든 상품 20% 할인 행사를 진행합니다."
|
|
targetAudience:
|
|
type: string
|
|
description: 타겟 고객
|
|
example: "20-30대 여성"
|
|
promotionType:
|
|
type: string
|
|
description: 프로모션 유형
|
|
example: "할인"
|
|
discountRate:
|
|
type: integer
|
|
description: 할인율 (%)
|
|
example: 20
|
|
startDate:
|
|
type: string
|
|
format: date
|
|
description: 시작일
|
|
example: "2025-03-01"
|
|
endDate:
|
|
type: string
|
|
format: date
|
|
description: 종료일
|
|
example: "2025-03-31"
|
|
status:
|
|
type: string
|
|
enum: [DRAFT, PUBLISHED, ENDED]
|
|
description: 이벤트 상태
|
|
example: "PUBLISHED"
|
|
selectedImageId:
|
|
type: string
|
|
format: uuid
|
|
description: 선택된 이미지 ID
|
|
example: "550e8400-e29b-41d4-a716-446655440006"
|
|
selectedImageUrl:
|
|
type: string
|
|
format: uri
|
|
description: 선택된 이미지 URL
|
|
example: "https://cdn.kt-event.com/images/event-img-001.jpg"
|
|
generatedImages:
|
|
type: array
|
|
description: 생성된 이미지 목록
|
|
items:
|
|
$ref: '#/components/schemas/GeneratedImage'
|
|
channels:
|
|
type: array
|
|
description: 배포 채널 목록
|
|
items:
|
|
type: string
|
|
example: "WEBSITE"
|
|
aiRecommendations:
|
|
type: array
|
|
description: AI 추천 목록
|
|
items:
|
|
$ref: '#/components/schemas/AiRecommendation'
|
|
createdAt:
|
|
type: string
|
|
format: date-time
|
|
description: 생성일시
|
|
example: "2025-02-15T10:30:00Z"
|
|
updatedAt:
|
|
type: string
|
|
format: date-time
|
|
description: 수정일시
|
|
example: "2025-02-20T14:45:00Z"
|
|
required:
|
|
- eventId
|
|
- userId
|
|
- storeId
|
|
- eventName
|
|
- objective
|
|
- status
|
|
- startDate
|
|
- endDate
|
|
- createdAt
|
|
|
|
GeneratedImage:
|
|
type: object
|
|
properties:
|
|
imageId:
|
|
type: string
|
|
format: uuid
|
|
description: 이미지 ID
|
|
example: "550e8400-e29b-41d4-a716-446655440006"
|
|
imageUrl:
|
|
type: string
|
|
format: uri
|
|
description: 이미지 URL
|
|
example: "https://cdn.kt-event.com/images/event-img-001.jpg"
|
|
isSelected:
|
|
type: boolean
|
|
description: 선택 여부
|
|
example: true
|
|
createdAt:
|
|
type: string
|
|
format: date-time
|
|
description: 생성일시
|
|
example: "2025-02-16T11:00:00Z"
|
|
required:
|
|
- imageId
|
|
- imageUrl
|
|
- isSelected
|
|
- createdAt
|
|
|
|
AiRecommendation:
|
|
type: object
|
|
properties:
|
|
recommendationId:
|
|
type: string
|
|
format: uuid
|
|
description: 추천 ID
|
|
example: "550e8400-e29b-41d4-a716-446655440007"
|
|
eventName:
|
|
type: string
|
|
description: 추천 이벤트명
|
|
example: "봄맞이 20% 할인 이벤트"
|
|
description:
|
|
type: string
|
|
description: 추천 설명
|
|
example: "봄을 맞이하여 모든 상품 20% 할인 행사를 진행합니다."
|
|
promotionType:
|
|
type: string
|
|
description: 추천 프로모션 유형
|
|
example: "할인"
|
|
targetAudience:
|
|
type: string
|
|
description: 추천 타겟 고객
|
|
example: "20-30대 여성"
|
|
isSelected:
|
|
type: boolean
|
|
description: 선택 여부
|
|
example: true
|
|
required:
|
|
- recommendationId
|
|
- eventName
|
|
- description
|
|
- isSelected
|
|
|
|
SelectObjectiveRequest:
|
|
type: object
|
|
properties:
|
|
objective:
|
|
type: string
|
|
description: 이벤트 목적
|
|
example: "신규 고객 유치"
|
|
required:
|
|
- objective
|
|
|
|
EventCreatedResponse:
|
|
type: object
|
|
properties:
|
|
eventId:
|
|
type: string
|
|
format: uuid
|
|
description: 생성된 이벤트 ID
|
|
example: "550e8400-e29b-41d4-a716-446655440000"
|
|
status:
|
|
type: string
|
|
enum: [DRAFT]
|
|
description: 이벤트 상태 (항상 DRAFT)
|
|
example: "DRAFT"
|
|
objective:
|
|
type: string
|
|
description: 선택된 이벤트 목적
|
|
example: "신규 고객 유치"
|
|
createdAt:
|
|
type: string
|
|
format: date-time
|
|
description: 생성일시
|
|
example: "2025-02-15T10:30:00Z"
|
|
required:
|
|
- eventId
|
|
- status
|
|
- objective
|
|
- createdAt
|
|
|
|
AiRecommendationRequest:
|
|
type: object
|
|
properties:
|
|
storeInfo:
|
|
type: object
|
|
description: 매장 정보 (User Service에서 조회)
|
|
properties:
|
|
storeId:
|
|
type: string
|
|
format: uuid
|
|
example: "550e8400-e29b-41d4-a716-446655440002"
|
|
storeName:
|
|
type: string
|
|
example: "우진네 고깃집"
|
|
category:
|
|
type: string
|
|
example: "음식점"
|
|
description:
|
|
type: string
|
|
example: "신선한 한우를 제공하는 고깃집"
|
|
required:
|
|
- storeId
|
|
- storeName
|
|
- category
|
|
required:
|
|
- storeInfo
|
|
|
|
JobAcceptedResponse:
|
|
type: object
|
|
properties:
|
|
jobId:
|
|
type: string
|
|
format: uuid
|
|
description: 생성된 Job ID
|
|
example: "550e8400-e29b-41d4-a716-446655440005"
|
|
status:
|
|
type: string
|
|
enum: [PENDING]
|
|
description: Job 상태 (초기 상태는 PENDING)
|
|
example: "PENDING"
|
|
message:
|
|
type: string
|
|
description: 안내 메시지
|
|
example: "AI 추천 생성 요청이 접수되었습니다. /jobs/{jobId}로 상태를 확인하세요."
|
|
required:
|
|
- jobId
|
|
- status
|
|
- message
|
|
|
|
JobStatusResponse:
|
|
type: object
|
|
properties:
|
|
jobId:
|
|
type: string
|
|
format: uuid
|
|
description: Job ID
|
|
example: "550e8400-e29b-41d4-a716-446655440005"
|
|
jobType:
|
|
type: string
|
|
enum: [AI_RECOMMENDATION, IMAGE_GENERATION]
|
|
description: Job 유형
|
|
example: "AI_RECOMMENDATION"
|
|
status:
|
|
type: string
|
|
enum: [PENDING, PROCESSING, COMPLETED, FAILED]
|
|
description: Job 상태
|
|
example: "COMPLETED"
|
|
progress:
|
|
type: integer
|
|
minimum: 0
|
|
maximum: 100
|
|
description: 진행률 (%)
|
|
example: 100
|
|
resultKey:
|
|
type: string
|
|
description: Redis 결과 키 (COMPLETED 시)
|
|
example: "ai:recommendation:550e8400-e29b-41d4-a716-446655440005"
|
|
errorMessage:
|
|
type: string
|
|
description: 에러 메시지 (FAILED 시)
|
|
example: "AI 서비스 연결 실패"
|
|
createdAt:
|
|
type: string
|
|
format: date-time
|
|
description: Job 생성일시
|
|
example: "2025-02-15T10:31:00Z"
|
|
completedAt:
|
|
type: string
|
|
format: date-time
|
|
description: Job 완료일시
|
|
example: "2025-02-15T10:31:30Z"
|
|
required:
|
|
- jobId
|
|
- jobType
|
|
- status
|
|
- progress
|
|
- createdAt
|
|
|
|
SelectRecommendationRequest:
|
|
type: object
|
|
properties:
|
|
recommendationId:
|
|
type: string
|
|
format: uuid
|
|
description: 선택한 추천 ID
|
|
example: "550e8400-e29b-41d4-a716-446655440007"
|
|
customizations:
|
|
type: object
|
|
description: 커스터마이징 항목
|
|
properties:
|
|
eventName:
|
|
type: string
|
|
description: 수정된 이벤트명
|
|
example: "봄맞이 특별 할인 이벤트"
|
|
description:
|
|
type: string
|
|
description: 수정된 설명
|
|
example: "봄을 맞이하여 전 메뉴 20% 할인"
|
|
startDate:
|
|
type: string
|
|
format: date
|
|
description: 수정된 시작일
|
|
example: "2025-03-01"
|
|
endDate:
|
|
type: string
|
|
format: date
|
|
description: 수정된 종료일
|
|
example: "2025-03-31"
|
|
discountRate:
|
|
type: integer
|
|
description: 수정된 할인율
|
|
example: 20
|
|
required:
|
|
- recommendationId
|
|
|
|
ImageGenerationRequest:
|
|
type: object
|
|
properties:
|
|
eventInfo:
|
|
type: object
|
|
description: 이벤트 정보 (이미지 생성에 필요한 정보)
|
|
properties:
|
|
eventName:
|
|
type: string
|
|
example: "봄맞이 20% 할인 이벤트"
|
|
description:
|
|
type: string
|
|
example: "봄을 맞이하여 모든 상품 20% 할인 행사를 진행합니다."
|
|
promotionType:
|
|
type: string
|
|
example: "할인"
|
|
required:
|
|
- eventName
|
|
- description
|
|
imageCount:
|
|
type: integer
|
|
minimum: 1
|
|
maximum: 5
|
|
description: 생성할 이미지 개수
|
|
default: 3
|
|
example: 3
|
|
required:
|
|
- eventInfo
|
|
|
|
ImageEditRequest:
|
|
type: object
|
|
properties:
|
|
editType:
|
|
type: string
|
|
enum: [TEXT_OVERLAY, COLOR_ADJUST, CROP, FILTER]
|
|
description: 편집 유형
|
|
example: "TEXT_OVERLAY"
|
|
parameters:
|
|
type: object
|
|
description: 편집 파라미터 (편집 유형에 따라 다름)
|
|
additionalProperties: true
|
|
example:
|
|
text: "20% 할인"
|
|
fontSize: 48
|
|
color: "#FF0000"
|
|
position: "center"
|
|
required:
|
|
- editType
|
|
- parameters
|
|
|
|
ImageEditResponse:
|
|
type: object
|
|
properties:
|
|
imageId:
|
|
type: string
|
|
format: uuid
|
|
description: 편집된 이미지 ID
|
|
example: "550e8400-e29b-41d4-a716-446655440008"
|
|
imageUrl:
|
|
type: string
|
|
format: uri
|
|
description: 편집된 이미지 URL
|
|
example: "https://cdn.kt-event.com/images/event-img-001-edited.jpg"
|
|
editedAt:
|
|
type: string
|
|
format: date-time
|
|
description: 편집일시
|
|
example: "2025-02-16T15:20:00Z"
|
|
required:
|
|
- imageId
|
|
- imageUrl
|
|
- editedAt
|
|
|
|
SelectChannelsRequest:
|
|
type: object
|
|
properties:
|
|
channels:
|
|
type: array
|
|
description: 배포 채널 목록
|
|
items:
|
|
type: string
|
|
enum: [WEBSITE, KAKAO, INSTAGRAM, FACEBOOK, NAVER_BLOG]
|
|
example: ["WEBSITE", "KAKAO", "INSTAGRAM"]
|
|
minItems: 1
|
|
required:
|
|
- channels
|
|
|
|
EventPublishedResponse:
|
|
type: object
|
|
properties:
|
|
eventId:
|
|
type: string
|
|
format: uuid
|
|
description: 이벤트 ID
|
|
example: "550e8400-e29b-41d4-a716-446655440000"
|
|
status:
|
|
type: string
|
|
enum: [PUBLISHED]
|
|
description: 이벤트 상태 (항상 PUBLISHED)
|
|
example: "PUBLISHED"
|
|
publishedAt:
|
|
type: string
|
|
format: date-time
|
|
description: 배포일시
|
|
example: "2025-02-20T16:00:00Z"
|
|
channels:
|
|
type: array
|
|
description: 배포된 채널 목록
|
|
items:
|
|
type: string
|
|
example: "WEBSITE"
|
|
distributionResults:
|
|
type: array
|
|
description: 채널별 배포 결과
|
|
items:
|
|
$ref: '#/components/schemas/DistributionResult'
|
|
required:
|
|
- eventId
|
|
- status
|
|
- publishedAt
|
|
- channels
|
|
- distributionResults
|
|
|
|
DistributionResult:
|
|
type: object
|
|
properties:
|
|
channel:
|
|
type: string
|
|
description: 채널명
|
|
example: "WEBSITE"
|
|
success:
|
|
type: boolean
|
|
description: 배포 성공 여부
|
|
example: true
|
|
url:
|
|
type: string
|
|
format: uri
|
|
description: 배포된 URL
|
|
example: "https://store.kt-event.com/event/550e8400-e29b-41d4-a716-446655440000"
|
|
message:
|
|
type: string
|
|
description: 배포 결과 메시지
|
|
example: "웹사이트에 성공적으로 배포되었습니다."
|
|
required:
|
|
- channel
|
|
- success
|
|
|
|
UpdateEventRequest:
|
|
type: object
|
|
properties:
|
|
eventName:
|
|
type: string
|
|
description: 이벤트명
|
|
example: "봄맞이 특별 할인 이벤트"
|
|
description:
|
|
type: string
|
|
description: 이벤트 설명
|
|
example: "봄을 맞이하여 전 메뉴 20% 할인"
|
|
startDate:
|
|
type: string
|
|
format: date
|
|
description: 시작일
|
|
example: "2025-03-01"
|
|
endDate:
|
|
type: string
|
|
format: date
|
|
description: 종료일
|
|
example: "2025-03-31"
|
|
discountRate:
|
|
type: integer
|
|
description: 할인율
|
|
example: 20
|
|
|
|
EndEventRequest:
|
|
type: object
|
|
properties:
|
|
reason:
|
|
type: string
|
|
description: 종료 사유
|
|
example: "목표 달성으로 조기 종료"
|
|
required:
|
|
- reason
|
|
|
|
PageInfo:
|
|
type: object
|
|
properties:
|
|
page:
|
|
type: integer
|
|
description: 현재 페이지 번호
|
|
example: 0
|
|
size:
|
|
type: integer
|
|
description: 페이지 크기
|
|
example: 20
|
|
totalElements:
|
|
type: integer
|
|
description: 전체 요소 개수
|
|
example: 45
|
|
totalPages:
|
|
type: integer
|
|
description: 전체 페이지 개수
|
|
example: 3
|
|
required:
|
|
- page
|
|
- size
|
|
- totalElements
|
|
- totalPages
|
|
|
|
ErrorResponse:
|
|
type: object
|
|
required:
|
|
- code
|
|
- message
|
|
- timestamp
|
|
properties:
|
|
code:
|
|
type: string
|
|
description: 에러 코드
|
|
example: "INVALID_REQUEST"
|
|
message:
|
|
type: string
|
|
description: 에러 메시지
|
|
example: "요청 파라미터가 올바르지 않습니다."
|
|
timestamp:
|
|
type: string
|
|
format: date-time
|
|
description: 에러 발생 시각
|
|
example: "2025-02-15T10:30:00Z"
|
|
details:
|
|
type: array
|
|
description: 상세 에러 정보 (선택 사항)
|
|
items:
|
|
type: string
|
|
example: ["objective 필드는 필수입니다."]
|
|
|
|
responses:
|
|
BadRequest:
|
|
description: 잘못된 요청
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorResponse'
|
|
example:
|
|
code: INVALID_REQUEST
|
|
message: 요청 파라미터가 올바르지 않습니다.
|
|
details:
|
|
- "objective 필드는 필수입니다."
|
|
timestamp: "2025-02-15T10:30:00Z"
|
|
|
|
Unauthorized:
|
|
description: 인증 실패
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorResponse'
|
|
example:
|
|
code: UNAUTHORIZED
|
|
message: 인증에 실패했습니다.
|
|
timestamp: "2025-02-15T10:30:00Z"
|
|
|
|
Forbidden:
|
|
description: 권한 없음
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorResponse'
|
|
example:
|
|
code: FORBIDDEN
|
|
message: 해당 리소스에 접근할 권한이 없습니다.
|
|
timestamp: "2025-02-15T10:30:00Z"
|
|
|
|
NotFound:
|
|
description: 리소스를 찾을 수 없음
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorResponse'
|
|
example:
|
|
code: NOT_FOUND
|
|
message: 요청한 리소스를 찾을 수 없습니다.
|
|
timestamp: "2025-02-15T10:30:00Z"
|
|
|
|
InternalServerError:
|
|
description: 서버 내부 오류
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorResponse'
|
|
example:
|
|
code: INTERNAL_SERVER_ERROR
|
|
message: 서버 내부 오류가 발생했습니다.
|
|
timestamp: "2025-02-15T10:30:00Z"
|