DOCS/troubleshooting/250823_happybell80_rb8001_레벨1_표시_문제.md

210 lines
5.6 KiB
Markdown

# rb8001 레벨 1 표시 문제 해결
## 작성일: 2025-08-23 (수정: 2025-08-28)
## 작성자: happybell80 with Claude
## 상태: ✅ 해결 완료
---
## 1. 문제 상황
### 증상
- DB에 rb8001의 레벨이 20으로 저장되어 있음
- 프론트엔드에서는 계속 레벨 1로 표시됨
- `/api/stats/rb8001` 요청시 기본값(레벨 1) 반환
### 영향
- 사용자가 로빙의 실제 성장 상태를 확인할 수 없음
- Gmail 아이템 등 레벨 기반 기능 사용 제한
---
## 2. 원인 분석
### 2.1 Gateway의 하드코딩 문제
**위치**: `robeing-gateway/app/main.py:267`
```python
# 문제 코드
response = await http_client.get(
f"http://192.168.219.52:10508/api/stats/{robeing_id}" # 항상 rb10508_micro로!
)
```
**문제점**:
- 모든 stats 요청을 rb10508_micro(포트 10508)로 강제 라우팅
- 사용자별 로빙 무시
### 2.2 프론트엔드 헤더 누락
**위치**: `frontend-customer/src/services/robeing-api.ts:447`
```typescript
// 문제 코드
const response = await fetch(`${ROBEING_API_URL}/api/stats/${robeingId}`);
// X-User-Id 헤더 없음!
```
**문제점**:
- Gateway가 사용자를 식별할 수 없음
- 기본값 반환
### 2.3 잘못된 엔드포인트 경로
**실제 엔드포인트**:
- rb8001: `/stats` (api 없음)
- rb10508_micro: `/stats/{robeing_id}` (api 없음)
**Gateway 요청**:
- `/api/stats/{robeing_id}` → 404 에러
### 2.4 서버 위치 오류
**Gateway 설정**:
- rb8001: `http://localhost:8001` → 51123 서버에 없음
**실제 위치**:
- rb8001: `http://192.168.219.52:8001` (51124 서버)
### 2.5 ~~State Service 연결 실패~~ (제거됨 - State Service 사용 안 함)
- ~~State Service는 더 이상 사용하지 않음~~
- rb8001이 직접 DB 접근하여 스탯 조회
---
## 3. 해결 과정
### 3.1 Gateway 사용자별 라우팅 구현
```python
# robeing-gateway/app/main.py
@app.get("/api/stats/{robeing_id}")
async def get_stats(
robeing_id: str,
x_user_id: Optional[str] = Header(None) # 사용자 식별 추가
):
# 사용자별 로빙 정보 조회
robeing_info = await get_robeing_info(x_user_id)
# 로빙별 올바른 서버로 라우팅
if robeing_id == "rb8001":
target_url = f"http://192.168.219.52:8001/stats"
elif robeing_id == "rb10508_micro":
target_url = f"http://192.168.219.52:10508/stats/{robeing_id}"
```
### 3.2 프론트엔드 헤더 추가
```typescript
// frontend-customer/src/services/robeing-api.ts
const headers: HeadersInit = {
'X-User-Id': userId,
'Authorization': `Bearer ${authToken}`
};
const response = await fetch(`${ROBEING_API_URL}/api/stats/${robeingId}`, {
headers
});
```
### 3.3 응답 형식 정규화
```python
# rb8001 응답 형식 변환
if robeing_id == "rb8001" and "stats" in data:
return {
"robeing_id": robeing_id,
"level": data.get("level", 1),
"experience": stats_data.get("experience", 0),
# ... 표준 형식으로 변환
}
```
---
## 4. 해결 진행 (2025-08-28)
### 4.1 완료된 작업 ✅
- **robeing-monitor**: state_service를 `/api` 경로로 마운트
- **Gateway**: 모든 로빙을 robeing-monitor로 통합
```python
# 조건문 제거, 모든 로빙 통합
target_url = f"http://192.168.219.52:9024/api/stats/{robeing_id}"
```
- **DB**: robeing_stats에 스탯 컬럼 추가 (memory, compute 등)
- **테스트**: robeing-monitor 직접 호출 시 레벨 20 반환 확인
### 4.2 새로운 문제 발견 및 해결 완료 ✅
**robeing_id가 undefined로 전달됨**
```
Gateway 로그:
GET /api/stats/undefined HTTP/1.0" 200 OK
GET /api/user/robeing → 404 Not Found
```
**원인**: Frontend가 잘못된 엔드포인트 호출
- 시도: `/api/user/robeing` (없음)
- 실제: `/api/robeing/info` (Gateway에 있음)
**해결 완료 (로컬 개발자)**:
1. **Gateway**: `/api/robeing/info` JWT 인증 적용 ✅
```python
x_user_id: str = Depends(get_verified_user)
```
2. **Frontend**: 엔드포인트 변경 ✅
```javascript
// 변경 전: /api/user/robeing
// 변경 후: /api/robeing/info
```
### 4.3 라우트 우선순위 문제 (2025-08-28 추가)
**문제 발견**: `/api/robeing/info`가 작동 안함
```
GET http://192.168.219.52:8001/api/robeing/info → 404 Not Found
```
**원인**: FastAPI 라우트 정의 순서
- `/api/{path:path}` (line 408) - catch-all 패턴이 먼저 매칭
- `/api/robeing/info` (line 431) - 도달하지 못함
- 결과: robeing/info가 rb8001로 프록시되어 404
**해결 필요**:
- `/api/robeing/info`를 `/api/{path:path}`보다 앞에 정의
- 또는 catch-all 패턴에서 robeing/info 제외
### 4.4 최종 플로우 ✅ 해결 완료
```
Frontend (JWT) → Gateway /api/stats/rb8001 → robeing-monitor → DB
레벨 20 정상 반환 및 표시
```
**해결 완료 (2025-08-28 16:40)**:
- Frontend가 레벨 20 정상 표시
- DB 값이 UI에 올바르게 반영됨
---
## 5. 교훈
### 아키텍처 일관성
- 모든 로빙이 동일한 API 경로 규칙을 따라야 함
- `/api/stats` vs `/stats` 혼용 문제
### 헤더 전달 중요성
- 프론트엔드는 항상 사용자 식별 헤더 포함 필요
- X-User-Id, Authorization 등
### 환경변수 관리
- 필수 서비스 URL은 반드시 설정
- 누락시 fallback 처리 필요
### 디버깅 체인
1. 프론트엔드 요청 확인
2. Gateway 라우팅 확인
3. 실제 서비스 엔드포인트 확인
4. 서비스 내부 로직 확인
---
## 6. 참고 파일
- `robeing-gateway/app/main.py`
- `frontend-customer/src/services/robeing-api.ts`
- `rb8001/main.py`
- `rb8001/app/router/router.py`
- `rb8001/docker-compose.yml`