# Partner API OpenAPI 품질 개선 지침서

> **버전**: v3.0 (최종)
> **작성일**: 2026-03-23
> **기준**: partner-api openapi.json (66 operations, 56 schemas, 16 missing schemas)
> **선행 문서**: `AXIM_REST_DOC_GENERATOR_IMPROVEMENTS.md` (Generator 레벨 8개 항목)
> **Generator 버전**: v2.0.7 → v2.1.0 → v2.1.1 → v2.1.2 → **v2.1.3** (모든 지침서 항목 반영 완료)
> **Guide #**: 47

---

## 개요

partner-api의 `openapi.json`을 admin-api 수준으로 끌어올리기 위한 개선 지침서입니다.

| 단계 | 범위 | 작업량 | 효과 |
|------|------|--------|------|
| **P0** | build.gradle 설정 수정 | 5분 | securitySchemes 정상 생성 + basePackage 확장 |
| **P1** | ~~Entity → Response DTO 전환~~ | ~~2~3일~~ | ~~→ basePackage 확장으로 대체~~ |
| **P2** | Generator v2.1.0 미반영 잔여 항목 3건 | Generator 소스 수정 | enum 모델, @Size required, NPE 방어 |

---

## 현황 비교: partner-api vs admin-api

| 항목 | admin-api | partner-api | 문제 |
|------|-----------|-------------|------|
| Operations | 120 | 66 | — |
| Schemas | 103 | 56 | — |
| Missing schemas | **0** | **16** | Entity가 schemas에 미포함 |
| Broken $ref endpoints | **0** | **35** | XPage 내부 + 직접 반환 모두 |
| securitySchemes | ✅ ApiKeyAuth | ❌ 없음 | build.gradle auth 설정 오류 |
| Tags | 25 | 13 | — |
| operationId | MD5 해시 | MD5 해시 | ✅ v2.1.0에서 메서드명 기반으로 개선 |
| enum values | 없음 | 없음 | ✅ v2.1.3에서 완전 지원 (DTO + 쿼리 파라미터) |

---

## P0: build.gradle 설정 수정 (5분)

### P0-1. 인증 설정 수정

`partner-api/build.gradle`의 `restMetaGenerator.auth` 설정이 잘못되어 `securitySchemes`가 생성되지 않습니다.

**현재 (잘못됨)**:
```gradle
auth {
    type = 'bearer'
    headerKey = 'Authorization'
    value = 'Bearer {{token}}'
}
```

**실제 partner-api 인증 방식**: admin-api와 동일하게 Axim Framework의 `XBaseAccessTokenHandler` 기반 `Access-Token` 헤더 사용.

**수정**:
```gradle
auth {
    type = 'token'
    headerKey = 'Access-Token'
    value = '{{token}}'
}
```

### P0-2. basePackage 확장 — Missing Schema 16개 해소

Entity를 Response DTO로 변환하는 대신, Generator 스캔 범위에 `common.entity`와 `common.enums` 패키지를 추가합니다. Entity를 응답으로 직접 사용하는 것은 문제가 아니며, Generator가 못 읽는 것이 문제입니다.

**현재**:
```gradle
basePackage = 'com.cryptoments.partnerapi,com.cryptoments.common.exception'
```

**수정**:
```gradle
basePackage = 'com.cryptoments.partnerapi,com.cryptoments.common.exception,com.cryptoments.common.entity,com.cryptoments.common.enums'
```

> **참고**: `common.enums`도 추가하면 Generator가 enum 클래스를 직접 스캔하여 `"enum": [...]` 배열 생성에도 도움이 됩니다.

### P0 기대 결과

- securitySchemes 정상 생성
- 16개 missing schema 중 15개 해소 (Entity schema 자동 생성)
- `LocalDateTime`은 Generator P2에서 인라인 처리로 해결

### P0 검증

```bash
./gradlew :partner-api:generateRestMeta

python3 -c "
import json, sys, re

with open('partner-api/build/docs/openapi.json') as f:
    spec = json.load(f)

schemas = set(spec.get('components', {}).get('schemas', {}).keys())

# 1. securitySchemes 확인
ss = spec.get('components', {}).get('securitySchemes', {})
assert 'ApiKeyAuth' in ss, 'FAIL: securitySchemes 미생성'
print('✅ securitySchemes 정상')

# 2. Missing schema 확인
text = json.dumps(spec)
refs = set(re.findall(r'\"\\\$ref\":\s*\"#/components/schemas/([^\"]+)\"', text))
missing = refs - schemas
missing_no_ldt = missing - {'LocalDateTime'}
if missing_no_ldt:
    print(f'❌ Missing schemas: {missing_no_ldt}')
else:
    print('✅ Missing schemas: 0 (LocalDateTime 제외)')

# 3. 스키마 수 확인
print(f'✅ Total schemas: {len(schemas)} (기존 56 → 목표 ~70+)')

# 4. 총 operations 수 확인
total = sum(1 for p in spec['paths'].values()
            for m in p if m in ('get','post','put','patch','delete'))
print(f'✅ Total operations: {total}')

print('\\n=== ALL CHECKS PASSED ===' if not missing_no_ldt else '\\n=== CHECKS FAILED ===')
"
```

---

## ~~P1: Entity → Response DTO 전환~~ (삭제)

~~15개 Response DTO를 생성하여 Entity 직접 반환을 대체~~

**→ P0-2 (basePackage 확장)으로 대체**. Entity를 응답값으로 직접 사용하는 것은 합리적인 설계이며, Generator의 스캔 범위를 넓히는 것이 올바른 해결책입니다.

---

## P2: Generator 개선 이력 — v2.0.7 → v2.1.3 (✅ 완료)

두 지침서(`AXIM_REST_DOC_GENERATOR_IMPROVEMENTS.md` + 본 문서)를 Generator 프로젝트에 전달하여 v2.1.3까지 개선 완료했습니다.

### 전체 반영 현황

| # | 항목 | 반영 버전 | 비고 |
|---|------|----------|------|
| 1 | @RequestParam 복합 객체 전개 | v2.1.0 | generateQueryParameterModel() 추가 |
| 2 | operationId 메서드명 기반 | v2.1.0 | MD5 해시 → Java 메서드명 |
| 3 | enum 값 목록 | v2.1.0 + **v2.1.3** | DTO 필드 (v2.1.0) + 쿼리 파라미터 enum 모델 누락 수정 (v2.1.3) |
| 4 | required 필드 자동 추출 | v2.1.0 + **v2.1.3** | @NotNull/@NotBlank (v2.1.0) + @Size(min=1) 추가 (v2.1.3) |
| 5 | ApiError 스키마 | v2.1.0 | 4xx/5xx 자동 첨부 |
| 6 | LocalDateTime 인라인 | v2.1.0 | date-time format 변환 |
| 7 | BigDecimal format | v2.1.0 | type: string, format: decimal |
| 8 | example 값 | v2.1.0 | 타입 기반 기본값 |
| 9 | @XApiIgnore + excludePackages/Classes | **v2.1.1** | 스키마 제외 제어 |
| 10 | Missing schema (외부 패키지) | **v2.1.2** | 외부 모듈 Entity 자동 스캔 |
| 11 | 쿼리 파라미터 enum 모델 누락 | **v2.1.3** | referenceClassSet 전달 수정 |
| 12 | 외부 모듈 DTO 쿼리 파라미터 NPE | **v2.1.3** | srcFile null 방어 로직 |

### v2.1.3 수정 내역 (본 지침서에서 발견된 3건)

| Fix | 문제 | 영향 |
|-----|------|------|
| **enum 모델 생성** | `generateQueryParameterModel()`이 `referenceClassSet`을 받지 않아 enum 필드의 모델 JSON 미생성 | 검색 DTO의 status 같은 enum 드롭다운이 OpenAPI에서 누락 |
| **@Size(min=1)** | 지침서 Item 4에서 명시했으나 구현 누락 | `@Size(min=1, max=100)` 붙은 필드가 optional로 처리됨 |
| **NPE 방어** | 외부 모듈 클래스를 쿼리 파라미터로 사용 시 소스 파일 없으면 `JavaSourceParser.parse(null)` → NPE | v2.1.2 외부 모델 생성과 결합 시 크래시 가능 |

### 향후 확장 가능 (미구현)

`@XApiDoc` 어노테이션 기반 확장 — 현재는 불필요하나, 필요 시 추가:
- `@XApiDoc(example = "ACTIVE")` — 필드별 example 직접 지정
- `@XApiDoc(operationId = "customId")` — operationId 직접 override
- `@XApiDoc(hidden = true)` — 특정 필드/엔드포인트 문서 제외

---

## 요약

| 단계 | 작업 | 효과 | 상태 |
|------|------|------|------|
| **P0-1** | build.gradle auth 수정 (`Access-Token`) | securitySchemes 정상화 | ⚠️ 미적용 |
| **P0-2** | build.gradle basePackage 확장 (`common.entity`, `common.enums`) | 15개 missing schema 해소 | ⚠️ 미적용 |
| **P0-3** | Generator v2.1.3 적용 | openapi.json 전체 품질 향상 | ⚠️ 미적용 |

**남은 작업**: IntelliJ에서 partner-api `build.gradle` 수정 (P0-1 + P0-2) + Generator v2.1.3 JitPack 의존성 업데이트 (P0-3).
Generator 레벨 개선은 **모두 완료** — `@XApiDoc` 어노테이션 확장만 향후 필요 시 추가.
