mirror of
https://github.com/ktds-dg0501/kt-event-marketing.git
synced 2025-12-06 06:46:25 +00:00
7개 마이크로서비스 API 명세서 컨벤션 통일
- 공통 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>
This commit is contained in:
parent
b9745f24e5
commit
6b1c4224f7
914
design/backend/api/API_CONVENTION.md
Normal file
914
design/backend/api/API_CONVENTION.md
Normal file
@ -0,0 +1,914 @@
|
||||
# OpenAPI 3.0.3 공통 컨벤션
|
||||
|
||||
KT AI 기반 소상공인 이벤트 자동 생성 서비스의 모든 마이크로서비스 API 명세서에 적용되는 공통 컨벤션입니다.
|
||||
|
||||
## 목차
|
||||
1. [기본 정보 섹션](#1-기본-정보-섹션)
|
||||
2. [서버 정의](#2-서버-정의)
|
||||
3. [보안 스키마](#3-보안-스키마)
|
||||
4. [태그 구성](#4-태그-구성)
|
||||
5. [엔드포인트 정의](#5-엔드포인트-정의)
|
||||
6. [응답 구조](#6-응답-구조)
|
||||
7. [에러 응답 구조](#7-에러-응답-구조)
|
||||
8. [스키마 정의](#8-스키마-정의)
|
||||
9. [메타데이터 주석](#9-메타데이터-주석)
|
||||
10. [기술 명세 섹션](#10-기술-명세-섹션)
|
||||
11. [예제 작성](#11-예제-작성)
|
||||
|
||||
---
|
||||
|
||||
## 1. 기본 정보 섹션
|
||||
|
||||
### 1.1 OpenAPI 버전
|
||||
```yaml
|
||||
openapi: 3.0.3
|
||||
```
|
||||
- **필수**: 모든 명세서는 OpenAPI 3.0.3 버전을 사용합니다.
|
||||
|
||||
### 1.2 Info 객체
|
||||
```yaml
|
||||
info:
|
||||
title: {Service Name} API
|
||||
description: |
|
||||
KT AI 기반 소상공인 이벤트 자동 생성 서비스 - {Service Name} API
|
||||
|
||||
{서비스 설명 1-2줄}
|
||||
|
||||
**주요 기능:**
|
||||
- {기능 1}
|
||||
- {기능 2}
|
||||
- {기능 3}
|
||||
|
||||
**보안:** (보안 관련 서비스인 경우)
|
||||
- {보안 메커니즘 1}
|
||||
- {보안 메커니즘 2}
|
||||
version: 1.0.0
|
||||
contact:
|
||||
name: Digital Garage Team
|
||||
email: support@kt-event-marketing.com
|
||||
```
|
||||
|
||||
**필수 항목:**
|
||||
- `title`: "{서비스명} API" 형식
|
||||
- `description`: 마크다운 형식으로 서비스 설명 작성
|
||||
- 첫 줄: 프로젝트명과 서비스 역할
|
||||
- 서비스 설명
|
||||
- 주요 기능 목록 (bullet points)
|
||||
- 보안 관련 서비스의 경우 보안 섹션 추가
|
||||
- `version`: "1.0.0"
|
||||
- `contact`: name과 email 필수
|
||||
|
||||
---
|
||||
|
||||
## 2. 서버 정의
|
||||
|
||||
### 2.1 서버 URL 구조
|
||||
```yaml
|
||||
servers:
|
||||
- url: http://localhost:{port}
|
||||
description: Local Development Server
|
||||
- url: https://dev-api.kt-event-marketing.com/{service}/v1
|
||||
description: Development Server
|
||||
- url: https://api.kt-event-marketing.com/{service}/v1
|
||||
description: Production Server
|
||||
```
|
||||
|
||||
**포트 번호 할당:**
|
||||
- User Service: 8081
|
||||
- Event Service: 8080
|
||||
- Content Service: 8082
|
||||
- AI Service: 8083
|
||||
- Participation Service: 8084
|
||||
- Distribution Service: 8085
|
||||
- Analytics Service: 8086
|
||||
|
||||
**URL 패턴:**
|
||||
- Local: `http://localhost:{port}`
|
||||
- Dev: `https://dev-api.kt-event-marketing.com/{service}/v1`
|
||||
- Prod: `https://api.kt-event-marketing.com/{service}/v1`
|
||||
|
||||
---
|
||||
|
||||
## 3. 보안 스키마
|
||||
|
||||
### 3.1 JWT Bearer 인증
|
||||
```yaml
|
||||
components:
|
||||
securitySchemes:
|
||||
BearerAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: JWT
|
||||
description: |
|
||||
JWT Bearer 토큰 인증
|
||||
|
||||
**형식:** Authorization: Bearer {JWT_TOKEN}
|
||||
|
||||
**토큰 만료:** 7일
|
||||
|
||||
**Claims:**
|
||||
- userId: 사용자 ID
|
||||
- role: 사용자 역할 (OWNER)
|
||||
- iat: 발급 시각
|
||||
- exp: 만료 시각
|
||||
```
|
||||
|
||||
### 3.2 전역 보안 적용
|
||||
```yaml
|
||||
security:
|
||||
- BearerAuth: []
|
||||
```
|
||||
|
||||
**적용 방법:**
|
||||
- 인증이 필요한 모든 엔드포인트에 `security` 섹션 추가
|
||||
- 공개 API (예: 로그인, 회원가입)는 엔드포인트 레벨에서 `security: []`로 오버라이드
|
||||
|
||||
---
|
||||
|
||||
## 4. 태그 구성
|
||||
|
||||
### 4.1 태그 정의 패턴
|
||||
```yaml
|
||||
tags:
|
||||
- name: {Category Name}
|
||||
description: {카테고리 설명 (한글)}
|
||||
```
|
||||
|
||||
**태그 명명 규칙:**
|
||||
- **영문 사용**: 명확한 영문 카테고리명
|
||||
- **설명 한글**: description은 한글로 상세 설명
|
||||
- **일관성 유지**: 유사 기능은 동일한 태그명 사용
|
||||
|
||||
**예시:**
|
||||
```yaml
|
||||
tags:
|
||||
- name: Authentication
|
||||
description: 인증 관련 API (로그인, 로그아웃, 회원가입)
|
||||
- name: Profile
|
||||
description: 프로필 관련 API (조회, 수정, 비밀번호 변경)
|
||||
- name: Event Creation
|
||||
description: 이벤트 생성 플로우
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 엔드포인트 정의
|
||||
|
||||
### 5.1 엔드포인트 경로 규칙
|
||||
|
||||
**경로 패턴:**
|
||||
```
|
||||
/{resource}
|
||||
/{resource}/{id}
|
||||
/{resource}/{id}/{sub-resource}
|
||||
```
|
||||
|
||||
**중요: `/api` prefix 사용 금지**
|
||||
- ❌ 잘못된 예: `/api/users/register`
|
||||
- ✅ 올바른 예: `/users/register`
|
||||
|
||||
API Gateway 또는 서버 URL에서 서비스 구분이 이루어지므로, 엔드포인트 경로에 `/api`를 포함하지 않습니다.
|
||||
|
||||
### 5.2 공통 엔드포인트 구조
|
||||
```yaml
|
||||
paths:
|
||||
/{resource}:
|
||||
{http-method}:
|
||||
tags:
|
||||
- {Tag Name}
|
||||
summary: {짧은 한글 설명}
|
||||
description: |
|
||||
{상세 설명}
|
||||
|
||||
**유저스토리:** {UFR 코드}
|
||||
|
||||
**주요 기능:**
|
||||
- {기능 1}
|
||||
- {기능 2}
|
||||
|
||||
**처리 흐름:** (복잡한 로직인 경우)
|
||||
1. {단계 1}
|
||||
2. {단계 2}
|
||||
|
||||
**보안:** (보안 관련 엔드포인트인 경우)
|
||||
- {보안 메커니즘}
|
||||
operationId: {camelCase 메서드명}
|
||||
x-user-story: {UFR 코드}
|
||||
x-controller: {ControllerClass}.{methodName}
|
||||
security:
|
||||
- BearerAuth: []
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/{ParameterName}'
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/{RequestSchema}'
|
||||
examples:
|
||||
{exampleName}:
|
||||
summary: {예시 설명}
|
||||
value: {...}
|
||||
responses:
|
||||
'{statusCode}':
|
||||
description: {응답 설명}
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/{ResponseSchema}'
|
||||
examples:
|
||||
{exampleName}:
|
||||
summary: {예시 설명}
|
||||
value: {...}
|
||||
```
|
||||
|
||||
### 5.3 필수 항목
|
||||
- `tags`: 1개 이상의 태그 지정
|
||||
- `summary`: 한글로 간결하게 (10자 이내 권장)
|
||||
- `description`: 마크다운 형식의 상세 설명
|
||||
- 유저스토리 코드 명시
|
||||
- 주요 기능 bullet points
|
||||
- 복잡한 경우 처리 흐름 순서 작성
|
||||
- 보안 관련 내용 (해당 시)
|
||||
- `operationId`: camelCase 메서드명 (예: `getUserProfile`, `createEvent`)
|
||||
- `x-user-story`: UFR 코드 (예: `UFR-USER-010`)
|
||||
- `x-controller`: 컨트롤러 클래스와 메서드 (예: `UserController.getProfile`)
|
||||
|
||||
### 5.4 operationId 명명 규칙
|
||||
```
|
||||
{동사}{명사}
|
||||
```
|
||||
|
||||
**동사 목록:**
|
||||
- `get`: 조회
|
||||
- `list`: 목록 조회
|
||||
- `create`: 생성
|
||||
- `update`: 수정
|
||||
- `delete`: 삭제
|
||||
- `register`: 등록
|
||||
- `login`: 로그인
|
||||
- `logout`: 로그아웃
|
||||
- `select`: 선택
|
||||
- `request`: 요청
|
||||
- `publish`: 배포
|
||||
- `end`: 종료
|
||||
|
||||
**예시:**
|
||||
- `getUser`, `listEvents`, `createEvent`
|
||||
- `updateProfile`, `deleteEvent`
|
||||
- `registerUser`, `loginUser`, `logoutUser`
|
||||
- `selectRecommendation`, `publishEvent`
|
||||
|
||||
---
|
||||
|
||||
## 6. 응답 구조
|
||||
|
||||
### 6.1 성공 응답 (Success Response)
|
||||
|
||||
**원칙: 직접 응답 (Direct Response)**
|
||||
```yaml
|
||||
responses:
|
||||
'200':
|
||||
description: {작업} 성공
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/{ResponseSchema}'
|
||||
```
|
||||
|
||||
**응답 스키마 예시:**
|
||||
```yaml
|
||||
UserProfileResponse:
|
||||
type: object
|
||||
required:
|
||||
- userId
|
||||
- userName
|
||||
- email
|
||||
properties:
|
||||
userId:
|
||||
type: integer
|
||||
format: int64
|
||||
description: 사용자 ID
|
||||
example: 123
|
||||
userName:
|
||||
type: string
|
||||
description: 사용자 이름
|
||||
example: 홍길동
|
||||
email:
|
||||
type: string
|
||||
format: email
|
||||
description: 이메일 주소
|
||||
example: hong@example.com
|
||||
```
|
||||
|
||||
**예외: Wrapper가 필요한 경우 (메시지 전달 필요 시)**
|
||||
```yaml
|
||||
LogoutResponse:
|
||||
type: object
|
||||
required:
|
||||
- success
|
||||
- message
|
||||
properties:
|
||||
success:
|
||||
type: boolean
|
||||
description: 성공 여부
|
||||
example: true
|
||||
message:
|
||||
type: string
|
||||
description: 응답 메시지
|
||||
example: 안전하게 로그아웃되었습니다
|
||||
```
|
||||
|
||||
### 6.2 페이징 응답 (Pagination Response)
|
||||
```yaml
|
||||
{Resource}ListResponse:
|
||||
type: object
|
||||
required:
|
||||
- content
|
||||
- page
|
||||
properties:
|
||||
content:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/{ResourceSummary}'
|
||||
page:
|
||||
$ref: '#/components/schemas/PageInfo'
|
||||
|
||||
PageInfo:
|
||||
type: object
|
||||
required:
|
||||
- page
|
||||
- size
|
||||
- totalElements
|
||||
- totalPages
|
||||
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
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 에러 응답 구조
|
||||
|
||||
### 7.1 표준 에러 응답 스키마
|
||||
```yaml
|
||||
ErrorResponse:
|
||||
type: object
|
||||
required:
|
||||
- code
|
||||
- message
|
||||
- timestamp
|
||||
properties:
|
||||
code:
|
||||
type: string
|
||||
description: 에러 코드
|
||||
example: USER_001
|
||||
message:
|
||||
type: string
|
||||
description: 에러 메시지
|
||||
example: 이미 가입된 전화번호입니다
|
||||
timestamp:
|
||||
type: string
|
||||
format: date-time
|
||||
description: 에러 발생 시각
|
||||
example: 2025-10-22T10:30:00Z
|
||||
details:
|
||||
type: array
|
||||
description: 상세 에러 정보 (선택 사항)
|
||||
items:
|
||||
type: string
|
||||
example: ["필드명: 필수 항목입니다"]
|
||||
```
|
||||
|
||||
**필수 필드:**
|
||||
- `code`: 에러 코드 (서비스별 고유 코드)
|
||||
- `message`: 사용자에게 표시할 에러 메시지 (한글)
|
||||
- `timestamp`: 에러 발생 시각 (ISO 8601 형식)
|
||||
|
||||
**선택 필드:**
|
||||
- `details`: 상세 에러 정보 배열 (validation 에러 등)
|
||||
|
||||
### 7.2 에러 코드 명명 규칙
|
||||
```
|
||||
{SERVICE}_{NUMBER}
|
||||
```
|
||||
|
||||
**서비스 약어:**
|
||||
- `USER`: User Service
|
||||
- `EVENT`: Event Service
|
||||
- `CONT`: Content Service
|
||||
- `AI`: AI Service
|
||||
- `PART`: Participation Service
|
||||
- `DIST`: Distribution Service
|
||||
- `ANAL`: Analytics Service
|
||||
- `AUTH`: 인증 관련 (공통)
|
||||
- `VALIDATION_ERROR`: 입력 검증 오류 (공통)
|
||||
|
||||
**예시:**
|
||||
- `USER_001`: 중복 사용자
|
||||
- `USER_002`: 사업자번호 검증 실패
|
||||
- `AUTH_001`: 인증 실패
|
||||
- `AUTH_002`: 유효하지 않은 토큰
|
||||
- `VALIDATION_ERROR`: 입력 검증 오류
|
||||
|
||||
### 7.3 공통 에러 응답 정의
|
||||
```yaml
|
||||
components:
|
||||
responses:
|
||||
BadRequest:
|
||||
description: 잘못된 요청
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
examples:
|
||||
validationError:
|
||||
summary: 입력 검증 오류
|
||||
value:
|
||||
code: VALIDATION_ERROR
|
||||
message: 요청 파라미터가 올바르지 않습니다
|
||||
timestamp: 2025-10-22T10:30:00Z
|
||||
details:
|
||||
- "필드명: 필수 항목입니다"
|
||||
|
||||
Unauthorized:
|
||||
description: 인증 실패
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
examples:
|
||||
authFailed:
|
||||
summary: 인증 실패
|
||||
value:
|
||||
code: AUTH_001
|
||||
message: 인증에 실패했습니다
|
||||
timestamp: 2025-10-22T10:30:00Z
|
||||
|
||||
Forbidden:
|
||||
description: 권한 없음
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
examples:
|
||||
forbidden:
|
||||
summary: 권한 없음
|
||||
value:
|
||||
code: AUTH_003
|
||||
message: 해당 리소스에 접근할 권한이 없습니다
|
||||
timestamp: 2025-10-22T10:30:00Z
|
||||
|
||||
NotFound:
|
||||
description: 리소스를 찾을 수 없음
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
examples:
|
||||
notFound:
|
||||
summary: 리소스 없음
|
||||
value:
|
||||
code: NOT_FOUND
|
||||
message: 요청한 리소스를 찾을 수 없습니다
|
||||
timestamp: 2025-10-22T10:30:00Z
|
||||
|
||||
InternalServerError:
|
||||
description: 서버 내부 오류
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
examples:
|
||||
serverError:
|
||||
summary: 서버 오류
|
||||
value:
|
||||
code: INTERNAL_SERVER_ERROR
|
||||
message: 서버 내부 오류가 발생했습니다
|
||||
timestamp: 2025-10-22T10:30:00Z
|
||||
```
|
||||
|
||||
### 7.4 엔드포인트별 에러 응답 적용
|
||||
```yaml
|
||||
responses:
|
||||
'400':
|
||||
$ref: '#/components/responses/BadRequest'
|
||||
'401':
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
'403':
|
||||
$ref: '#/components/responses/Forbidden'
|
||||
'404':
|
||||
$ref: '#/components/responses/NotFound'
|
||||
'500':
|
||||
$ref: '#/components/responses/InternalServerError'
|
||||
```
|
||||
|
||||
**특수 에러 (비즈니스 로직 에러):**
|
||||
```yaml
|
||||
'409':
|
||||
description: 비즈니스 로직 충돌
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
examples:
|
||||
duplicateUser:
|
||||
summary: 중복 사용자
|
||||
value:
|
||||
code: USER_001
|
||||
message: 이미 가입된 전화번호입니다
|
||||
timestamp: 2025-10-22T10:30:00Z
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 스키마 정의
|
||||
|
||||
### 8.1 스키마 명명 규칙
|
||||
|
||||
**Request 스키마:**
|
||||
```
|
||||
{Action}{Resource}Request
|
||||
```
|
||||
예: `RegisterRequest`, `LoginRequest`, `CreateEventRequest`
|
||||
|
||||
**Response 스키마:**
|
||||
```
|
||||
{Resource}{Type}Response
|
||||
```
|
||||
예: `UserProfileResponse`, `EventListResponse`, `EventDetailResponse`
|
||||
|
||||
**공통 모델:**
|
||||
```
|
||||
{Resource}{Type}
|
||||
```
|
||||
예: `EventSummary`, `GeneratedImage`, `PageInfo`
|
||||
|
||||
### 8.2 스키마 작성 원칙
|
||||
|
||||
**필수 항목:**
|
||||
- `type`: 객체 타입 (object, array, string 등)
|
||||
- `required`: 필수 필드 목록
|
||||
- `properties`: 각 필드 정의
|
||||
- `type`: 필드 타입
|
||||
- `description`: 필드 설명 (한글)
|
||||
- `example`: 예시 값
|
||||
|
||||
**선택 항목:**
|
||||
- `format`: 특수 형식 (date, date-time, email, uri, uuid, int64 등)
|
||||
- `pattern`: 정규식 패턴 (전화번호, 사업자번호 등)
|
||||
- `minLength`, `maxLength`: 문자열 길이 제한
|
||||
- `minimum`, `maximum`: 숫자 범위 제한
|
||||
- `enum`: 허용 값 목록
|
||||
|
||||
**예시:**
|
||||
```yaml
|
||||
RegisterRequest:
|
||||
type: object
|
||||
required:
|
||||
- name
|
||||
- phoneNumber
|
||||
- email
|
||||
- password
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
minLength: 2
|
||||
maxLength: 50
|
||||
description: 사용자 이름 (2자 이상, 한글/영문)
|
||||
example: 홍길동
|
||||
phoneNumber:
|
||||
type: string
|
||||
pattern: '^010\d{8}$'
|
||||
description: 휴대폰 번호 (010XXXXXXXX)
|
||||
example: "01012345678"
|
||||
email:
|
||||
type: string
|
||||
format: email
|
||||
maxLength: 100
|
||||
description: 이메일 주소
|
||||
example: hong@example.com
|
||||
password:
|
||||
type: string
|
||||
minLength: 8
|
||||
maxLength: 100
|
||||
description: 비밀번호 (8자 이상, 영문/숫자/특수문자 포함)
|
||||
example: "Password123!"
|
||||
```
|
||||
|
||||
### 8.3 날짜/시간 형식
|
||||
|
||||
**날짜:** `format: date`, 형식 `YYYY-MM-DD`
|
||||
```yaml
|
||||
startDate:
|
||||
type: string
|
||||
format: date
|
||||
description: 시작일
|
||||
example: "2025-03-01"
|
||||
```
|
||||
|
||||
**날짜/시간:** `format: date-time`, 형식 `ISO 8601`
|
||||
```yaml
|
||||
createdAt:
|
||||
type: string
|
||||
format: date-time
|
||||
description: 생성일시
|
||||
example: 2025-10-22T10:30:00Z
|
||||
```
|
||||
|
||||
### 8.4 ID 형식
|
||||
|
||||
**UUID:**
|
||||
```yaml
|
||||
eventId:
|
||||
type: string
|
||||
format: uuid
|
||||
description: 이벤트 ID
|
||||
example: "550e8400-e29b-41d4-a716-446655440000"
|
||||
```
|
||||
|
||||
**정수 ID:**
|
||||
```yaml
|
||||
userId:
|
||||
type: integer
|
||||
format: int64
|
||||
description: 사용자 ID
|
||||
example: 123
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 메타데이터 주석
|
||||
|
||||
### 9.1 필수 메타데이터
|
||||
```yaml
|
||||
x-user-story: {UFR 코드}
|
||||
x-controller: {ControllerClass}.{methodName}
|
||||
```
|
||||
|
||||
**x-user-story:**
|
||||
- 유저스토리 코드 명시
|
||||
- 여러 유저스토리와 관련된 경우 콤마로 구분
|
||||
- 예: `UFR-USER-010`, `UFR-EVENT-010, UFR-EVENT-070`
|
||||
|
||||
**x-controller:**
|
||||
- 컨트롤러 클래스와 메서드 매핑
|
||||
- 백엔드 개발 시 참조
|
||||
- 예: `UserController.registerUser`, `EventController.getEvents`
|
||||
|
||||
### 9.2 선택 메타데이터 (필요 시)
|
||||
```yaml
|
||||
x-internal: true # 내부 API 표시
|
||||
x-async: true # 비동기 처리 표시
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. 기술 명세 섹션
|
||||
|
||||
### 10.1 x-technical-specifications
|
||||
|
||||
**비동기 처리 서비스 (AI, Content 등):**
|
||||
```yaml
|
||||
x-technical-specifications:
|
||||
async-processing:
|
||||
message-queue: Kafka
|
||||
topics:
|
||||
request: ai.recommendation.request
|
||||
response: ai.recommendation.response
|
||||
job-tracking: Redis (TTL 24h)
|
||||
timeout: 300s
|
||||
|
||||
resilience:
|
||||
circuit-breaker:
|
||||
failure-threshold: 5
|
||||
timeout: 10s
|
||||
half-open-requests: 3
|
||||
retry:
|
||||
max-attempts: 3
|
||||
backoff: exponential
|
||||
initial-interval: 1s
|
||||
max-interval: 10s
|
||||
fallback:
|
||||
strategy: cached-result
|
||||
|
||||
caching:
|
||||
provider: Redis
|
||||
ttl: 7d
|
||||
key-pattern: "content:event:{eventDraftId}"
|
||||
|
||||
external-apis:
|
||||
- name: Claude API
|
||||
endpoint: https://api.anthropic.com/v1/messages
|
||||
timeout: 60s
|
||||
circuit-breaker: true
|
||||
- name: GPT-4 API
|
||||
endpoint: https://api.openai.com/v1/chat/completions
|
||||
timeout: 60s
|
||||
circuit-breaker: true
|
||||
```
|
||||
|
||||
**동기 처리 서비스:**
|
||||
```yaml
|
||||
x-technical-specifications:
|
||||
database:
|
||||
type: PostgreSQL
|
||||
connection-pool:
|
||||
min: 10
|
||||
max: 50
|
||||
timeout: 30s
|
||||
|
||||
caching:
|
||||
provider: Redis
|
||||
ttl: 30m
|
||||
key-pattern: "user:{userId}"
|
||||
|
||||
security:
|
||||
authentication: JWT Bearer
|
||||
password-hashing: bcrypt
|
||||
encryption:
|
||||
algorithm: AES-256-GCM
|
||||
fields: [businessNumber]
|
||||
```
|
||||
|
||||
### 10.2 적용 기준
|
||||
|
||||
**필수 포함 서비스:**
|
||||
- Content Service: 비동기 처리, Kafka, 외부 API 통합
|
||||
- AI Service: 비동기 처리, Kafka, Claude/GPT 통합
|
||||
|
||||
**선택 포함 서비스:**
|
||||
- User Service: 보안 관련 명세
|
||||
- Event Service: 오케스트레이션 패턴
|
||||
- Participation Service: 대용량 트래픽 대비 캐싱
|
||||
|
||||
---
|
||||
|
||||
## 11. 예제 작성
|
||||
|
||||
### 11.1 Request/Response 예제 원칙
|
||||
|
||||
**모든 requestBody와 주요 response에 예제 필수:**
|
||||
```yaml
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RegisterRequest'
|
||||
examples:
|
||||
restaurant:
|
||||
summary: 음식점 회원가입 예시
|
||||
value:
|
||||
name: 홍길동
|
||||
phoneNumber: "01012345678"
|
||||
email: hong@example.com
|
||||
password: "Password123!"
|
||||
storeName: 맛있는집
|
||||
industry: 음식점
|
||||
cafe:
|
||||
summary: 카페 회원가입 예시
|
||||
value:
|
||||
name: 김철수
|
||||
phoneNumber: "01087654321"
|
||||
email: kim@example.com
|
||||
password: "SecurePass456!"
|
||||
storeName: 아메리카노 카페
|
||||
industry: 카페
|
||||
```
|
||||
|
||||
**성공 응답 예제:**
|
||||
```yaml
|
||||
responses:
|
||||
'200':
|
||||
description: 프로필 조회 성공
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ProfileResponse'
|
||||
examples:
|
||||
success:
|
||||
summary: 프로필 조회 성공 응답
|
||||
value:
|
||||
userId: 123
|
||||
userName: 홍길동
|
||||
phoneNumber: "01012345678"
|
||||
email: hong@example.com
|
||||
```
|
||||
|
||||
**에러 응답 예제:**
|
||||
```yaml
|
||||
responses:
|
||||
'400':
|
||||
description: 잘못된 요청
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
examples:
|
||||
duplicateUser:
|
||||
summary: 중복 사용자
|
||||
value:
|
||||
code: USER_001
|
||||
message: 이미 가입된 전화번호입니다
|
||||
timestamp: 2025-10-22T10:30:00Z
|
||||
invalidBusinessNumber:
|
||||
summary: 사업자번호 검증 실패
|
||||
value:
|
||||
code: USER_002
|
||||
message: 유효하지 않은 사업자번호입니다
|
||||
timestamp: 2025-10-22T10:30:00Z
|
||||
```
|
||||
|
||||
### 11.2 예제 명명 규칙
|
||||
- `success`: 성공 케이스
|
||||
- `{errorType}`: 에러 케이스 (예: `duplicateUser`, `validationError`)
|
||||
- `{scenario}`: 시나리오별 예제 (예: `restaurant`, `cafe`)
|
||||
|
||||
---
|
||||
|
||||
## 12. 체크리스트
|
||||
|
||||
API 명세서 작성 시 아래 체크리스트를 확인하세요:
|
||||
|
||||
### 기본 정보
|
||||
- [ ] OpenAPI 버전 3.0.3 명시
|
||||
- [ ] info.title에 서비스명 포함
|
||||
- [ ] info.description에 주요 기능 목록 포함
|
||||
- [ ] info.version 1.0.0
|
||||
- [ ] contact 정보 포함
|
||||
|
||||
### 서버 및 보안
|
||||
- [ ] servers에 Local, Dev, Prod 정의
|
||||
- [ ] 포트 번호 정확히 할당
|
||||
- [ ] components.securitySchemes에 BearerAuth 정의
|
||||
- [ ] 인증 필요한 엔드포인트에 security 적용
|
||||
|
||||
### 엔드포인트
|
||||
- [ ] 모든 엔드포인트에 tags 지정
|
||||
- [ ] summary와 description 작성 (한글)
|
||||
- [ ] operationId camelCase로 작성
|
||||
- [ ] x-user-story UFR 코드 명시
|
||||
- [ ] x-controller 매핑 정보 포함
|
||||
|
||||
### 스키마
|
||||
- [ ] Request/Response 스키마 명명 규칙 준수
|
||||
- [ ] required 필드 명시
|
||||
- [ ] 모든 properties에 description과 example 포함
|
||||
- [ ] 적절한 format 사용 (date, date-time, email, uuid 등)
|
||||
|
||||
### 응답 구조
|
||||
- [ ] ErrorResponse 표준 스키마 사용
|
||||
- [ ] 공통 에러 응답 ($ref) 활용
|
||||
- [ ] 에러 코드 명명 규칙 준수
|
||||
- [ ] 페이징 응답에 PageInfo 사용
|
||||
|
||||
### 예제
|
||||
- [ ] requestBody에 최소 1개 이상 예제
|
||||
- [ ] 주요 response에 success 예제
|
||||
- [ ] 주요 에러 케이스에 예제
|
||||
|
||||
### 기술 명세 (해당 시)
|
||||
- [ ] 비동기 처리 서비스: x-technical-specifications 포함
|
||||
- [ ] Kafka 토픽, Redis 캐싱 정보 명시
|
||||
- [ ] 외부 API 연동 정보 포함
|
||||
|
||||
---
|
||||
|
||||
## 13. 참고 자료
|
||||
|
||||
### 서비스별 API 명세서
|
||||
- User Service API: `/design/backend/api/user-service-api.yaml`
|
||||
- Event Service API: `/design/backend/api/event-service-api.yaml`
|
||||
- Content Service API: `/design/backend/api/content-service-api.yaml`
|
||||
- AI Service API: `/design/backend/api/ai-service-api.yaml`
|
||||
- Participation Service API: `/design/backend/api/participation-service-api.yaml`
|
||||
- Distribution Service API: `/design/backend/api/distribution-service-api.yaml`
|
||||
- Analytics Service API: `/design/backend/api/analytics-service-api.yaml`
|
||||
|
||||
### OpenAPI 3.0.3 공식 문서
|
||||
- https://swagger.io/specification/
|
||||
|
||||
### 프로젝트 아키텍처
|
||||
- High-Level Architecture: `/design/high-level-architecture.md`
|
||||
- Logical Architecture: `/design/backend/logical/`
|
||||
|
||||
---
|
||||
|
||||
**문서 버전:** 1.0.0
|
||||
**최종 수정일:** 2025-10-23
|
||||
**작성자:** Digital Garage Team
|
||||
@ -24,14 +24,16 @@ info:
|
||||
|
||||
version: 1.0.0
|
||||
contact:
|
||||
name: Backend Architect
|
||||
email: architect@kt.com
|
||||
name: Digital Garage Team
|
||||
email: support@kt-event-marketing.com
|
||||
|
||||
servers:
|
||||
- url: http://localhost:8083
|
||||
description: Local Development Server
|
||||
- url: http://ai-service:8083
|
||||
description: Kubernetes Internal Service
|
||||
- url: https://dev-api.kt-event-marketing.com/ai/v1
|
||||
description: Development Server
|
||||
- url: https://api.kt-event-marketing.com/ai/v1
|
||||
description: Production Server
|
||||
|
||||
tags:
|
||||
- name: Health Check
|
||||
|
||||
@ -27,15 +27,15 @@ info:
|
||||
- Real-time updates via Kafka event subscription
|
||||
version: 1.0.0
|
||||
contact:
|
||||
name: Analytics Service Team
|
||||
email: analytics@kt-event.com
|
||||
name: Digital Garage Team
|
||||
email: support@kt-event-marketing.com
|
||||
|
||||
servers:
|
||||
- url: http://localhost:8086
|
||||
description: Local Development Server
|
||||
- url: https://api-dev.kt-event.com/analytics
|
||||
- url: https://dev-api.kt-event-marketing.com/analytics/v1
|
||||
description: Development Server
|
||||
- url: https://api.kt-event.com/analytics
|
||||
- url: https://api.kt-event-marketing.com/analytics/v1
|
||||
description: Production Server
|
||||
|
||||
tags:
|
||||
@ -49,7 +49,7 @@ tags:
|
||||
description: 투자 대비 수익률 분석 API
|
||||
|
||||
paths:
|
||||
/api/events/{eventId}/analytics:
|
||||
/events/{eventId}/analytics:
|
||||
get:
|
||||
tags:
|
||||
- Analytics
|
||||
@ -115,7 +115,7 @@ paths:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
|
||||
/api/events/{eventId}/analytics/channels:
|
||||
/events/{eventId}/analytics/channels:
|
||||
get:
|
||||
tags:
|
||||
- Channels
|
||||
@ -188,7 +188,7 @@ paths:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
|
||||
/api/events/{eventId}/analytics/timeline:
|
||||
/events/{eventId}/analytics/timeline:
|
||||
get:
|
||||
tags:
|
||||
- Timeline
|
||||
@ -264,7 +264,7 @@ paths:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
|
||||
/api/events/{eventId}/analytics/roi:
|
||||
/events/{eventId}/analytics/roi:
|
||||
get:
|
||||
tags:
|
||||
- ROI
|
||||
|
||||
@ -41,15 +41,15 @@ info:
|
||||
- CDN URL 반환
|
||||
|
||||
contact:
|
||||
name: Content Service Team
|
||||
email: content-team@kt.com
|
||||
name: Digital Garage Team
|
||||
email: support@kt-event-marketing.com
|
||||
|
||||
servers:
|
||||
- url: http://localhost:8083
|
||||
description: Content Service Local Development Server
|
||||
- url: https://api-dev.kt-event.com
|
||||
- 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.com
|
||||
- url: https://api.kt-event-marketing.com/content/v1
|
||||
description: Production Server
|
||||
|
||||
tags:
|
||||
@ -61,7 +61,7 @@ tags:
|
||||
description: 이미지 재생성 및 삭제 (UFR-CONT-020)
|
||||
|
||||
paths:
|
||||
/api/content/images/generate:
|
||||
/content/images/generate:
|
||||
post:
|
||||
tags:
|
||||
- Job Status
|
||||
@ -71,7 +71,7 @@ paths:
|
||||
|
||||
## 처리 방식
|
||||
- **비동기 처리**: Kafka `image-generation-job` 토픽에 Job 발행
|
||||
- **폴링 조회**: jobId로 생성 상태 조회 (GET /api/content/images/jobs/{jobId})
|
||||
- **폴링 조회**: jobId로 생성 상태 조회 (GET /content/images/jobs/{jobId})
|
||||
- **캐싱**: 동일한 eventDraftId 재요청 시 캐시 반환 (TTL 7일)
|
||||
|
||||
## 생성 스타일
|
||||
@ -91,7 +91,7 @@ paths:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ImageGenerationRequest'
|
||||
$ref: "#/components/schemas/ImageGenerationRequest"
|
||||
examples:
|
||||
basicEvent:
|
||||
summary: 기본 이벤트
|
||||
@ -112,14 +112,14 @@ paths:
|
||||
brandColor: "#00704A"
|
||||
|
||||
responses:
|
||||
'202':
|
||||
"202":
|
||||
description: |
|
||||
이미지 생성 요청이 성공적으로 접수되었습니다.
|
||||
jobId를 사용하여 생성 상태를 폴링 조회하세요.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ImageGenerationAcceptedResponse'
|
||||
$ref: "#/components/schemas/ImageGenerationAcceptedResponse"
|
||||
examples:
|
||||
accepted:
|
||||
summary: 요청 접수 성공
|
||||
@ -130,12 +130,12 @@ paths:
|
||||
estimatedCompletionTime: 5
|
||||
message: "이미지 생성 요청이 접수되었습니다. jobId로 결과를 조회하세요."
|
||||
|
||||
'400':
|
||||
"400":
|
||||
description: 잘못된 요청 (필수 필드 누락, 유효하지 않은 데이터)
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
examples:
|
||||
missingField:
|
||||
summary: 필수 필드 누락
|
||||
@ -150,12 +150,12 @@ paths:
|
||||
message: "brandColor는 HEX 색상 코드 형식이어야 합니다."
|
||||
timestamp: "2025-10-22T14:30:00Z"
|
||||
|
||||
'429':
|
||||
"429":
|
||||
description: 요청 제한 초과 (Rate Limiting)
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
examples:
|
||||
rateLimitExceeded:
|
||||
summary: 요청 제한 초과
|
||||
@ -165,12 +165,12 @@ paths:
|
||||
timestamp: "2025-10-22T14:30:00Z"
|
||||
retryAfter: 60
|
||||
|
||||
'500':
|
||||
"500":
|
||||
description: 서버 내부 오류
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
examples:
|
||||
internalError:
|
||||
summary: 서버 내부 오류
|
||||
@ -182,7 +182,7 @@ paths:
|
||||
security:
|
||||
- BearerAuth: []
|
||||
|
||||
/api/content/images/jobs/{jobId}:
|
||||
/content/images/jobs/{jobId}:
|
||||
get:
|
||||
tags:
|
||||
- Job Status
|
||||
@ -218,12 +218,12 @@ paths:
|
||||
example: "job-img-abc123"
|
||||
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
description: 이미지 생성 상태 조회 성공
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ImageGenerationStatusResponse'
|
||||
$ref: "#/components/schemas/ImageGenerationStatusResponse"
|
||||
examples:
|
||||
pending:
|
||||
summary: 대기 중
|
||||
@ -308,12 +308,12 @@ paths:
|
||||
detail: "외부 AI API 응답 시간 초과. 기본 템플릿으로 대체되었습니다."
|
||||
completedAt: "2025-10-22T14:30:25Z"
|
||||
|
||||
'404':
|
||||
"404":
|
||||
description: Job ID를 찾을 수 없음
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
examples:
|
||||
notFound:
|
||||
summary: Job ID 없음
|
||||
@ -322,12 +322,12 @@ paths:
|
||||
message: "Job ID를 찾을 수 없습니다."
|
||||
timestamp: "2025-10-22T14:30:00Z"
|
||||
|
||||
'500':
|
||||
"500":
|
||||
description: 서버 내부 오류
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
examples:
|
||||
internalError:
|
||||
summary: 서버 내부 오류
|
||||
@ -339,7 +339,7 @@ paths:
|
||||
security:
|
||||
- BearerAuth: []
|
||||
|
||||
/api/content/events/{eventDraftId}:
|
||||
/content/events/{eventDraftId}:
|
||||
get:
|
||||
tags:
|
||||
- Content Management
|
||||
@ -363,12 +363,12 @@ paths:
|
||||
example: "evt-draft-12345"
|
||||
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
description: 콘텐츠 조회 성공
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ContentResponse'
|
||||
$ref: "#/components/schemas/ContentResponse"
|
||||
examples:
|
||||
success:
|
||||
summary: 콘텐츠 조회 성공
|
||||
@ -403,12 +403,12 @@ paths:
|
||||
createdAt: "2025-10-22T14:30:00Z"
|
||||
expiresAt: "2025-10-29T14:30:00Z"
|
||||
|
||||
'404':
|
||||
"404":
|
||||
description: 콘텐츠를 찾을 수 없음 (생성 중이거나 만료됨)
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
examples:
|
||||
notFound:
|
||||
summary: 콘텐츠 없음
|
||||
@ -417,17 +417,17 @@ paths:
|
||||
message: "해당 이벤트의 콘텐츠를 찾을 수 없습니다."
|
||||
timestamp: "2025-10-22T14:30:00Z"
|
||||
|
||||
'500':
|
||||
"500":
|
||||
description: 서버 내부 오류
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
|
||||
security:
|
||||
- BearerAuth: []
|
||||
|
||||
/api/content/events/{eventDraftId}/images:
|
||||
/content/events/{eventDraftId}/images:
|
||||
get:
|
||||
tags:
|
||||
- Content Management
|
||||
@ -465,7 +465,7 @@ paths:
|
||||
example: "INSTAGRAM"
|
||||
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
description: 이미지 목록 조회 성공
|
||||
content:
|
||||
application/json:
|
||||
@ -479,7 +479,7 @@ paths:
|
||||
images:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/GeneratedImage'
|
||||
$ref: "#/components/schemas/GeneratedImage"
|
||||
examples:
|
||||
allImages:
|
||||
summary: 전체 이미지 조회
|
||||
@ -496,17 +496,17 @@ paths:
|
||||
height: 1080
|
||||
createdAt: "2025-10-22T14:30:05Z"
|
||||
|
||||
'404':
|
||||
"404":
|
||||
description: 이미지를 찾을 수 없음
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
|
||||
security:
|
||||
- BearerAuth: []
|
||||
|
||||
/api/content/images/{imageId}:
|
||||
/content/images/{imageId}:
|
||||
get:
|
||||
tags:
|
||||
- Image Management
|
||||
@ -526,12 +526,12 @@ paths:
|
||||
example: "img-12345-simple"
|
||||
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
description: 이미지 조회 성공
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GeneratedImage'
|
||||
$ref: "#/components/schemas/GeneratedImage"
|
||||
examples:
|
||||
success:
|
||||
summary: 이미지 조회 성공
|
||||
@ -545,12 +545,12 @@ paths:
|
||||
height: 1080
|
||||
createdAt: "2025-10-22T14:30:05Z"
|
||||
|
||||
'404':
|
||||
"404":
|
||||
description: 이미지를 찾을 수 없음
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
|
||||
security:
|
||||
- BearerAuth: []
|
||||
@ -577,20 +577,20 @@ paths:
|
||||
example: "img-12345-simple"
|
||||
|
||||
responses:
|
||||
'204':
|
||||
"204":
|
||||
description: 이미지 삭제 성공
|
||||
|
||||
'404':
|
||||
"404":
|
||||
description: 이미지를 찾을 수 없음
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
|
||||
security:
|
||||
- BearerAuth: []
|
||||
|
||||
/api/content/images/{imageId}/regenerate:
|
||||
/content/images/{imageId}/regenerate:
|
||||
post:
|
||||
tags:
|
||||
- Image Management
|
||||
@ -619,7 +619,7 @@ paths:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ImageRegenerationRequest'
|
||||
$ref: "#/components/schemas/ImageRegenerationRequest"
|
||||
examples:
|
||||
modifyPrompt:
|
||||
summary: 프롬프트 수정
|
||||
@ -631,7 +631,7 @@ paths:
|
||||
style: "FANCY"
|
||||
|
||||
responses:
|
||||
'202':
|
||||
"202":
|
||||
description: 재생성 요청 접수 (비동기 처리)
|
||||
content:
|
||||
application/json:
|
||||
@ -653,19 +653,19 @@ paths:
|
||||
description: 예상 소요 시간 (초)
|
||||
example: 10
|
||||
|
||||
'404':
|
||||
"404":
|
||||
description: 원본 이미지를 찾을 수 없음
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
|
||||
'503':
|
||||
"503":
|
||||
description: 이미지 생성 서비스 장애 (Circuit Breaker Open)
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/CircuitBreakerErrorResponse'
|
||||
$ref: "#/components/schemas/CircuitBreakerErrorResponse"
|
||||
|
||||
security:
|
||||
- BearerAuth: []
|
||||
@ -723,7 +723,7 @@ components:
|
||||
brandColor:
|
||||
type: string
|
||||
description: 브랜드 컬러 (HEX)
|
||||
pattern: '^#[0-9A-Fa-f]{6}$'
|
||||
pattern: "^#[0-9A-Fa-f]{6}$"
|
||||
example: "#FF5733"
|
||||
logoUrl:
|
||||
type: string
|
||||
@ -801,7 +801,7 @@ components:
|
||||
description: |
|
||||
브랜드 컬러 (HEX 색상 코드)
|
||||
사용자 프로필에서 가져오거나 기본값 사용
|
||||
pattern: '^#[0-9A-Fa-f]{6}$'
|
||||
pattern: "^#[0-9A-Fa-f]{6}$"
|
||||
example: "#FF5733"
|
||||
|
||||
logoUrl:
|
||||
@ -883,7 +883,7 @@ components:
|
||||
type: array
|
||||
description: 생성된 이미지 배열 (COMPLETED 상태에서만)
|
||||
items:
|
||||
$ref: '#/components/schemas/GeneratedImage'
|
||||
$ref: "#/components/schemas/GeneratedImage"
|
||||
|
||||
completedAt:
|
||||
type: string
|
||||
@ -897,7 +897,7 @@ components:
|
||||
example: false
|
||||
|
||||
error:
|
||||
$ref: '#/components/schemas/JobError'
|
||||
$ref: "#/components/schemas/JobError"
|
||||
|
||||
GeneratedImage:
|
||||
type: object
|
||||
@ -1016,7 +1016,7 @@ components:
|
||||
type: array
|
||||
description: 생성된 이미지 목록
|
||||
items:
|
||||
$ref: '#/components/schemas/ImageDetail'
|
||||
$ref: "#/components/schemas/ImageDetail"
|
||||
|
||||
totalCount:
|
||||
type: integer
|
||||
|
||||
@ -24,18 +24,16 @@ info:
|
||||
|
||||
version: 1.0.0
|
||||
contact:
|
||||
name: Backend Development Team
|
||||
email: backend@kt-event-marketing.com
|
||||
name: Digital Garage Team
|
||||
email: support@kt-event-marketing.com
|
||||
|
||||
servers:
|
||||
- url: http://localhost:8083
|
||||
- url: http://localhost:8085
|
||||
description: Local Development Server
|
||||
- url: http://distribution-service:8083
|
||||
description: Docker/Kubernetes Service
|
||||
- url: https://api-dev.kt-event-marketing.com/distribution
|
||||
description: Development Environment
|
||||
- url: https://api.kt-event-marketing.com/distribution
|
||||
description: Production Environment
|
||||
- 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
|
||||
@ -44,7 +42,7 @@ tags:
|
||||
description: 배포 상태 모니터링
|
||||
|
||||
paths:
|
||||
/api/distribution/distribute:
|
||||
/distribution/distribute:
|
||||
post:
|
||||
tags:
|
||||
- Distribution
|
||||
@ -174,7 +172,7 @@ paths:
|
||||
message: "배포 처리 중 오류가 발생했습니다"
|
||||
timestamp: "2025-11-01T09:00:00Z"
|
||||
|
||||
/api/distribution/{eventId}/status:
|
||||
/distribution/{eventId}/status:
|
||||
get:
|
||||
tags:
|
||||
- Monitoring
|
||||
|
||||
@ -11,19 +11,19 @@ info:
|
||||
- 이벤트 상태 관리 (DRAFT, PUBLISHED, ENDED)
|
||||
version: 1.0.0
|
||||
contact:
|
||||
name: Event Service Team
|
||||
email: event-service@kt.com
|
||||
name: Digital Garage Team
|
||||
email: support@kt-event-marketing.com
|
||||
|
||||
servers:
|
||||
- url: http://localhost:8080
|
||||
description: Local development server
|
||||
- url: https://api-dev.kt-event.com
|
||||
description: Development server
|
||||
- url: https://api.kt-event.com
|
||||
description: Production server
|
||||
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: []
|
||||
- BearerAuth: []
|
||||
|
||||
tags:
|
||||
- name: Dashboard
|
||||
@ -36,7 +36,7 @@ tags:
|
||||
description: 비동기 작업 상태 조회
|
||||
|
||||
paths:
|
||||
/api/events:
|
||||
/events:
|
||||
get:
|
||||
tags:
|
||||
- Dashboard
|
||||
@ -119,7 +119,7 @@ paths:
|
||||
'500':
|
||||
$ref: '#/components/responses/InternalServerError'
|
||||
|
||||
/api/events/{eventId}:
|
||||
/events/{eventId}:
|
||||
get:
|
||||
tags:
|
||||
- Dashboard
|
||||
@ -223,7 +223,7 @@ paths:
|
||||
'500':
|
||||
$ref: '#/components/responses/InternalServerError'
|
||||
|
||||
/api/events/objectives:
|
||||
/events/objectives:
|
||||
post:
|
||||
tags:
|
||||
- Event Creation
|
||||
@ -254,7 +254,7 @@ paths:
|
||||
'500':
|
||||
$ref: '#/components/responses/InternalServerError'
|
||||
|
||||
/api/events/{eventId}/ai-recommendations:
|
||||
/events/{eventId}/ai-recommendations:
|
||||
post:
|
||||
tags:
|
||||
- Event Creation
|
||||
@ -262,7 +262,7 @@ paths:
|
||||
description: |
|
||||
AI 서비스에 이벤트 추천 생성을 요청합니다.
|
||||
Kafka Job을 발행하고 jobId를 반환합니다.
|
||||
Job 상태는 /api/jobs/{jobId}로 폴링하여 확인합니다.
|
||||
Job 상태는 /jobs/{jobId}로 폴링하여 확인합니다.
|
||||
operationId: requestAiRecommendations
|
||||
x-user-story: UFR-EVENT-030
|
||||
x-controller: EventController.requestAiRecommendations
|
||||
@ -299,7 +299,7 @@ paths:
|
||||
'500':
|
||||
$ref: '#/components/responses/InternalServerError'
|
||||
|
||||
/api/events/{eventId}/recommendations:
|
||||
/events/{eventId}/recommendations:
|
||||
put:
|
||||
tags:
|
||||
- Event Creation
|
||||
@ -343,7 +343,7 @@ paths:
|
||||
'500':
|
||||
$ref: '#/components/responses/InternalServerError'
|
||||
|
||||
/api/events/{eventId}/images:
|
||||
/events/{eventId}/images:
|
||||
post:
|
||||
tags:
|
||||
- Event Creation
|
||||
@ -351,7 +351,7 @@ paths:
|
||||
description: |
|
||||
Content Service에 이미지 생성을 요청합니다.
|
||||
Kafka Job을 발행하고 jobId를 반환합니다.
|
||||
Job 상태는 /api/jobs/{jobId}로 폴링하여 확인합니다.
|
||||
Job 상태는 /jobs/{jobId}로 폴링하여 확인합니다.
|
||||
operationId: requestImageGeneration
|
||||
x-user-story: UFR-CONT-010
|
||||
x-controller: EventController.requestImageGeneration
|
||||
@ -388,7 +388,7 @@ paths:
|
||||
'500':
|
||||
$ref: '#/components/responses/InternalServerError'
|
||||
|
||||
/api/events/{eventId}/images/{imageId}/select:
|
||||
/events/{eventId}/images/{imageId}/select:
|
||||
put:
|
||||
tags:
|
||||
- Event Creation
|
||||
@ -432,7 +432,7 @@ paths:
|
||||
'500':
|
||||
$ref: '#/components/responses/InternalServerError'
|
||||
|
||||
/api/events/{eventId}/images/{imageId}/edit:
|
||||
/events/{eventId}/images/{imageId}/edit:
|
||||
put:
|
||||
tags:
|
||||
- Event Creation
|
||||
@ -484,7 +484,7 @@ paths:
|
||||
'500':
|
||||
$ref: '#/components/responses/InternalServerError'
|
||||
|
||||
/api/events/{eventId}/channels:
|
||||
/events/{eventId}/channels:
|
||||
put:
|
||||
tags:
|
||||
- Event Creation
|
||||
@ -528,7 +528,7 @@ paths:
|
||||
'500':
|
||||
$ref: '#/components/responses/InternalServerError'
|
||||
|
||||
/api/events/{eventId}/publish:
|
||||
/events/{eventId}/publish:
|
||||
post:
|
||||
tags:
|
||||
- Event Creation
|
||||
@ -575,7 +575,7 @@ paths:
|
||||
code: DISTRIBUTION_SERVICE_UNAVAILABLE
|
||||
message: 배포 서비스를 일시적으로 사용할 수 없습니다.
|
||||
|
||||
/api/events/{eventId}/end:
|
||||
/events/{eventId}/end:
|
||||
post:
|
||||
tags:
|
||||
- Event Management
|
||||
@ -622,7 +622,7 @@ paths:
|
||||
'500':
|
||||
$ref: '#/components/responses/InternalServerError'
|
||||
|
||||
/api/jobs/{jobId}:
|
||||
/jobs/{jobId}:
|
||||
get:
|
||||
tags:
|
||||
- Job Status
|
||||
@ -659,11 +659,22 @@ paths:
|
||||
|
||||
components:
|
||||
securitySchemes:
|
||||
bearerAuth:
|
||||
BearerAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: JWT
|
||||
description: JWT 토큰 인증
|
||||
description: |
|
||||
JWT Bearer 토큰 인증
|
||||
|
||||
**형식:** Authorization: Bearer {JWT_TOKEN}
|
||||
|
||||
**토큰 만료:** 7일
|
||||
|
||||
**Claims:**
|
||||
- userId: 사용자 ID
|
||||
- role: 사용자 역할 (OWNER)
|
||||
- iat: 발급 시각
|
||||
- exp: 만료 시각
|
||||
|
||||
parameters:
|
||||
EventId:
|
||||
@ -987,7 +998,7 @@ components:
|
||||
message:
|
||||
type: string
|
||||
description: 안내 메시지
|
||||
example: "AI 추천 생성 요청이 접수되었습니다. /api/jobs/{jobId}로 상태를 확인하세요."
|
||||
example: "AI 추천 생성 요청이 접수되었습니다. /jobs/{jobId}로 상태를 확인하세요."
|
||||
required:
|
||||
- jobId
|
||||
- status
|
||||
@ -1289,6 +1300,10 @@ components:
|
||||
|
||||
ErrorResponse:
|
||||
type: object
|
||||
required:
|
||||
- code
|
||||
- message
|
||||
- timestamp
|
||||
properties:
|
||||
code:
|
||||
type: string
|
||||
@ -1298,21 +1313,17 @@ components:
|
||||
type: string
|
||||
description: 에러 메시지
|
||||
example: "요청 파라미터가 올바르지 않습니다."
|
||||
details:
|
||||
type: array
|
||||
description: 상세 에러 정보
|
||||
items:
|
||||
type: string
|
||||
example: ["objective 필드는 필수입니다."]
|
||||
timestamp:
|
||||
type: string
|
||||
format: date-time
|
||||
description: 에러 발생 시각
|
||||
example: "2025-02-15T10:30:00Z"
|
||||
required:
|
||||
- code
|
||||
- message
|
||||
- timestamp
|
||||
details:
|
||||
type: array
|
||||
description: 상세 에러 정보 (선택 사항)
|
||||
items:
|
||||
type: string
|
||||
example: ["objective 필드는 필수입니다."]
|
||||
|
||||
responses:
|
||||
BadRequest:
|
||||
|
||||
@ -8,15 +8,15 @@ info:
|
||||
- 당첨자 추첨 및 관리
|
||||
version: 1.0.0
|
||||
contact:
|
||||
name: KT Event Marketing Team
|
||||
email: support@kt-event.com
|
||||
name: Digital Garage Team
|
||||
email: support@kt-event-marketing.com
|
||||
|
||||
servers:
|
||||
- url: http://localhost:8083
|
||||
- url: http://localhost:8084
|
||||
description: Local Development Server
|
||||
- url: https://api-dev.kt-event.com/participation
|
||||
- url: https://dev-api.kt-event-marketing.com/participation/v1
|
||||
description: Development Server
|
||||
- url: https://api.kt-event.com/participation
|
||||
- url: https://api.kt-event-marketing.com/participation/v1
|
||||
description: Production Server
|
||||
|
||||
tags:
|
||||
@ -28,7 +28,7 @@ tags:
|
||||
description: 당첨자 추첨 및 관리
|
||||
|
||||
paths:
|
||||
/api/events/{eventId}/participate:
|
||||
/events/{eventId}/participate:
|
||||
post:
|
||||
tags:
|
||||
- participation
|
||||
@ -146,7 +146,7 @@ paths:
|
||||
code: "EVENT_NOT_ACTIVE"
|
||||
message: "현재 참여할 수 없는 이벤트입니다"
|
||||
|
||||
/api/events/{eventId}/participants:
|
||||
/events/{eventId}/participants:
|
||||
get:
|
||||
tags:
|
||||
- participant
|
||||
@ -235,7 +235,7 @@ paths:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
|
||||
/api/events/{eventId}/participants/{participantId}:
|
||||
/events/{eventId}/participants/{participantId}:
|
||||
get:
|
||||
tags:
|
||||
- participant
|
||||
@ -300,7 +300,7 @@ paths:
|
||||
code: "PARTICIPANT_NOT_FOUND"
|
||||
message: "참여자를 찾을 수 없습니다"
|
||||
|
||||
/api/events/{eventId}/draw-winners:
|
||||
/events/{eventId}/draw-winners:
|
||||
post:
|
||||
tags:
|
||||
- winner
|
||||
@ -399,7 +399,7 @@ paths:
|
||||
code: "ALREADY_DRAWN"
|
||||
message: "이미 당첨자 추첨이 완료되었습니다"
|
||||
|
||||
/api/events/{eventId}/winners:
|
||||
/events/{eventId}/winners:
|
||||
get:
|
||||
tags:
|
||||
- winner
|
||||
|
||||
@ -22,14 +22,12 @@ info:
|
||||
email: support@kt-event-marketing.com
|
||||
|
||||
servers:
|
||||
- url: https://api.kt-event-marketing.com/user/v1
|
||||
description: Production Server
|
||||
- url: https://dev-api.kt-event-marketing.com/user/v1
|
||||
description: Development Server
|
||||
- url: https://virtserver.swaggerhub.com/kt-event-marketing/user-service/1.0.0
|
||||
description: SwaggerHub Mock Server
|
||||
- url: http://localhost:8081
|
||||
description: Local Development Server
|
||||
- url: https://dev-api.kt-event-marketing.com/user/v1
|
||||
description: Development Server
|
||||
- url: https://api.kt-event-marketing.com/user/v1
|
||||
description: Production Server
|
||||
|
||||
tags:
|
||||
- name: Authentication
|
||||
@ -38,7 +36,7 @@ tags:
|
||||
description: 프로필 관련 API (조회, 수정, 비밀번호 변경)
|
||||
|
||||
paths:
|
||||
/api/users/register:
|
||||
/users/register:
|
||||
post:
|
||||
tags:
|
||||
- Authentication
|
||||
@ -122,19 +120,19 @@ paths:
|
||||
summary: 중복 사용자
|
||||
value:
|
||||
code: USER_001
|
||||
error: 이미 가입된 전화번호입니다
|
||||
message: 이미 가입된 전화번호입니다
|
||||
timestamp: 2025-10-22T10:30:00Z
|
||||
invalidBusinessNumber:
|
||||
summary: 사업자번호 검증 실패
|
||||
value:
|
||||
code: USER_002
|
||||
error: 유효하지 않은 사업자번호입니다. 휴폐업 여부를 확인해주세요.
|
||||
message: 유효하지 않은 사업자번호입니다. 휴폐업 여부를 확인해주세요.
|
||||
timestamp: 2025-10-22T10:30:00Z
|
||||
validationError:
|
||||
summary: 입력 검증 오류
|
||||
value:
|
||||
code: VALIDATION_ERROR
|
||||
error: 비밀번호는 8자 이상이어야 합니다
|
||||
message: 비밀번호는 8자 이상이어야 합니다
|
||||
timestamp: 2025-10-22T10:30:00Z
|
||||
'500':
|
||||
description: 서버 오류
|
||||
@ -143,7 +141,7 @@ paths:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
|
||||
/api/users/login:
|
||||
/users/login:
|
||||
post:
|
||||
tags:
|
||||
- Authentication
|
||||
@ -205,10 +203,10 @@ paths:
|
||||
summary: 인증 실패
|
||||
value:
|
||||
code: AUTH_001
|
||||
error: 전화번호 또는 비밀번호를 확인해주세요
|
||||
message: 전화번호 또는 비밀번호를 확인해주세요
|
||||
timestamp: 2025-10-22T10:30:00Z
|
||||
|
||||
/api/users/logout:
|
||||
/users/logout:
|
||||
post:
|
||||
tags:
|
||||
- Authentication
|
||||
@ -257,10 +255,10 @@ paths:
|
||||
summary: 유효하지 않은 토큰
|
||||
value:
|
||||
code: AUTH_002
|
||||
error: 유효하지 않은 토큰입니다
|
||||
message: 유효하지 않은 토큰입니다
|
||||
timestamp: 2025-10-22T10:30:00Z
|
||||
|
||||
/api/users/profile:
|
||||
/users/profile:
|
||||
get:
|
||||
tags:
|
||||
- Profile
|
||||
@ -318,7 +316,7 @@ paths:
|
||||
summary: 사용자 없음
|
||||
value:
|
||||
code: USER_003
|
||||
error: 사용자를 찾을 수 없습니다
|
||||
message: 사용자를 찾을 수 없습니다
|
||||
timestamp: 2025-10-22T10:30:00Z
|
||||
|
||||
put:
|
||||
@ -335,7 +333,7 @@ paths:
|
||||
- 매장 정보: 매장명, 업종, 주소, 영업시간
|
||||
|
||||
**주의사항:**
|
||||
- 비밀번호 변경은 별도 API 사용 (/api/users/password)
|
||||
- 비밀번호 변경은 별도 API 사용 (/users/password)
|
||||
- 전화번호 변경 시 향후 재인증 필요 (현재는 직접 변경 가능)
|
||||
- Optimistic Locking으로 동시성 제어
|
||||
operationId: updateProfile
|
||||
@ -410,10 +408,10 @@ paths:
|
||||
summary: 동시성 충돌
|
||||
value:
|
||||
code: USER_005
|
||||
error: 다른 세션에서 프로필을 수정했습니다. 새로고침 후 다시 시도하세요
|
||||
message: 다른 세션에서 프로필을 수정했습니다. 새로고침 후 다시 시도하세요
|
||||
timestamp: 2025-10-22T10:30:00Z
|
||||
|
||||
/api/users/password:
|
||||
/users/password:
|
||||
put:
|
||||
tags:
|
||||
- Profile
|
||||
@ -472,13 +470,13 @@ paths:
|
||||
summary: 현재 비밀번호 불일치
|
||||
value:
|
||||
code: USER_004
|
||||
error: 현재 비밀번호가 일치하지 않습니다
|
||||
message: 현재 비밀번호가 일치하지 않습니다
|
||||
timestamp: 2025-10-22T10:30:00Z
|
||||
invalidNewPassword:
|
||||
summary: 새 비밀번호 규칙 위반
|
||||
value:
|
||||
code: VALIDATION_ERROR
|
||||
error: 비밀번호는 8자 이상이어야 하며 영문/숫자/특수문자를 포함해야 합니다
|
||||
message: 비밀번호는 8자 이상이어야 하며 영문/숫자/특수문자를 포함해야 합니다
|
||||
timestamp: 2025-10-22T10:30:00Z
|
||||
'401':
|
||||
description: 인증 실패
|
||||
@ -487,7 +485,7 @@ paths:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
|
||||
/api/users/{userId}/store:
|
||||
/users/{userId}/store:
|
||||
get:
|
||||
tags:
|
||||
- Profile
|
||||
@ -547,7 +545,7 @@ paths:
|
||||
summary: 인증 실패
|
||||
value:
|
||||
code: AUTH_002
|
||||
error: 유효하지 않은 토큰입니다
|
||||
message: 유효하지 않은 토큰입니다
|
||||
timestamp: 2025-10-22T10:30:00Z
|
||||
'403':
|
||||
description: 권한 없음 (내부 서비스만 접근 가능)
|
||||
@ -560,7 +558,7 @@ paths:
|
||||
summary: 권한 없음
|
||||
value:
|
||||
code: AUTH_003
|
||||
error: 이 API는 내부 서비스만 접근 가능합니다
|
||||
message: 이 API는 내부 서비스만 접근 가능합니다
|
||||
timestamp: 2025-10-22T10:30:00Z
|
||||
'404':
|
||||
description: 사용자 또는 매장을 찾을 수 없음
|
||||
@ -573,7 +571,7 @@ paths:
|
||||
summary: 사용자 또는 매장 없음
|
||||
value:
|
||||
code: USER_003
|
||||
error: 사용자 또는 매장을 찾을 수 없습니다
|
||||
message: 사용자 또는 매장을 찾을 수 없습니다
|
||||
timestamp: 2025-10-22T10:30:00Z
|
||||
'500':
|
||||
description: 서버 오류
|
||||
@ -983,7 +981,7 @@ components:
|
||||
type: object
|
||||
required:
|
||||
- code
|
||||
- error
|
||||
- message
|
||||
- timestamp
|
||||
properties:
|
||||
code:
|
||||
@ -1000,7 +998,7 @@ components:
|
||||
- AUTH_002 # 유효하지 않은 토큰
|
||||
- AUTH_003 # 권한 없음 (내부 서비스만 접근)
|
||||
- VALIDATION_ERROR # 입력 검증 오류
|
||||
error:
|
||||
message:
|
||||
type: string
|
||||
description: 에러 메시지
|
||||
example: 이미 가입된 전화번호입니다
|
||||
@ -1009,3 +1007,9 @@ components:
|
||||
format: date-time
|
||||
description: 에러 발생 시각
|
||||
example: 2025-10-22T10:30:00Z
|
||||
details:
|
||||
type: array
|
||||
description: 상세 에러 정보 (선택 사항)
|
||||
items:
|
||||
type: string
|
||||
example: ["필드명: 필수 항목입니다"]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user