518 lines
15 KiB
Markdown
518 lines
15 KiB
Markdown
|
|
# Swagger API 문서화 가이드
|
||
|
|
|
||
|
|
**작성일**: 2025-10-16
|
||
|
|
**버전**: 1.0.0
|
||
|
|
**프로젝트**: SNP Batch - Spring Batch 기반 데이터 통합 시스템
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 📋 Swagger 설정 완료 사항
|
||
|
|
|
||
|
|
### ✅ 수정 완료 파일
|
||
|
|
1. **BaseController.java** - 공통 CRUD Controller 추상 클래스
|
||
|
|
- Java import alias 오류 수정 (`as SwaggerApiResponse` 제거)
|
||
|
|
- `@Operation` 어노테이션 내 `responses` 속성으로 통합
|
||
|
|
- 전체 경로로 어노테이션 사용: `@io.swagger.v3.oas.annotations.responses.ApiResponse`
|
||
|
|
|
||
|
|
2. **ProductWebController.java** - 샘플 제품 API Controller
|
||
|
|
- Java import alias 오류 수정
|
||
|
|
- 커스텀 엔드포인트 Swagger 어노테이션 수정
|
||
|
|
|
||
|
|
3. **SwaggerConfig.java** - Swagger/OpenAPI 3.0 설정
|
||
|
|
- 서버 포트 동적 설정 (`@Value("${server.port:8081}")`)
|
||
|
|
- 상세한 API 문서 설명 추가
|
||
|
|
- Markdown 형식 설명 추가
|
||
|
|
|
||
|
|
4. **BatchController.java** - 배치 관리 API (이미 올바르게 구현됨)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🌐 Swagger UI 접속 정보
|
||
|
|
|
||
|
|
### 접속 URL
|
||
|
|
```
|
||
|
|
Swagger UI: http://localhost:8081/swagger-ui/index.html
|
||
|
|
API 문서 (JSON): http://localhost:8081/v3/api-docs
|
||
|
|
API 문서 (YAML): http://localhost:8081/v3/api-docs.yaml
|
||
|
|
```
|
||
|
|
|
||
|
|
### 제공되는 API 그룹
|
||
|
|
|
||
|
|
> **참고**: BaseController는 추상 클래스이므로 별도의 API 그룹으로 표시되지 않습니다.
|
||
|
|
> 상속받는 Controller(예: ProductWebController)의 `@Tag`로 모든 CRUD 엔드포인트가 그룹화됩니다.
|
||
|
|
|
||
|
|
#### 1. **Batch Management API** (`/api/batch`)
|
||
|
|
배치 작업 실행 및 스케줄 관리
|
||
|
|
|
||
|
|
**엔드포인트**:
|
||
|
|
- `POST /api/batch/jobs/{jobName}/execute` - 배치 작업 실행
|
||
|
|
- `GET /api/batch/jobs` - 배치 작업 목록 조회
|
||
|
|
- `GET /api/batch/jobs/{jobName}/executions` - 실행 이력 조회
|
||
|
|
- `POST /api/batch/executions/{executionId}/stop` - 실행 중지
|
||
|
|
- `GET /api/batch/schedules` - 스케줄 목록 조회
|
||
|
|
- `POST /api/batch/schedules` - 스케줄 생성
|
||
|
|
- `PUT /api/batch/schedules/{jobName}` - 스케줄 수정
|
||
|
|
- `DELETE /api/batch/schedules/{jobName}` - 스케줄 삭제
|
||
|
|
- `PATCH /api/batch/schedules/{jobName}/toggle` - 스케줄 활성화/비활성화
|
||
|
|
- `GET /api/batch/dashboard` - 대시보드 데이터
|
||
|
|
- `GET /api/batch/timeline` - 타임라인 데이터
|
||
|
|
|
||
|
|
#### 2. **Product API** (`/api/products`)
|
||
|
|
샘플 제품 데이터 CRUD (BaseController 상속)
|
||
|
|
|
||
|
|
**모든 엔드포인트가 "Product API" 그룹으로 통합 표시됩니다.**
|
||
|
|
|
||
|
|
**공통 CRUD 엔드포인트** (BaseController에서 상속):
|
||
|
|
- `POST /api/products` - 제품 생성
|
||
|
|
- `GET /api/products/{id}` - 제품 조회 (ID)
|
||
|
|
- `GET /api/products` - 전체 제품 조회
|
||
|
|
- `GET /api/products/page?offset=0&limit=20` - 페이징 조회
|
||
|
|
- `PUT /api/products/{id}` - 제품 수정
|
||
|
|
- `DELETE /api/products/{id}` - 제품 삭제
|
||
|
|
- `GET /api/products/{id}/exists` - 존재 여부 확인
|
||
|
|
|
||
|
|
**커스텀 엔드포인트**:
|
||
|
|
- `GET /api/products/by-product-id/{productId}` - 제품 코드로 조회
|
||
|
|
- `GET /api/products/stats/active-count` - 활성 제품 개수
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🛠️ 애플리케이션 실행 및 테스트
|
||
|
|
|
||
|
|
### 1. 애플리케이션 빌드 및 실행
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Maven 빌드 (IntelliJ IDEA에서)
|
||
|
|
mvn clean package -DskipTests
|
||
|
|
|
||
|
|
# 애플리케이션 실행
|
||
|
|
mvn spring-boot:run
|
||
|
|
```
|
||
|
|
|
||
|
|
또는 IntelliJ IDEA에서:
|
||
|
|
1. `SnpBatchApplication.java` 파일 열기
|
||
|
|
2. 메인 메서드 왼쪽의 ▶ 아이콘 클릭
|
||
|
|
3. "Run 'SnpBatchApplication'" 선택
|
||
|
|
|
||
|
|
### 2. Swagger UI 접속
|
||
|
|
|
||
|
|
브라우저에서 다음 URL 접속:
|
||
|
|
```
|
||
|
|
http://localhost:8081/swagger-ui/index.html
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3. API 테스트 예시
|
||
|
|
|
||
|
|
#### 예시 1: 배치 작업 목록 조회
|
||
|
|
```http
|
||
|
|
GET http://localhost:8081/api/batch/jobs
|
||
|
|
```
|
||
|
|
|
||
|
|
**예상 응답**:
|
||
|
|
```json
|
||
|
|
[
|
||
|
|
"sampleProductImportJob",
|
||
|
|
"shipDataImportJob"
|
||
|
|
]
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 예시 2: 배치 작업 실행
|
||
|
|
```http
|
||
|
|
POST http://localhost:8081/api/batch/jobs/sampleProductImportJob/execute
|
||
|
|
```
|
||
|
|
|
||
|
|
**예상 응답**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"success": true,
|
||
|
|
"message": "Job started successfully",
|
||
|
|
"executionId": 1
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 예시 3: 제품 생성 (샘플)
|
||
|
|
```http
|
||
|
|
POST http://localhost:8081/api/products
|
||
|
|
Content-Type: application/json
|
||
|
|
|
||
|
|
{
|
||
|
|
"productId": "TEST-001",
|
||
|
|
"productName": "테스트 제품",
|
||
|
|
"category": "Electronics",
|
||
|
|
"price": 99.99,
|
||
|
|
"stockQuantity": 50,
|
||
|
|
"isActive": true,
|
||
|
|
"rating": 4.5
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**예상 응답**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"success": true,
|
||
|
|
"message": "Product created successfully",
|
||
|
|
"data": {
|
||
|
|
"id": 1,
|
||
|
|
"productId": "TEST-001",
|
||
|
|
"productName": "테스트 제품",
|
||
|
|
"category": "Electronics",
|
||
|
|
"price": 99.99,
|
||
|
|
"stockQuantity": 50,
|
||
|
|
"isActive": true,
|
||
|
|
"rating": 4.5,
|
||
|
|
"createdAt": "2025-10-16T10:30:00",
|
||
|
|
"updatedAt": "2025-10-16T10:30:00"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 예시 4: 페이징 조회
|
||
|
|
```http
|
||
|
|
GET http://localhost:8081/api/products/page?offset=0&limit=10
|
||
|
|
```
|
||
|
|
|
||
|
|
**예상 응답**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"success": true,
|
||
|
|
"message": "Retrieved 10 items (total: 100)",
|
||
|
|
"data": [
|
||
|
|
{ "id": 1, "productName": "Product 1", ... },
|
||
|
|
{ "id": 2, "productName": "Product 2", ... },
|
||
|
|
...
|
||
|
|
]
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 📚 Swagger 어노테이션 가이드
|
||
|
|
|
||
|
|
### BaseController에서 사용된 패턴
|
||
|
|
|
||
|
|
#### ❌ 잘못된 사용법 (Java에서는 불가능)
|
||
|
|
```java
|
||
|
|
// Kotlin의 import alias는 Java에서 지원되지 않음
|
||
|
|
import io.swagger.v3.oas.annotations.responses.ApiResponse as SwaggerApiResponse;
|
||
|
|
|
||
|
|
@ApiResponses(value = {
|
||
|
|
@SwaggerApiResponse(responseCode = "200", description = "성공")
|
||
|
|
})
|
||
|
|
```
|
||
|
|
|
||
|
|
#### ✅ 올바른 사용법 (수정 완료)
|
||
|
|
```java
|
||
|
|
// import alias 제거
|
||
|
|
import io.swagger.v3.oas.annotations.Operation;
|
||
|
|
import io.swagger.v3.oas.annotations.Parameter;
|
||
|
|
|
||
|
|
@Operation(
|
||
|
|
summary = "리소스 생성",
|
||
|
|
description = "새로운 리소스를 생성합니다",
|
||
|
|
responses = {
|
||
|
|
@io.swagger.v3.oas.annotations.responses.ApiResponse(
|
||
|
|
responseCode = "200",
|
||
|
|
description = "생성 성공"
|
||
|
|
),
|
||
|
|
@io.swagger.v3.oas.annotations.responses.ApiResponse(
|
||
|
|
responseCode = "500",
|
||
|
|
description = "서버 오류"
|
||
|
|
)
|
||
|
|
}
|
||
|
|
)
|
||
|
|
@PostMapping
|
||
|
|
public ResponseEntity<ApiResponse<D>> create(
|
||
|
|
@Parameter(description = "생성할 리소스 데이터", required = true)
|
||
|
|
@RequestBody D dto) {
|
||
|
|
// ...
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 주요 어노테이션 설명
|
||
|
|
|
||
|
|
#### 1. `@Tag` - API 그룹화
|
||
|
|
```java
|
||
|
|
@Tag(name = "Product API", description = "제품 관리 API")
|
||
|
|
public class ProductWebController extends BaseController<ProductWebDto, Long> {
|
||
|
|
// ...
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 2. `@Operation` - 엔드포인트 문서화
|
||
|
|
```java
|
||
|
|
@Operation(
|
||
|
|
summary = "짧은 설명 (목록에 표시)",
|
||
|
|
description = "상세 설명 (확장 시 표시)",
|
||
|
|
responses = { /* 응답 정의 */ }
|
||
|
|
)
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 3. `@Parameter` - 파라미터 설명
|
||
|
|
```java
|
||
|
|
@Parameter(
|
||
|
|
description = "파라미터 설명",
|
||
|
|
required = true,
|
||
|
|
example = "예시 값"
|
||
|
|
)
|
||
|
|
@PathVariable String id
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 4. `@io.swagger.v3.oas.annotations.responses.ApiResponse` - 응답 정의
|
||
|
|
```java
|
||
|
|
@io.swagger.v3.oas.annotations.responses.ApiResponse(
|
||
|
|
responseCode = "200",
|
||
|
|
description = "성공 메시지",
|
||
|
|
content = @Content(
|
||
|
|
mediaType = "application/json",
|
||
|
|
schema = @Schema(implementation = ProductDto.class)
|
||
|
|
)
|
||
|
|
)
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🎯 신규 Controller 개발 시 Swagger 적용 가이드
|
||
|
|
|
||
|
|
### 1. BaseController를 상속하는 경우
|
||
|
|
|
||
|
|
```java
|
||
|
|
@RestController
|
||
|
|
@RequestMapping("/api/myresource")
|
||
|
|
@RequiredArgsConstructor
|
||
|
|
@Tag(name = "My Resource API", description = "나의 리소스 관리 API")
|
||
|
|
public class MyResourceController extends BaseController<MyResourceDto, Long> {
|
||
|
|
|
||
|
|
private final MyResourceService myResourceService;
|
||
|
|
|
||
|
|
@Override
|
||
|
|
protected BaseService<?, MyResourceDto, Long> getService() {
|
||
|
|
return myResourceService;
|
||
|
|
}
|
||
|
|
|
||
|
|
@Override
|
||
|
|
protected String getResourceName() {
|
||
|
|
return "MyResource";
|
||
|
|
}
|
||
|
|
|
||
|
|
// BaseController가 제공하는 CRUD 엔드포인트 자동 생성:
|
||
|
|
// POST /api/myresource
|
||
|
|
// GET /api/myresource/{id}
|
||
|
|
// GET /api/myresource
|
||
|
|
// GET /api/myresource/page
|
||
|
|
// PUT /api/myresource/{id}
|
||
|
|
// DELETE /api/myresource/{id}
|
||
|
|
// GET /api/myresource/{id}/exists
|
||
|
|
|
||
|
|
// 커스텀 엔드포인트 추가 시:
|
||
|
|
@Operation(
|
||
|
|
summary = "커스텀 조회",
|
||
|
|
description = "특정 조건으로 리소스를 조회합니다",
|
||
|
|
responses = {
|
||
|
|
@io.swagger.v3.oas.annotations.responses.ApiResponse(
|
||
|
|
responseCode = "200",
|
||
|
|
description = "조회 성공"
|
||
|
|
)
|
||
|
|
}
|
||
|
|
)
|
||
|
|
@GetMapping("/custom/{key}")
|
||
|
|
public ResponseEntity<ApiResponse<MyResourceDto>> customEndpoint(
|
||
|
|
@Parameter(description = "커스텀 키", required = true)
|
||
|
|
@PathVariable String key) {
|
||
|
|
// 구현...
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. 독립적인 Controller를 작성하는 경우
|
||
|
|
|
||
|
|
```java
|
||
|
|
@RestController
|
||
|
|
@RequestMapping("/api/custom")
|
||
|
|
@RequiredArgsConstructor
|
||
|
|
@Slf4j
|
||
|
|
@Tag(name = "Custom API", description = "커스텀 API")
|
||
|
|
public class CustomController {
|
||
|
|
|
||
|
|
@Operation(
|
||
|
|
summary = "커스텀 작업",
|
||
|
|
description = "특정 작업을 수행합니다",
|
||
|
|
responses = {
|
||
|
|
@io.swagger.v3.oas.annotations.responses.ApiResponse(
|
||
|
|
responseCode = "200",
|
||
|
|
description = "작업 성공"
|
||
|
|
),
|
||
|
|
@io.swagger.v3.oas.annotations.responses.ApiResponse(
|
||
|
|
responseCode = "500",
|
||
|
|
description = "서버 오류"
|
||
|
|
)
|
||
|
|
}
|
||
|
|
)
|
||
|
|
@PostMapping("/action")
|
||
|
|
public ResponseEntity<Map<String, Object>> customAction(
|
||
|
|
@Parameter(description = "액션 파라미터", required = true)
|
||
|
|
@RequestBody Map<String, String> params) {
|
||
|
|
// 구현...
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🔍 Swagger UI 화면 구성
|
||
|
|
|
||
|
|
### 메인 화면
|
||
|
|
```
|
||
|
|
┌─────────────────────────────────────────────────┐
|
||
|
|
│ SNP Batch REST API │
|
||
|
|
│ Version: v1.0.0 │
|
||
|
|
│ Spring Batch 기반 데이터 통합 시스템 REST API │
|
||
|
|
├─────────────────────────────────────────────────┤
|
||
|
|
│ Servers: │
|
||
|
|
│ ▼ http://localhost:8081 (로컬 개발 서버) │
|
||
|
|
├─────────────────────────────────────────────────┤
|
||
|
|
│ │
|
||
|
|
│ ▼ Batch Management API │
|
||
|
|
│ POST /api/batch/jobs/{jobName}/execute │
|
||
|
|
│ GET /api/batch/jobs │
|
||
|
|
│ ... │
|
||
|
|
│ │
|
||
|
|
│ ▼ Product API (9개 엔드포인트 통합 표시) │
|
||
|
|
│ POST /api/products │
|
||
|
|
│ GET /api/products/{id} │
|
||
|
|
│ GET /api/products │
|
||
|
|
│ GET /api/products/page │
|
||
|
|
│ PUT /api/products/{id} │
|
||
|
|
│ DELETE /api/products/{id} │
|
||
|
|
│ GET /api/products/{id}/exists │
|
||
|
|
│ GET /api/products/by-product-id/{...} │
|
||
|
|
│ GET /api/products/stats/active-count │
|
||
|
|
│ │
|
||
|
|
│ (Base API 그룹은 표시되지 않음) │
|
||
|
|
│ │
|
||
|
|
└─────────────────────────────────────────────────┘
|
||
|
|
```
|
||
|
|
|
||
|
|
### API 실행 화면 예시
|
||
|
|
각 엔드포인트 클릭 시:
|
||
|
|
- **Parameters**: 파라미터 입력 필드
|
||
|
|
- **Request body**: JSON 요청 본문 에디터
|
||
|
|
- **Try it out**: 실제 API 호출 버튼
|
||
|
|
- **Responses**: 응답 코드 및 예시
|
||
|
|
- **Curl**: curl 명령어 생성
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## ⚠️ 문제 해결
|
||
|
|
|
||
|
|
### 1. Swagger UI 접속 불가
|
||
|
|
**증상**: `http://localhost:8081/swagger-ui/index.html` 접속 시 404 오류
|
||
|
|
|
||
|
|
**해결**:
|
||
|
|
1. 애플리케이션이 실행 중인지 확인
|
||
|
|
2. 포트 번호 확인 (`application.yml`의 `server.port`)
|
||
|
|
3. 다음 URL 시도:
|
||
|
|
- `http://localhost:8081/swagger-ui.html`
|
||
|
|
- `http://localhost:8081/swagger-ui/`
|
||
|
|
|
||
|
|
### 2. API 실행 시 401/403 오류
|
||
|
|
**증상**: "Try it out" 클릭 시 인증 오류
|
||
|
|
|
||
|
|
**해결**:
|
||
|
|
- 현재 인증이 설정되지 않음 (기본 허용)
|
||
|
|
- Spring Security 추가 시 Swagger 경로 허용 필요:
|
||
|
|
```java
|
||
|
|
.authorizeHttpRequests(auth -> auth
|
||
|
|
.requestMatchers("/swagger-ui/**", "/v3/api-docs/**").permitAll()
|
||
|
|
.anyRequest().authenticated()
|
||
|
|
)
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3. 특정 엔드포인트가 보이지 않음
|
||
|
|
**증상**: Controller는 작성했지만 Swagger UI에 표시되지 않음
|
||
|
|
|
||
|
|
**해결**:
|
||
|
|
1. `@RestController` 어노테이션 확인
|
||
|
|
2. `@RequestMapping` 경로 확인
|
||
|
|
3. Controller가 `com.snp.batch` 패키지 하위에 있는지 확인
|
||
|
|
4. 애플리케이션 재시작
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 📊 설정 파일
|
||
|
|
|
||
|
|
### application.yml (Swagger 관련 설정)
|
||
|
|
```yaml
|
||
|
|
server:
|
||
|
|
port: 8081 # Swagger UI 접속 포트
|
||
|
|
|
||
|
|
# Springdoc OpenAPI 설정 (필요 시 추가)
|
||
|
|
springdoc:
|
||
|
|
api-docs:
|
||
|
|
path: /v3/api-docs # OpenAPI JSON 경로
|
||
|
|
swagger-ui:
|
||
|
|
path: /swagger-ui.html # Swagger UI 경로
|
||
|
|
enabled: true
|
||
|
|
operations-sorter: alpha # 엔드포인트 정렬 (alpha, method)
|
||
|
|
tags-sorter: alpha # 태그 정렬
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🎓 추가 학습 자료
|
||
|
|
|
||
|
|
### Swagger 어노테이션 공식 문서
|
||
|
|
- [OpenAPI 3.0 Annotations](https://github.com/swagger-api/swagger-core/wiki/Swagger-2.X---Annotations)
|
||
|
|
- [Springdoc OpenAPI](https://springdoc.org/)
|
||
|
|
|
||
|
|
### 관련 파일 위치
|
||
|
|
```
|
||
|
|
src/main/java/com/snp/batch/
|
||
|
|
├── common/web/controller/BaseController.java # 공통 CRUD Base
|
||
|
|
├── global/config/SwaggerConfig.java # Swagger 설정
|
||
|
|
├── global/controller/BatchController.java # Batch API
|
||
|
|
└── jobs/sample/web/controller/ProductWebController.java # Product API
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## ✅ 체크리스트
|
||
|
|
|
||
|
|
애플리케이션 실행 전 확인:
|
||
|
|
- [ ] Maven 빌드 성공
|
||
|
|
- [ ] `application.yml` 설정 확인
|
||
|
|
- [ ] PostgreSQL 데이터베이스 연결 확인
|
||
|
|
- [ ] 포트 8081 사용 가능 여부 확인
|
||
|
|
|
||
|
|
Swagger 테스트 확인:
|
||
|
|
- [ ] Swagger UI 접속 성공
|
||
|
|
- [ ] Batch Management API 표시 확인
|
||
|
|
- [ ] Product API 표시 확인
|
||
|
|
- [ ] "Try it out" 기능 동작 확인
|
||
|
|
- [ ] API 응답 정상 확인
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 📚 관련 문서
|
||
|
|
|
||
|
|
### 핵심 문서
|
||
|
|
- **[README.md](README.md)** - 프로젝트 개요 및 빠른 시작 가이드
|
||
|
|
- **[DEVELOPMENT_GUIDE.md](DEVELOPMENT_GUIDE.md)** - 신규 Job 개발 가이드 및 Base 클래스 사용법
|
||
|
|
- **[CLAUDE.md](CLAUDE.md)** - 프로젝트 형상관리 문서 (세션 연속성)
|
||
|
|
|
||
|
|
### 아키텍처 문서
|
||
|
|
- **[docs/architecture/ARCHITECTURE.md](docs/architecture/ARCHITECTURE.md)** - 프로젝트 아키텍처 상세 설계
|
||
|
|
- **[docs/architecture/PROJECT_STRUCTURE.md](docs/architecture/PROJECT_STRUCTURE.md)** - Job 중심 패키지 구조 가이드
|
||
|
|
|
||
|
|
### 구현 가이드
|
||
|
|
- **[docs/guides/PROXY_SERVICE_GUIDE.md](docs/guides/PROXY_SERVICE_GUIDE.md)** - 외부 API 프록시 패턴 구현 가이드
|
||
|
|
- **[docs/guides/SHIP_API_EXAMPLE.md](docs/guides/SHIP_API_EXAMPLE.md)** - Maritime API 연동 실전 예제
|
||
|
|
|
||
|
|
### 보안 문서
|
||
|
|
- **[docs/security/README.md](docs/security/README.md)** - 보안 전략 개요 (계획 단계)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
**최종 업데이트**: 2025-10-16
|
||
|
|
**작성자**: Claude Code
|
||
|
|
**버전**: 1.1.0
|