# 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
