# Implementation Report: 국제 시세 커모디티 페이지 + 캐시 수리

## Summary
Alpha Vantage 기반 국제 시세 페이지 7종(구리·알루미늄·밀·섬유(면화)·설탕·커피·원자재 지수)을 단일 라우트 `Price/Global/{commodity}` + 공용 모델/뷰로 구현. `_Layout.cshtml` 국제 시세 드롭다운 복원(8개 링크). IMemoryCache DI 도입으로 캐시가 실제로 동작하게 수리(2차 요청 5ms 실측). 기존 버그 3건(원화 항상 0, 페이지네이션 interval 초기화, 환율 조회 레이스) 수정. 금/석유/배출권 조용한 실패에 alert 표출 추가.

## Assessment vs Reality

| Metric | Predicted (Plan) | Actual |
|---|---|---|
| Complexity | Medium | Medium |
| Confidence | 8/10 | 적중 (통합테스트에서 환경 이슈 1건 발견·수정) |
| Files Changed | 9 | 11 |

## Tasks Completed

| # | Task | Status | Notes |
|---|---|---|---|
| 1 | Commodity Request/Response 모델 | ✅ | |
| 2 | GlobalModel GetCommodityPriceInfo + 캐시 | ✅ | 빈 응답 미캐시, JsonDocument 래퍼 제거 |
| 3 | GlobalController 매핑+공용 액션+버그수정 | ✅ | GetExchangeValueAsync 헬퍼 추가(하단 Deviations) |
| 4 | Commodity.cshtml 공용 뷰 | ✅ | interval 셀렉트, unit caption, KRW 열 토글 |
| 5 | commodity.js | ✅ | interval 변경 시 page=1 리셋 |
| 6 | Program.cs AddMemoryCache | ✅ | 인코딩 보존 위해 sed로 삽입(19행) |
| 7 | _Layout.cshtml 메뉴 복원 | ✅ | 8개 링크, 기존 미커밋 변경 보존 |
| 8 | 금/석유/배출권 오류 표출 | ✅ | else 분기 + ViewBag.isError |

## Validation Results

| Level | Status | Notes |
|---|---|---|
| Build | ✅ Pass | `dotnet build` 0 errors (신규 경고: 뷰 CS8602 1건 — 기존 패턴과 동일 수준) |
| Unit Tests | N/A | repo에 테스트 프로젝트 없음(계획에서 범위 외로 명시) |
| Integration | ✅ Pass | 별도 출력 빌드 + localhost:5099 스모크 |
| Edge Cases | ✅ Pass | 아래 표 |

### 통합 테스트 실측 (2026-07-22)

| 케이스 | 결과 |
|---|---|
| `/Price/Global/copper` 1차 | 200, 3.7s (환율 3s 타임아웃 + Alpha 호출) |
| `/Price/Global/copper` 2차 | 200, **0.005s** (캐시 적중) |
| wheat/cotton/sugar/coffee/aluminum | 전부 200, ~0.2s |
| `/Price/Global/allcommodities` | 200, 원화 열 없음·"지수" 헤더 확인 |
| `/Price/Global/xyz` | 404 |
| `/Price/Global/copper?interval=daily` | 400 (사전 차단) |
| `/Price/Global/copper?interval=quarterly` | 200 |
| `/Price/Global/NaturalGas` | 200 (기존 URL 유지) |
| `/Price/Domestic/Gold` | 200 + 실데이터(20260721 행 확인 — data.go.kr 승인 반영) |
| `/Price/Domestic/Oil`, `/Emission` | 200 |
| 구리 페이지 본문 | 제목 "구리 시세", 단위 "dollar per metric ton", 값 "13,552.04" 포맷 확인 |

## Files Changed

| File | Action |
|---|---|
| `Models/Request/Price/Global/Commodity.cs` | CREATED |
| `Models/Response/Price/Global/Commodity.cs` | CREATED |
| `Views/Price/Global/Commodity.cshtml` | CREATED |
| `wwwroot/js/commodity.js` | CREATED |
| `Controllers/Price/GlobalController.cs` | UPDATED (매핑, 공용 액션, 버그 3건, 환율 헬퍼) |
| `Models/Price/GlobalModel.cs` | UPDATED (IMemoryCache 주입, GetCommodityPriceInfo, 캐시 키 수정) |
| `Program.cs` | UPDATED (AddMemoryCache, 19행) |
| `Views/Shared/_Layout.cshtml` | UPDATED (국제 시세 메뉴 복원) |
| `Controllers/Price/Domestic/GoldController.cs` | UPDATED (오류 표출) |
| `Controllers/Price/Domestic/OilController.cs` | UPDATED (오류 표출) |
| `Controllers/Price/Domestic/EmissionController.cs` | UPDATED (오류 표출) |

## Deviations from Plan
1. **환율 조회 3초 타임아웃 + 실패값 5분 네거티브 캐시 추가** — 통합 테스트에서 한국수출입은행 API가 이 환경에서 SSL 오류/무응답 행(hang)을 일으켜 페이지가 HttpClient 기본 100초까지 지연되는 문제 발견. `Task.WhenAny` 3초 상한으로 페이지 지연 차단, 실패 시 원화 0 표시(기존 동작과 동일). 기존 코드는 fire-and-forget 레이스 버그 때문에 우연히 안 막혔던 것.
2. **feature 브랜치 미생성(main 유지)** — 사용자 워크플로가 main 직커밋이고, 더티 트리에 이 기능의 전제인 미커밋 변경(data.go.kr 키 교체)이 존재. 커밋은 사용자 지시 대기.
3. **NaturalGas 액션에도 오류 alert 추가** — 계획은 Commodity에만 명시했으나 일관성 위해 동일 적용.
4. Program.cs는 CP949로 추정되는 파일 인코딩 보존을 위해 Edit 대신 `sed` 바이트 삽입 사용.

## Issues Encountered
- 빌드 시 `economy.exe` 잠김(사용자 실행 중 인스턴스 PID 75640) → 별도 출력 폴더(`-o`) 빌드로 우회, 실행 중 앱 무간섭. **사용자 앱 재시작 전까지 로컬 실행 인스턴스에는 변경이 반영되지 않음.**
- 한국수출입은행 환율 API가 이 환경에서 SSL 실패/행 → Deviation 1로 해결. 운영 환경에서 정상이면 원화 열 자동 표시됨.

## Next Steps
- [ ] 사용자 로컬 앱 재시작 후 메뉴 확인
- [ ] 커밋 + 운영 배포 (data.go.kr 신 키가 운영에 반영되어야 금/석유/배출권 정상화)
- [ ] (선택) FinancialModel의 per-instance 캐시도 IMemoryCache 주입으로 전환
