---
name: api-doc-generator
description: |
  트리거: "API 문서 만들어줘", "swagger 생성", "openapi spec", "API 명세 작성", "readme api 섹션", "swagger yaml 만들어줘"
  수행: 코드(Controller/Router/ViewSet)를 분석하여 OpenAPI 3.0 YAML/JSON 명세와 README API 섹션을 자동 생성한다.
  엔드포인트별 경로·메서드·파라미터·요청/응답 스키마·에러 코드·인증 방식을 포함한다.
  출력: openapi.yaml + README.md API 섹션 마크다운.
---

# API 문서 자동 생성기

## 목적

기존 백엔드 코드(Spring Controller, FastAPI Router, DRF ViewSet)를 분석하여
OpenAPI 3.0 명세와 개발자 친화적인 README API 섹션을 자동 생성한다.
Swagger UI에서 바로 사용 가능한 YAML과 팀 협업용 마크다운을 동시에 출력한다.

## 실행 절차

1. **코드 분석**: 엔드포인트 경로, HTTP 메서드, 파라미터, 요청/응답 바디 타입 추출
2. **스키마 정의**: 요청/응답 DTO 또는 Pydantic/Serializer 클래스에서 컴포넌트 스키마 생성
3. **인증 방식 파악**: JWT Bearer, API Key, Basic Auth, OAuth2 등 확인
4. **에러 응답 정의**: 공통 에러 코드(400/401/403/404/409/422/500) 표준화
5. **OpenAPI YAML 생성**: `openapi: 3.0.3` 기준, info/servers/paths/components 구조
6. **README 마크다운 생성**: 엔드포인트 표, curl 예시, 응답 예시 포함
7. **Swagger 설정 안내**: Spring(springdoc-openapi), FastAPI(내장), Django(drf-spectacular) 설정법

## 출력 형식

### 1. openapi.yaml
```yaml
openapi: 3.0.3
info:
  title: API Name
  version: 1.0.0
servers:
  - url: https://api.example.com/v1
paths:
  /resource:
    get: ...
components:
  schemas: ...
  securitySchemes: ...
```

### 2. README.md API 섹션
```markdown
## API Reference
### Authentication
### Endpoints
| Method | Path | Description |
...
### Examples
```

## 사용 예시

### 입력 (Spring Boot Controller 코드)
```java
@RestController
@RequestMapping("/api/v1/users")
@RequiredArgsConstructor
public class UserController {
    @PostMapping
    public ResponseEntity<UserResponseDto> createUser(@Valid @RequestBody UserRequestDto dto) { ... }
    @GetMapping("/{id}")
    public ResponseEntity<UserResponseDto> getUser(@PathVariable Long id) { ... }
    @GetMapping
    public ResponseEntity<Page<UserResponseDto>> listUsers(
        @RequestParam(defaultValue = "0") int page,
        @RequestParam(defaultValue = "20") int size) { ... }
    @PutMapping("/{id}")
    public ResponseEntity<UserResponseDto> updateUser(@PathVariable Long id, @Valid @RequestBody UserRequestDto dto) { ... }
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteUser(@PathVariable Long id) { ... }
}
```

### 출력 (openapi.yaml)
```yaml
openapi: 3.0.3
info:
  title: User Management API
  description: 사용자 관리 REST API
  version: 1.0.0
  contact:
    name: API Support
    email: support@example.com

servers:
  - url: http://localhost:8080/api/v1
    description: 로컬 개발 서버
  - url: https://api.example.com/v1
    description: 운영 서버

security:
  - BearerAuth: []

paths:
  /users:
    post:
      summary: 사용자 생성
      operationId: createUser
      tags:
        - Users
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UserRequest'
            example:
              username: "john_doe"
              email: "john@example.com"
              password: "securePassword123"
      responses:
        '201':
          description: 사용자 생성 성공
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '409':
          $ref: '#/components/responses/Conflict'

    get:
      summary: 사용자 목록 조회
      operationId: listUsers
      tags:
        - Users
      parameters:
        - name: page
          in: query
          schema:
            type: integer
            default: 0
            minimum: 0
          description: 페이지 번호 (0부터 시작)
        - name: size
          in: query
          schema:
            type: integer
            default: 20
            minimum: 1
            maximum: 100
          description: 페이지 크기
      responses:
        '200':
          description: 사용자 목록
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserPage'

  /users/{id}:
    parameters:
      - name: id
        in: path
        required: true
        schema:
          type: integer
          format: int64
        description: 사용자 ID

    get:
      summary: 사용자 상세 조회
      operationId: getUserById
      tags:
        - Users
      responses:
        '200':
          description: 사용자 정보
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserResponse'
        '404':
          $ref: '#/components/responses/NotFound'

    put:
      summary: 사용자 정보 수정
      operationId: updateUser
      tags:
        - Users
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UserRequest'
      responses:
        '200':
          description: 수정된 사용자 정보
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserResponse'
        '404':
          $ref: '#/components/responses/NotFound'

    delete:
      summary: 사용자 삭제
      operationId: deleteUser
      tags:
        - Users
      responses:
        '204':
          description: 삭제 성공 (No Content)
        '404':
          $ref: '#/components/responses/NotFound'

components:
  schemas:
    UserRequest:
      type: object
      required:
        - username
        - email
        - password
      properties:
        username:
          type: string
          minLength: 2
          maxLength: 50
          example: "john_doe"
          description: 사용자명 (2~50자)
        email:
          type: string
          format: email
          example: "john@example.com"
          description: 이메일 주소
        password:
          type: string
          minLength: 8
          writeOnly: true
          example: "securePassword123"
          description: 비밀번호 (최소 8자)

    UserResponse:
      type: object
      properties:
        id:
          type: integer
          format: int64
          example: 1
        username:
          type: string
          example: "john_doe"
        email:
          type: string
          format: email
          example: "john@example.com"
        role:
          type: string
          enum: [USER, ADMIN]
          example: "USER"
        isActive:
          type: boolean
          example: true
        createdAt:
          type: string
          format: date-time
          example: "2024-01-15T09:30:00Z"

    UserPage:
      type: object
      properties:
        content:
          type: array
          items:
            $ref: '#/components/schemas/UserResponse'
        totalElements:
          type: integer
          example: 150
        totalPages:
          type: integer
          example: 8
        size:
          type: integer
          example: 20
        number:
          type: integer
          example: 0

    ErrorResponse:
      type: object
      properties:
        timestamp:
          type: string
          format: date-time
        status:
          type: integer
          example: 404
        error:
          type: string
          example: "Not Found"
        message:
          type: string
          example: "사용자를 찾을 수 없습니다: 99"
        path:
          type: string
          example: "/api/v1/users/99"

  responses:
    BadRequest:
      description: 잘못된 요청 (유효성 검사 실패)
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            status: 400
            error: "Bad Request"
            message: "이메일 형식이 올바르지 않습니다"

    NotFound:
      description: 리소스를 찾을 수 없음
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'

    Conflict:
      description: 중복 데이터 충돌
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'

  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: "JWT 토큰. 형식: Bearer {token}"
```

### 출력 (README.md API 섹션)
```markdown
## API Reference

Base URL: `https://api.example.com/v1`

### Authentication

모든 요청에 JWT Bearer 토큰이 필요합니다.

```http
Authorization: Bearer <your_jwt_token>
```

### Users

#### 사용자 목록 조회

| 항목 | 내용 |
|------|------|
| Method | `GET` |
| Path | `/users` |
| Auth | Required |

**Query Parameters**

| 파라미터 | 타입 | 기본값 | 설명 |
|----------|------|--------|------|
| page | integer | 0 | 페이지 번호 |
| size | integer | 20 | 페이지 크기 (최대 100) |

**Response 200**
```json
{
  "content": [
    {
      "id": 1,
      "username": "john_doe",
      "email": "john@example.com",
      "role": "USER",
      "createdAt": "2024-01-15T09:30:00Z"
    }
  ],
  "totalElements": 150,
  "totalPages": 8,
  "size": 20,
  "number": 0
}
```

**curl 예시**
```bash
curl -X GET "https://api.example.com/v1/users?page=0&size=20" \
  -H "Authorization: Bearer eyJ0eXAiOiJKV1Q..."
```

#### 사용자 생성

| 항목 | 내용 |
|------|------|
| Method | `POST` |
| Path | `/users` |
| Auth | Required |

**Request Body**
```json
{
  "username": "john_doe",
  "email": "john@example.com",
  "password": "securePassword123"
}
```

**Response 201**
```json
{
  "id": 42,
  "username": "john_doe",
  "email": "john@example.com",
  "role": "USER",
  "createdAt": "2024-01-15T09:30:00Z"
}
```

**Error Responses**

| Status | 설명 |
|--------|------|
| 400 | 유효성 검사 실패 (이메일 형식, 필수 필드 누락 등) |
| 409 | 이메일 또는 사용자명 중복 |

**curl 예시**
```bash
curl -X POST "https://api.example.com/v1/users" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer eyJ0eXAiOiJKV1Q..." \
  -d '{"username":"john_doe","email":"john@example.com","password":"securePass123"}'
```
```

### Swagger 설정 안내
**Spring Boot (springdoc-openapi)**
```yaml
# build.gradle
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0'

# application.yml
springdoc:
  api-docs:
    path: /api-docs
  swagger-ui:
    path: /swagger-ui.html
```

**FastAPI (내장)**
```python
# 자동 생성: /docs (Swagger UI), /redoc, /openapi.json
app = FastAPI(title="My API", version="1.0.0")
```

**Django DRF (drf-spectacular)**
```python
# pip install drf-spectacular
# settings.py
INSTALLED_APPS = [..., 'drf_spectacular']
REST_FRAMEWORK = {'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema'}
# urls.py
path('api/schema/', SpectacularAPIView.as_view(), name='schema'),
path('api/docs/', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'),
```

## 주의사항

- **`writeOnly: true`**: 비밀번호 등 요청 전용 필드에 반드시 표시. 응답 스키마에서 제외.
- **`$ref` 재사용**: 동일한 에러 응답 구조는 `components/responses`로 추출하여 중복 제거.
- **operationId 유일성**: 각 엔드포인트의 `operationId`는 코드 생성 시 함수명으로 사용되므로 유일해야 함.
- **example vs examples**: 단일 예시는 `example`, 복수 시나리오는 `examples` 키 사용.
- **nullable 처리**: OpenAPI 3.0은 `nullable: true`, 3.1은 `type: [string, "null"]` 사용.
- **파일 업로드**: `multipart/form-data` + `type: string, format: binary` 스키마 사용.
- **버전 관리**: API 변경 시 `info.version` 업데이트, breaking change는 `/v2` 경로 분리 권장.
