From 6b1c4224f7cb90197ff0b9f80a61cca97245baa4 Mon Sep 17 00:00:00 2001 From: cherry2250 Date: Thu, 23 Oct 2025 17:12:28 +0900 Subject: [PATCH] =?UTF-8?q?7=EA=B0=9C=20=EB=A7=88=EC=9D=B4=ED=81=AC?= =?UTF-8?q?=EB=A1=9C=EC=84=9C=EB=B9=84=EC=8A=A4=20API=20=EB=AA=85=EC=84=B8?= =?UTF-8?q?=EC=84=9C=20=EC=BB=A8=EB=B2=A4=EC=85=98=20=ED=86=B5=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 공통 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 --- design/backend/api/API_CONVENTION.md | 914 ++++++++++++++++++ design/backend/api/ai-service-api.yaml | 10 +- design/backend/api/analytics-service-api.yaml | 16 +- design/backend/api/content-service-api.yaml | 112 +-- .../backend/api/distribution-service-api.yaml | 20 +- design/backend/api/event-service-api.yaml | 81 +- .../api/participation-service-api.yaml | 20 +- design/backend/api/user-service-api.yaml | 58 +- 8 files changed, 1080 insertions(+), 151 deletions(-) create mode 100644 design/backend/api/API_CONVENTION.md diff --git a/design/backend/api/API_CONVENTION.md b/design/backend/api/API_CONVENTION.md new file mode 100644 index 0000000..6c80671 --- /dev/null +++ b/design/backend/api/API_CONVENTION.md @@ -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 diff --git a/design/backend/api/ai-service-api.yaml b/design/backend/api/ai-service-api.yaml index ea2583f..b4ba555 100644 --- a/design/backend/api/ai-service-api.yaml +++ b/design/backend/api/ai-service-api.yaml @@ -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 diff --git a/design/backend/api/analytics-service-api.yaml b/design/backend/api/analytics-service-api.yaml index 6fb198a..6b0f234 100644 --- a/design/backend/api/analytics-service-api.yaml +++ b/design/backend/api/analytics-service-api.yaml @@ -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 diff --git a/design/backend/api/content-service-api.yaml b/design/backend/api/content-service-api.yaml index 46cada2..d8f9f45 100644 --- a/design/backend/api/content-service-api.yaml +++ b/design/backend/api/content-service-api.yaml @@ -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 diff --git a/design/backend/api/distribution-service-api.yaml b/design/backend/api/distribution-service-api.yaml index 9f8a8ae..938b3a8 100644 --- a/design/backend/api/distribution-service-api.yaml +++ b/design/backend/api/distribution-service-api.yaml @@ -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 diff --git a/design/backend/api/event-service-api.yaml b/design/backend/api/event-service-api.yaml index 3fe6652..c179b53 100644 --- a/design/backend/api/event-service-api.yaml +++ b/design/backend/api/event-service-api.yaml @@ -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: diff --git a/design/backend/api/participation-service-api.yaml b/design/backend/api/participation-service-api.yaml index 93db96c..645da39 100644 --- a/design/backend/api/participation-service-api.yaml +++ b/design/backend/api/participation-service-api.yaml @@ -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 diff --git a/design/backend/api/user-service-api.yaml b/design/backend/api/user-service-api.yaml index 29dd55e..75832d1 100644 --- a/design/backend/api/user-service-api.yaml +++ b/design/backend/api/user-service-api.yaml @@ -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: ["필드명: 필수 항목입니다"]