161 lines
4.1 KiB
Markdown
161 lines
4.1 KiB
Markdown
# rb8001 레벨 1 표시 문제 해결
|
|
|
|
## 작성일: 2025-08-23
|
|
## 작성자: 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 추가)
|
|
|
|
### 로빙 모니터 API 활용
|
|
- **51124 서버**: robeing-monitor (포트 9024) 실행 중
|
|
- **문제**: `/api/stats/{robeing_id}` 엔드포인트가 main.py에 마운트 안됨
|
|
- **해결**: 51124에서 state_service를 main.py에 /api 경로로 마운트
|
|
- **Gateway 수정**:
|
|
```python
|
|
# rb8001 하드코딩 대신 로빙 모니터 호출
|
|
# state_service가 /api에 마운트됨
|
|
target_url = f"http://192.168.219.52:9024/api/stats/{robeing_id}"
|
|
```
|
|
|
|
---
|
|
|
|
## 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` |