# task-1043.1 완료 보고서: 대시보드 토큰 탭 새로고침 시 즉시 갱신

## SCQA

**S**: 대시보드 토큰 탭에 30분 자동 스캔 기능(task-1039.1)이 구현되어, token-tracker.py가 주기적으로 토큰 데이터를 갱신하고 있다.

**C**: 새로고침 버튼 클릭 시 `_maybe_trigger_token_scan()`이 30분 캐시를 체크하여 최근 스캔 이후 30분이 지나지 않으면 재스캔을 스킵한다. 사용자가 수동으로 즉시 갱신할 수 없어 UX가 불편하다.

**Q**: 기존 30분 자동 스캔에 영향 없이, 새로고침 버튼 클릭 시 즉시 토큰 데이터를 갱신할 수 있는가?

**A**: `force_token_scan()` 메서드 + `?force=true` API 파라미터를 추가하여 즉시 스캔 기능 구현. 프론트엔드에서 새로고침 버튼 클릭 시 `force=true`로 API 호출, 스캔 중 로딩 스피너 표시, 실패 시 기존 데이터 유지. pyright 에러 0건, 문법 오류 0건.

## 수정 파일 목록

- `/home/jay/workspace/dashboard/server.py` — `force_token_scan()` 메서드 추가 (765~778행), GET 핸들러에 `force` 파라미터 처리 추가 (2095~2098행)
- `/home/jay/workspace/dashboard/components/TokenView.js` — `refreshing` 상태 추가 (67행), `handleForceRefresh` 함수 추가 (94~108행), 새로고침 버튼 UI 변경 (403~416행)

## 변경 상세

### 서버 (server.py)
1. **`force_token_scan()` 메서드**: 30분 캐시를 무시하고 `token-tracker.py scan` 즉시 실행. `_token_cache`와 `_token_cache_time`을 clear하여 캐시된 구 데이터 방지. 실패 시 `False` 반환 (예외 전파 없음).
2. **GET `/api/token-usage?force=true`**: `force` 파라미터 감지 시 `force_token_scan()` 호출 후 최신 데이터 반환. 기존 30분 자동 스캔(`_maybe_trigger_token_scan`) 무변경.

### 프론트엔드 (TokenView.js)
1. **`refreshing` 상태**: 스캔 진행 중 UI 상태 관리
2. **`handleForceRefresh` 함수**: `force=true` 파라미터로 API 호출, 성공 시 데이터 갱신, 실패 시 기존 데이터 유지
3. **버튼 UI**: 스캔 중 `disabled` + `cursor-not-allowed` + SVG 아이콘 `animate-spin` + 텍스트 "갱신 중..."

## 완료 조건 대조

1. 새로고침 버튼 클릭 시 즉시 토큰 데이터 갱신 → `force=true` 파라미터 + `force_token_scan()` 즉시 실행
2. 기존 30분 자동 스캔에 영향 없음 → `_maybe_trigger_token_scan()` 무변경
3. 스캔 중 사용자에게 로딩 상태 표시 → `refreshing` 상태 + 스피너 + "갱신 중..." 텍스트
4. 스캔 실패 시에도 기존 데이터 유지 → catch 블록에서 `tokenData` 미변경, 서버 `force_token_scan()`도 예외 비전파

## 발견 이슈 및 해결

### 자체 해결 (3건)
1. **캐시 무효화 누락 위험** — `force_token_scan()` 내에서 `_token_cache.clear()` + `_token_cache_time.clear()` 호출로 5분 TTL 캐시까지 초기화. 미초기화 시 강제 스캔해도 캐시된 구 데이터가 반환되는 문제 방지.
2. **중복 클릭 방지** — `refreshing` 상태일 때 버튼 `disabled` 처리로 중복 스캔 요청 차단.
3. **기존 fetchTokenData와 역할 분리** — 새로고침은 `handleForceRefresh` (force=true), 자동 갱신은 `fetchTokenData` (force 없음)으로 명확히 분리. 기존 5분 자동 갱신 로직 보존.

## 검증 결과

- pyright: 0 errors, 0 warnings, 0 informations
- server.py 문법: `ast.parse` 통과 (Syntax OK)
- black + isort: 규격 준수 (1 file left unchanged)
