# VMIS API 통합 아키텍처 문서

## 📋 목차
- [1. 개요](#1-개요)
- [2. 패키지 구조](#2-패키지-구조)
- [3. 아키텍처 패턴](#3-아키텍처-패턴)
- [4. Internal Mode 상세](#4-internal-mode-상세)
- [5. External Mode 상세](#5-external-mode-상세)
- [6. 공통 구성요소](#6-공통-구성요소)
- [7. 데이터 흐름](#7-데이터-흐름)
- [8. 설정 가이드](#8-설정-가이드)
- [9. 사용 예제](#9-사용-예제)

---

## 1. 개요

### 1.1 목적
VMIS(차량관리정보시스템) API 통합 모듈은 차량 정보 조회 기능을 제공하며, 두 가지 운영 모드를 지원합니다:
- **Internal Mode**: 내부 VMIS 모듈을 직접 호출 (성능 우선)
- **External Mode**: 외부 REST API 서버 호출 (분리된 아키텍처)

### 1.2 설계 원칙
- **Strategy Pattern**: 런타임에 알고리즘(구현체) 전환
- **Dependency Inversion**: 인터페이스에 의존, 구현체는 교체 가능
- **Single Responsibility**: 각 클래스는 단일 책임만 수행
- **Open-Closed**: 확장에는 열려있고 수정에는 닫혀있음

---

## 2. 패키지 구조

```
src/main/java/go/kr/project/api/
├── VehicleInfoService.java          # 공통 인터페이스
│
├── config/                           # 공통 설정
│   ├── ApiConstant.java             # API 상수
│   ├── ApiMapperConfig.java         # API Mapper 스캔 설정
│   ├── VmisIntegrationConfig.java   # 통합 설정 및 모니터링
│   └── properties/
│       └── VmisProperties.java      # 설정 바인딩 클래스
│
├── vo/                               # 공통 응답 VO (공유)
│   ├── VehicleApiResponseVO.java    # 최상위 응답 객체
│   ├── VehicleBasicInfoVO.java      # 차량 기본정보 VO
│   ├── VehicleLedgerVO.java         # 차량 등록원부 VO
│   ├── VehicleBasicRequestVO.java   # 기본정보 요청 VO
│   └── VehicleLedgerRequestVO.java  # 등록원부 요청 VO
│
├── internal/                         # Internal Mode (내부 모듈)
│   ├── service/
│   │   ├── InternalVehicleInfoServiceImpl.java          # 내부 모드 구현체 ⭐
│   │   ├── VmisCarBassMatterInqireService.java          # 기본정보 조회 서비스
│   │   ├── VmisCarBassMatterInqireLogService.java       # 기본정보 로그 서비스
│   │   ├── VmisCarLedgerFrmbkService.java               # 등록원부 조회 서비스
│   │   └── VmisCarLedgerFrmbkLogService.java            # 등록원부 로그 서비스
│   │
│   ├── client/
│   │   ├── GovernmentApi.java       # 정부 API 인터페이스
│   │   └── GovernmentApiClient.java # 정부 API 클라이언트
│   │
│   ├── mapper/
│   │   ├── VmisCarBassMatterInqireMapper.java  # 기본정보 Mapper
│   │   └── VmisCarLedgerFrmbkMapper.java       # 등록원부 Mapper
│   │
│   ├── model/                        # Internal 전용 모델
│   │   ├── basic/
│   │   │   ├── BasicRequest.java    # 기본정보 요청
│   │   │   ├── BasicResponse.java   # 기본정보 응답
│   │   │   └── VmisCarBassMatterInqireVO.java
│   │   ├── ledger/
│   │   │   ├── LedgerRequest.java   # 등록원부 요청
│   │   │   ├── LedgerResponse.java  # 등록원부 응답
│   │   │   ├── VmisCarLedgerFrmbkVO.java
│   │   │   └── VmisCarLedgerFrmbkDtlVO.java
│   │   └── common/
│   │       └── Envelope.java        # 공통 Envelope
│   │
│   ├── config/
│   │   ├── HttpClientConfig.java    # RestTemplate 설정
│   │   ├── OpenApiConfig.java       # OpenAPI 설정
│   │   ├── PropertiesConfig.java    # Properties 빈 등록
│   │   ├── GpkiConfig.java          # GPKI 설정
│   │   └── Globals.java             # 전역 상수
│   │
│   ├── controller/
│   │   └── VehicleInterfaceController.java  # REST API 컨트롤러
│   │
│   ├── enricher/
│   │   └── VmisRequestEnricher.java # 요청 데이터 자동 보강
│   │
│   ├── gpki/
│   │   ├── GpkiService.java         # GPKI 인터페이스
│   │   ├── RealGpkiService.java     # 실제 GPKI 구현
│   │   └── NoopGpkiService.java     # GPKI 비활성화 구현
│   │
│   └── util/
│       └── VehicleResponseMapper.java  # 내부↔외부 VO 변환
│
└── external/                         # External Mode (외부 API)
    └── service/
        ├── ExternalVehicleInfoServiceImpl.java  # 외부 모드 구현체 ⭐
        └── ExternalVehicleApiService.java       # 외부 API 호출 서비스
```

---

## 3. 아키텍처 패턴

### 3.1 Strategy Pattern (전략 패턴)

```java
// 공통 인터페이스
public interface VehicleInfoService {
    VehicleApiResponseVO getVehicleInfo(String vehicleNumber);
    List<VehicleApiResponseVO> getVehiclesInfo(List<String> vehicleNumbers);
}

// Internal Mode 구현체
@Service
@ConditionalOnProperty(name = "vmis.integration.mode", havingValue = "internal")
public class InternalVehicleInfoServiceImpl implements VehicleInfoService {
    // 내부 VMIS 모듈 직접 호출
}

// External Mode 구현체
@Service
@ConditionalOnProperty(name = "vmis.integration.mode", havingValue = "external", matchIfMissing = true)
public class ExternalVehicleInfoServiceImpl implements VehicleInfoService {
    // 외부 REST API 호출
}
```

**장점:**
- 런타임에 구현체 전환 가능
- 클라이언트 코드는 인터페이스만 의존
- 새로운 전략 추가 시 기존 코드 수정 불필요

### 3.2 의존성 주입 (Dependency Injection)

```yaml
# application.yml
vmis:
  integration:
    mode: internal  # 또는 external
```

Spring의 `@ConditionalOnProperty`를 통해 설정값에 따라 자동으로 적절한 구현체가 Bean으로 등록됩니다.

```java
@Autowired
private VehicleInfoService vehicleInfoService;
// 설정에 따라 InternalVehicleInfoServiceImpl 또는
// ExternalVehicleInfoServiceImpl이 주입됨
```

### 3.3 계층화 아키텍처

```
┌─────────────────────────────────────┐
│   Controller Layer                  │  ← REST API 엔드포인트
├─────────────────────────────────────┤
│   Service Layer (VehicleInfoService)│  ← 비즈니스 로직
├─────────────────────────────────────┤
│   Client/Mapper Layer               │  ← 데이터 접근
├─────────────────────────────────────┤
│   External System (정부 API/DB)     │  ← 외부 시스템
└─────────────────────────────────────┘
```

---

## 4. Internal Mode 상세

### 4.1 개요
내부 VMIS 모듈을 직접 사용하여 정부 시스템(MOLIT)과 통신합니다.

**장점:**
- 네트워크 오버헤드 감소 (외부 서버 호출 불필요)
- 빠른 응답 속도
- 단일 애플리케이션으로 운영 가능

**단점:**
- GPKI 인증서 관리 필요
- 정부 API 연동 복잡도 증가

### 4.2 주요 구성요소

#### 4.2.1 InternalVehicleInfoServiceImpl
```java
@Service
@ConditionalOnProperty(name = "vmis.integration.mode", havingValue = "internal")
public class InternalVehicleInfoServiceImpl implements VehicleInfoService {

    private final VmisCarBassMatterInqireService carBassMatterInqireService;
    private final VmisCarLedgerFrmbkService carLedgerFrmbkService;

    @Override
    public VehicleApiResponseVO getVehicleInfo(String vehicleNumber) {
        // 1. 기본정보 조회
        VehicleBasicInfoVO basicInfo = getBasicInfo(vehicleNumber);

        // 2. 등록원부 조회
        VehicleLedgerVO ledgerInfo = getLedgerInfo(vehicleNumber);

        // 3. 결과 통합
        return VehicleApiResponseVO.builder()
            .vhrno(vehicleNumber)
            .basicInfo(basicInfo)
            .ledgerInfo(ledgerInfo)
            .build();
    }
}
```

#### 4.2.2 GovernmentApiClient
정부 API와 실제 HTTP 통신을 수행합니다.

```java
@Component
@RequiredArgsConstructor
public class GovernmentApiClient implements GovernmentApi {

    @Qualifier("vmisRestTemplate")
    private final RestTemplate restTemplate;

    @Override
    public ResponseEntity<String> basic(String requestBody) {
        String url = baseUrl + basicServicePath;
        return restTemplate.postForEntity(url, requestBody, String.class);
    }
}
```

#### 4.2.3 VmisRequestEnricher
요청 데이터를 자동으로 보강합니다.

```java
@Component
public class VmisRequestEnricher {

    public void enrichBasicRequest(BasicRequest request) {
        // 시스템 정보 자동 설정
        request.setInfoSysId(vmisProperties.getSystem().getInfoSysId());
        request.setInfoSysIp(vmisProperties.getSystem().getInfoSysIp());
        request.setRegionCode(vmisProperties.getSystem().getRegionCode());
        // ...
    }
}
```

#### 4.2.4 GPKI 암호화
운영 환경에서 정부 API 통신 시 GPKI 암호화를 사용합니다.

```java
public interface GpkiService {
    String encrypt(String plainText);
    String decrypt(String encryptedText);
}

// 개발: NoopGpkiService (암호화 없음)
// 운영: RealGpkiService (실제 GPKI 암호화)
```

### 4.3 데이터 흐름

```
[Client]
   │
   ▼
[InternalVehicleInfoServiceImpl]
   │
   ├─► [VmisCarBassMatterInqireService]
   │      │
   │      ├─► [VmisRequestEnricher] ──► Request 보강
   │      ├─► [GovernmentApiClient] ──► HTTP POST
   │      │      │
   │      │      ▼
   │      │   [정부 API - 기본정보]
   │      │      │
   │      │      ▼
   │      ├─► [GpkiService] ──► 암호화/복호화
   │      ├─► [VmisCarBassMatterInqireMapper] ──► DB 저장
   │      └─► BasicResponse
   │
   ├─► [VmisCarLedgerFrmbkService]
   │      │
   │      └─► (기본정보와 동일한 흐름)
   │
   └─► [VehicleResponseMapper] ──► 내부 VO → 외부 VO 변환
          │
          ▼
       VehicleApiResponseVO
```

### 4.4 설정 예시

```yaml
vmis:
  integration:
    mode: internal

  system:
    infoSysId: "41-345"
    infoSysIp: "105.19.10.135"
    regionCode: "41460"

  gov:
    scheme: "http"
    host: "10.188.225.94:29001"
    basePath: "/piss/api/molit"
    services:
      basic:
        path: "/SignguCarBassMatterInqireService"
        apiKey: "${GOV_API_KEY_BASIC}"
      ledger:
        path: "/SignguCarLedgerFrmbkService"
        apiKey: "${GOV_API_KEY_LEDGER}"

  gpki:
    enabled: "Y"  # 운영: Y, 개발: N
    certServerId: "SVR5640020001"
    targetServerId: "SVR1500000015"
```

---

## 5. External Mode 상세

### 5.1 개요
외부 VMIS-interface 서버의 REST API를 호출하여 차량 정보를 조회합니다.

**장점:**
- 마이크로서비스 아키텍처 지원
- GPKI 관리를 외부 서버에 위임
- 간단한 설정

**단점:**
- 네트워크 오버헤드 증가
- 외부 서버 의존성

### 5.2 주요 구성요소

#### 5.2.1 ExternalVehicleInfoServiceImpl
```java
@Service
@ConditionalOnProperty(name = "vmis.integration.mode", havingValue = "external", matchIfMissing = true)
public class ExternalVehicleInfoServiceImpl implements VehicleInfoService {

    private final ExternalVehicleApiService externalVehicleApiService;

    @Override
    public VehicleApiResponseVO getVehicleInfo(String vehicleNumber) {
        // 외부 API 서비스에 위임
        return externalVehicleApiService.getVehicleInfo(vehicleNumber);
    }
}
```

#### 5.2.2 ExternalVehicleApiService
외부 REST API를 호출합니다.

```java
@Service
@RequiredArgsConstructor
public class ExternalVehicleApiService {

    private final RestTemplate restTemplate;

    public VehicleApiResponseVO getVehicleInfo(String vehicleNumber) {
        String url = vmisProperties.getExternal().getApi().getUrl();

        VehicleBasicRequestVO request = new VehicleBasicRequestVO();
        request.setVhrno(vehicleNumber);

        return restTemplate.postForObject(url + "/basic", request, VehicleApiResponseVO.class);
    }
}
```

### 5.3 데이터 흐름

```
[Client]
   │
   ▼
[ExternalVehicleInfoServiceImpl]
   │
   ▼
[ExternalVehicleApiService]
   │
   ▼
[RestTemplate] ──► HTTP POST
   │
   ▼
[VMIS-interface Server] (외부)
   │
   ├─► 정부 API 호출
   ├─► GPKI 암호화/복호화
   ├─► DB 저장
   └─► VehicleApiResponseVO 반환
   │
   ▼
[Client]
```

### 5.4 설정 예시

```yaml
vmis:
  integration:
    mode: external

  external:
    api:
      url: "http://localhost:8081/api/v1/vehicles"
      connectTimeoutMillis: 5000
      readTimeoutMillis: 10000
```

---

## 6. 공통 구성요소

### 6.1 VehicleInfoService 인터페이스
```java
public interface VehicleInfoService {
    // 단일 차량 조회
    VehicleApiResponseVO getVehicleInfo(String vehicleNumber);

    // 일괄 조회
    List<VehicleApiResponseVO> getVehiclesInfo(List<String> vehicleNumbers);
}
```

### 6.2 공통 VO (vo 패키지)

#### VehicleApiResponseVO
```java
@Data
@Builder
public class VehicleApiResponseVO {
    private String vhrno;                    // 차량번호
    private boolean success;                 // 성공 여부
    private String message;                  // 메시지
    private VehicleBasicInfoVO basicInfo;    // 기본정보
    private VehicleLedgerVO ledgerInfo;      // 등록원부 정보
}
```

#### VehicleBasicInfoVO
차량 기본정보 (소유자, 차종, 연식 등)

#### VehicleLedgerVO
자동차 등록원부 정보 (등록일, 변경이력 등)

### 6.3 VmisProperties
application.yml의 설정을 바인딩하는 클래스입니다.

```java
@Data
@Component
@ConfigurationProperties(prefix = "vmis")
public class VmisProperties {
    private Integration integration;
    private System system;
    private Gov gov;
    private Gpki gpki;
    private External external;
}
```

### 6.4 ApiMapperConfig
API 전용 MyBatis Mapper를 스캔합니다.

```java
@Configuration
@MapperScan(basePackages = "go.kr.project.api.internal.mapper")
public class ApiMapperConfig {
}
```

---

## 7. 데이터 흐름

### 7.1 Internal Mode 전체 흐름

```
┌─────────────────────────────────────────────────────────────────────┐
│ 1. Client Request                                                   │
│    vehicleInfoService.getVehicleInfo("12가3456")                    │
└────────────────────────┬────────────────────────────────────────────┘
                         │
                         ▼
┌─────────────────────────────────────────────────────────────────────┐
│ 2. InternalVehicleInfoServiceImpl                                   │
│    - BasicRequest 생성 (vhrno="12가3456")                           │
│    - LedgerRequest 생성 (vhrno="12가3456")                          │
└────────────────────────┬────────────────────────────────────────────┘
                         │
         ┌───────────────┴───────────────┐
         │                               │
         ▼                               ▼
┌──────────────────────┐       ┌──────────────────────┐
│ 3-1. Basic Service   │       │ 3-2. Ledger Service  │
│ - VmisRequestEnricher│       │ - VmisRequestEnricher│
│   (시스템 정보 자동 설정)│      │   (시스템 정보 자동 설정)│
└──────┬───────────────┘       └──────┬───────────────┘
       │                               │
       ▼                               ▼
┌──────────────────────┐       ┌──────────────────────┐
│ 4-1. 정부 API 호출   │       │ 4-2. 정부 API 호출   │
│ - GovernmentApiClient│       │ - GovernmentApiClient│
│ - GPKI 암호화 (운영)  │       │ - GPKI 암호화 (운영)  │
│ - HTTP POST          │       │ - HTTP POST          │
└──────┬───────────────┘       └──────┬───────────────┘
       │                               │
       ▼                               ▼
┌──────────────────────┐       ┌──────────────────────┐
│ 5-1. 응답 처리       │       │ 5-2. 응답 처리       │
│ - GPKI 복호화        │       │ - GPKI 복호화        │
│ - JSON 파싱          │       │ - JSON 파싱          │
│ - DB 저장 (Mapper)   │       │ - DB 저장 (Mapper)   │
└──────┬───────────────┘       └──────┬───────────────┘
       │                               │
       └───────────────┬───────────────┘
                       ▼
┌─────────────────────────────────────────────────────────────────────┐
│ 6. VehicleResponseMapper                                            │
│    - BasicResponse → VehicleBasicInfoVO 변환                        │
│    - LedgerResponse → VehicleLedgerVO 변환                          │
└────────────────────────┬────────────────────────────────────────────┘
                         ▼
┌─────────────────────────────────────────────────────────────────────┐
│ 7. Response                                                         │
│    VehicleApiResponseVO {                                           │
│      vhrno: "12가3456",                                             │
│      success: true,                                                 │
│      basicInfo: { ... },                                            │
│      ledgerInfo: { ... }                                            │
│    }                                                                │
└─────────────────────────────────────────────────────────────────────┘
```

### 7.2 External Mode 전체 흐름

```
┌─────────────────────────────────────────────────────────────────────┐
│ 1. Client Request                                                   │
│    vehicleInfoService.getVehicleInfo("12가3456")                    │
└────────────────────────┬────────────────────────────────────────────┘
                         │
                         ▼
┌─────────────────────────────────────────────────────────────────────┐
│ 2. ExternalVehicleInfoServiceImpl                                   │
│    - ExternalVehicleApiService에 위임                               │
└────────────────────────┬────────────────────────────────────────────┘
                         │
                         ▼
┌─────────────────────────────────────────────────────────────────────┐
│ 3. ExternalVehicleApiService                                        │
│    - VehicleBasicRequestVO 생성                                     │
│    - RestTemplate으로 외부 API 호출                                 │
└────────────────────────┬────────────────────────────────────────────┘
                         │
                         ▼
┌─────────────────────────────────────────────────────────────────────┐
│ 4. HTTP Request to External Server                                 │
│    POST http://localhost:8081/api/v1/vehicles/basic                │
│    Body: { vhrno: "12가3456" }                                      │
└────────────────────────┬────────────────────────────────────────────┘
                         │
                         ▼
┌─────────────────────────────────────────────────────────────────────┐
│ 5. VMIS-interface Server (외부)                                     │
│    - 정부 API 호출                                                  │
│    - GPKI 처리                                                      │
│    - DB 저장                                                        │
│    - VehicleApiResponseVO 반환                                      │
└────────────────────────┬────────────────────────────────────────────┘
                         │
                         ▼
┌─────────────────────────────────────────────────────────────────────┐
│ 6. Response                                                         │
│    VehicleApiResponseVO {                                           │
│      vhrno: "12가3456",                                             │
│      success: true,                                                 │
│      basicInfo: { ... },                                            │
│      ledgerInfo: { ... }                                            │
│    }                                                                │
└─────────────────────────────────────────────────────────────────────┘
```

---

## 8. 설정 가이드

### 8.1 Internal Mode 설정

```yaml
vmis:
  integration:
    mode: internal  # ⭐ Internal Mode 활성화

  # 시스템 정보 (요청 헤더에 자동 포함)
  system:
    infoSysId: "41-345"
    infoSysIp: "${SERVER_IP:105.19.10.135}"
    regionCode: "41460"
    departmentCode: ""
    chargerId: ""
    chargerIp: ""
    chargerNm: ""

  # 정부 API 연동 설정
  gov:
    scheme: "http"
    host: "10.188.225.94:29001"
    basePath: "/piss/api/molit"
    connectTimeoutMillis: 5000
    readTimeoutMillis: 10000
    services:
      basic:
        path: "/SignguCarBassMatterInqireService"
        cntcInfoCode: "AC1_FD11_01"
        apiKey: "${GOV_API_KEY_BASIC}"
      ledger:
        path: "/SignguCarLedgerFrmbkService"
        cntcInfoCode: "AC1_FD11_02"
        apiKey: "${GOV_API_KEY_LEDGER}"

  # GPKI 암호화 (운영 환경 필수)
  gpki:
    enabled: "Y"  # Y: 암호화 사용, N: 암호화 미사용
    certServerId: "SVR5640020001"
    targetServerId: "SVR1500000015"
    envCertFilePathName: "src/GPKI/certs/SVR5640020001_env.cer"
    sigCertFilePathName: "src/GPKI/certs/SVR5640020001_sig.cer"
```

### 8.2 External Mode 설정

```yaml
vmis:
  integration:
    mode: external  # ⭐ External Mode 활성화

  # 외부 API 서버 설정
  external:
    api:
      url: "http://localhost:8081/api/v1/vehicles"
      connectTimeoutMillis: 5000
      readTimeoutMillis: 10000
```

### 8.3 개발 환경 설정 (GPKI 비활성화)

```yaml
vmis:
  integration:
    mode: internal

  gpki:
    enabled: "N"  # ⭐ GPKI 비활성화
```

---

## 9. 사용 예제

### 9.1 기본 사용법

```java
@RestController
@RequestMapping("/api/vehicles")
@RequiredArgsConstructor
public class VehicleController {

    private final VehicleInfoService vehicleInfoService;

    /**
     * 단일 차량 조회
     */
    @GetMapping("/{vehicleNumber}")
    public ResponseEntity<VehicleApiResponseVO> getVehicle(
            @PathVariable String vehicleNumber) {

        VehicleApiResponseVO response = vehicleInfoService.getVehicleInfo(vehicleNumber);

        if (response.isSuccess()) {
            return ResponseEntity.ok(response);
        } else {
            return ResponseEntity.badRequest().body(response);
        }
    }

    /**
     * 일괄 조회
     */
    @PostMapping("/batch")
    public ResponseEntity<List<VehicleApiResponseVO>> getVehicles(
            @RequestBody List<String> vehicleNumbers) {

        List<VehicleApiResponseVO> responses =
            vehicleInfoService.getVehiclesInfo(vehicleNumbers);

        return ResponseEntity.ok(responses);
    }
}
```

### 9.2 Service Layer에서 사용

```java
@Service
@RequiredArgsConstructor
public class InspectionService {

    private final VehicleInfoService vehicleInfoService;

    public void performInspection(String vehicleNumber) {
        // 1. 차량 정보 조회
        VehicleApiResponseVO vehicleInfo =
            vehicleInfoService.getVehicleInfo(vehicleNumber);

        if (!vehicleInfo.isSuccess()) {
            throw new VehicleNotFoundException(vehicleNumber);
        }

        // 2. 차량 정보를 사용한 비즈니스 로직
        VehicleBasicInfoVO basicInfo = vehicleInfo.getBasicInfo();
        String ownerName = basicInfo.getVhrNm();  // 소유자명
        String modelYear = basicInfo.getYridnw(); // 연식

        // 3. 검사 수행
        // ...
    }
}
```

### 9.3 응답 데이터 활용

```java
VehicleApiResponseVO response = vehicleInfoService.getVehicleInfo("12가3456");

if (response.isSuccess()) {
    // 기본정보 활용
    VehicleBasicInfoVO basic = response.getBasicInfo();
    System.out.println("차량번호: " + basic.getVhrno());
    System.out.println("소유자: " + basic.getVhrNm());
    System.out.println("차종: " + basic.getVhctyNm());
    System.out.println("용도: " + basic.getVhclPrposNm());

    // 등록원부 활용
    VehicleLedgerVO ledger = response.getLedgerInfo();
    System.out.println("최초등록일: " + ledger.getFrstRegistDe());
    System.out.println("등록상태: " + ledger.getRegistSttusNm());
} else {
    System.err.println("조회 실패: " + response.getMessage());
}
```

### 9.4 일괄 조회 예제

```java
List<String> vehicleNumbers = Arrays.asList(
    "12가3456",
    "34나5678",
    "56다7890"
);

List<VehicleApiResponseVO> responses =
    vehicleInfoService.getVehiclesInfo(vehicleNumbers);

// 성공/실패 분류
List<VehicleApiResponseVO> successful = responses.stream()
    .filter(VehicleApiResponseVO::isSuccess)
    .collect(Collectors.toList());

List<VehicleApiResponseVO> failed = responses.stream()
    .filter(r -> !r.isSuccess())
    .collect(Collectors.toList());

System.out.println("성공: " + successful.size());
System.out.println("실패: " + failed.size());
```

---

## 10. 모드 전환 시나리오

### 10.1 개발 → 운영 전환

```yaml
# 개발 환경 (application-local.yml)
vmis:
  integration:
    mode: internal
  gpki:
    enabled: "N"  # GPKI 비활성화
```

```yaml
# 운영 환경 (application-prod.yml)
vmis:
  integration:
    mode: internal
  gpki:
    enabled: "Y"  # GPKI 활성화
  system:
    infoSysIp: "${SERVER_IP}"  # 실제 서버 IP
```

### 10.2 Monolithic → MSA 전환

```yaml
# Phase 1: 단일 애플리케이션 (Internal Mode)
vmis:
  integration:
    mode: internal
```

```yaml
# Phase 2: 마이크로서비스 (External Mode)
vmis:
  integration:
    mode: external
  external:
    api:
      url: "http://vmis-service:8080/api/v1/vehicles"
```

**코드 변경 없이 설정만으로 전환 가능!**

---

## 11. 트러블슈팅

### 11.1 Bean 충돌 오류

**증상:**
```
expected single matching bean but found 2:
internalVehicleInfoServiceImpl, externalVehicleInfoServiceImpl
```

**원인:**
`vmis.integration.mode` 설정이 잘못되었거나 누락됨

**해결:**
```yaml
vmis:
  integration:
    mode: internal  # 또는 external (반드시 지정)
```

### 11.2 Mapper 중복 스캔 경고

**증상:**
```
Skipping MapperFactoryBean with name 'vmisCarBassMatterInqireMapper'
Bean already defined with the same name!
```

**원인:**
여러 `@MapperScan`에서 같은 패키지를 중복 스캔

**해결:**
`ApiMapperConfig`에서 API 전용 Mapper만 스캔하도록 분리되어 있음

### 11.3 GPKI 오류 (운영 환경)

**증상:**
```
GPKI 초기화 실패: 인증서 파일을 찾을 수 없습니다
```

**해결:**
1. GPKI 인증서 파일 경로 확인
2. 개발 환경에서는 `gpki.enabled: "N"` 설정

---

## 12. 성능 최적화

### 12.1 Internal Mode 최적화
- RestTemplate Connection Pool 설정 활용
- GPKI 세션 재사용
- DB 커넥션 풀 튜닝

### 12.2 External Mode 최적화
- 외부 API 서버와 동일 네트워크 배치
- Circuit Breaker 패턴 적용 (향후)
- 캐싱 전략 (향후)

---

## 13. 보안 고려사항

### 13.1 GPKI 인증서 관리
- 인증서 파일 접근 권한 제한
- 패스워드는 환경변수로 관리
- 인증서 만료 모니터링

### 13.2 API Key 관리
```yaml
vmis:
  gov:
    services:
      basic:
        apiKey: "${GOV_API_KEY_BASIC}"  # 환경변수 사용
```

### 13.3 로깅 주의사항
- 차량번호 등 개인정보는 마스킹 처리
- 요청/응답 전문은 DEBUG 레벨로 출력

---

## 14. 확장 가능성

### 14.1 새로운 모드 추가
Strategy Pattern을 사용하므로 새로운 구현체 추가 가능:

```java
@Service
@ConditionalOnProperty(name = "vmis.integration.mode", havingValue = "cache")
public class CachedVehicleInfoServiceImpl implements VehicleInfoService {
    // 캐시 기반 구현
}
```

### 14.2 새로운 차량 정보 조회 API 추가
1. 정부 API 인터페이스 메서드 추가
2. Service 계층에 메서드 추가
3. Mapper 및 Model 추가
4. VehicleInfoService 인터페이스 확장

---

## 15. 참고 자료

### 15.1 관련 설정 파일
- `src/main/resources/application.yml`
- `src/main/resources/mybatis/mapper/api-internal/`

### 15.2 관련 문서
- Spring Boot Conditional Beans
- Strategy Pattern
- MyBatis Integration

---

**문서 버전:** 1.0
**최종 수정일:** 2025-11-07
**작성자:** VIPS Development Team
