# 공통코드 Redis 캐시 시스템 - DanielLee

##  요구사항 검토

### 1. **API를 통해 공통코드 제공** 
- **구현 완료**: `CommonCodeApiController`에서 전체 공통코드 조회 API 제공
  ```
  GET /api/code
  → 모든 공통코드 조회
  ```
- **추가 구현**: 캐시 갱신 및 상태 확인 API
  ```
  POST /api/code/cache/refresh     → 캐시 갱신
  GET  /api/code/cache/status      → 캐시 상태 확인
  ```

---

### 2. **애플리케이션 로딩시 Redis 캐시에 올리기** 
- **구현 완료**: `CommonCodeCacheManager` 클래스 생성

#### 초기화 메커니즘
```java
@Component
@RequiredArgsConstructor
public class CommonCodeCacheManager {

  @EventListener(ApplicationReadyEvent.class)
  public void initializeCommonCodeCache() {
    // 애플리케이션 완전히 시작된 후 공통코드를 Redis에 미리 로드
    List<Basic> allCommonCodes = commonCodeService.getFindAll();
    // @Cacheable이 자동으로 Redis에 캐시함
  }
}
```

#### 동작 흐름
1. 애플리케이션 시작
2. Spring이 모든 Bean 생성 완료 (`ApplicationReadyEvent` 발생)
3. `CommonCodeCacheManager.initializeCommonCodeCache()` 실행
4. `commonCodeService.getFindAll()` 호출 (DB에서 조회)
5. `@Cacheable(value = "commonCodes")` 에노테이션이 결과를 Redis에 저장

---

### 3. **공통코드 변경시 데이터 갱신** 

#### 자동 갱신
- **등록 (CREATE)**: `@CacheEvict` → 캐시 전체 삭제
- **수정 (UPDATE)**: `@CacheEvict` → 캐시 전체 삭제
- **삭제 (DELETE)**: `@CacheEvict` → 캐시 전체 삭제
- **순서 변경**: `@CacheEvict` → 캐시 전체 삭제

```java
@CacheEvict(value = "commonCodes", allEntries = true)
public ResponseObj save(CommonCodeDto.AddReq req) {
  // 공통코드 저장
  // ↓
  // 캐시 전체 삭제 (다음 조회 시 DB에서 새로 로드)
}
```

#### 수동 갱신 (관리자)
```java
POST /api/code/cache/refresh
```
- 공통코드 설정이 변경된 후 API를 호출하여 캐시를 강제 갱신

#### 캐시 상태 모니터링
```java
GET /api/code/cache/status
→ 응답: { "data": 150 }  // 캐시된 공통코드 150개
```

---

## 전체 아키텍처

```
┌─────────────────────────────────────────────────────────┐
│   클라이언트 요청                                         │
└──────────────────┬──────────────────────────────────────┘
                   │
        ┌──────────▼──────────┐
        │ CommonCodeApiController
        └──────────┬──────────┘
                   │
         ┌─────────┴──────────┐
         │                    │
    ┌────▼─────┐      ┌──────▼────────────┐
    │ 조회 API │      │ 캐시 관리 API      │
    │ (GET)    │      │(POST, GET)         │
    └────┬─────┘      └──────┬────────────┘
         │                   │
         │          ┌────────▼──────────┐
         │          │CommonCodeCacheManager
         │          │(캐시 초기화/갱신)  │
         │          └────────┬──────────┘
         │                   │
    ┌────▼─────────────────┬─▼────┐
    │ CommonCodeService    │      │
    │ (@Cacheable)         │      │
    │ (@CacheEvict)        │      │
    └────┬──────────────────┴──────┘
         │
    ┌────▼──────────┐
    │ Redis 캐시    │
    │ (공통코드)    │
    └────┬──────────┘
         │
    ┌────▼──────────┐
    │ PostgreSQL DB │
    │ (공통코드)    │
    └───────────────┘
```

---

## API 명세

### 1. 공통코드 조회 (캐시됨)
```
GET /api/code

응답:
{
  "data": [
    {
      "id": 1,
      "code": "STATUS",
      "name": "상태",
      "description": "상태 공통코드",
      "used": true,
      ...
    },
    ...
  ]
}
```

### 2. 공통코드 캐시 갱신
```
POST /api/code/cache/refresh

응답:
{
  "data": "공통코드 캐시가 갱신되었습니다."
}
```

### 3. 캐시 상태 확인
```
GET /api/code/cache/status

응답:
{
  "data": 150  // Redis에 캐시된 공통코드 개수
}
```

---

## 캐시 갱신 흐름

### 자동 갱신 (CRUD 작업)
```
관리자가 공통코드 등록/수정/삭제
        ↓
CommonCodeService.save() / update() / removeCode()
(@CacheEvict 실행)
        ↓
Redis 캐시 전체 삭제
        ↓
다음 조회 시 DB에서 새로 로드
```

### 수동 갱신 (API 호출)
```
관리자: POST /api/code/cache/refresh
        ↓
CommonCodeCacheManager.refreshCommonCodeCache()
        ↓
캐시 정리 + 새로운 데이터 로드
        ↓
Redis 캐시 업데이트 완료
```

---

## 성능 최적화 효과

| 항목 | 개선 전 | 개선 후 |
|------|--------|--------|
| **조회 속도** | DB 직접 조회 (10-100ms) | Redis 캐시 (1-5ms) | 
| **DB 부하** | 매번 조회 | 캐시 미스시만 조회 |
| **네트워크 대역폭** | 높음 (DB 왕복) | 낮음 (로컬 캐시) |
| **응답 시간** | 변동적 | 일정 (캐시) |

---

## 추가 기능

### CommonCodeUtil - 전역 공통코드 조회
```java
@Component
public class CommonCodeUtil {
  // 모든 공통코드 조회 (캐시 활용)
  public List<Basic> getAllCommonCodes()
  
  // 특정 코드로 조회
  public List<Basic> getCommonCodesByCode(String code)
  
  // ID로 단건 조회
  public Optional<Basic> getCommonCodeById(Long id)
  
  // 코드명 조회
  public Optional<String> getCodeName(String parentCode, String childCode)
  
  // 하위 코드 조회
  public List<Basic> getChildCodesByParentCode(String parentCode)
  
  // 코드 사용 가능 여부 확인
  public boolean isCodeAvailable(Long parentId, String code)
}
```

### 사용 예시
```java
@RequiredArgsConstructor
@RestController
public class SomeController {
  
  private final CommonCodeUtil commonCodeUtil;
  
  @GetMapping("/example")
  public void example() {
    // 1. 모든 공통코드 조회 (캐시됨)
    List<Basic> allCodes = commonCodeUtil.getAllCommonCodes();
    
    // 2. 특정 코드 조회
    Optional<String> name = commonCodeUtil.getCodeName("PARENT", "CHILD");
    
    // 3. 코드 사용 가능 여부 확인
    boolean available = commonCodeUtil.isCodeAvailable(1L, "NEW_CODE");
  }
}
```

---

## 완료 체크리스트

-  Redis 캐싱 어노테이션 적용 (@Cacheable, @CacheEvict)
-  애플리케이션 로딩시 캐시 초기화
-  CRUD 작업시 자동 캐시 갱신
-  수동 캐시 갱신 API 제공
-  캐시 상태 모니터링 API
-  전역 공통코드 조회 유틸리티
-  포괄적인 유닛 테스트 (12개)

---

## 모니터링

캐시 상태를 주기적으로 모니터링:
```bash
# 캐시 상태 확인
curl http://localhost:8080/api/code/cache/status

# 캐시 갱신
curl -X POST http://localhost:8080/api/code/cache/refresh
```

로그 확인:
```
=== 공통코드 캐시 초기화 시작 ===
✓ 공통코드 150개가 Redis 캐시에 로드되었습니다.
  - [STATUS] 상태 (ID: 1)
  - [TYPE] 타입 (ID: 2)
  ...
=== 공통코드 캐시 초기화 완료 ===
```
