- 7-8월 초기 구축 문서 12개를 _archive/troubleshooting/2025_07-08_initial_setup/로 이동 - book/300_architecture/390_human_in_the_loop_intent_learning.md를 journey/research/intent_classification/로 이동 (개발 여정 문서) - 빈 폴더 제거 (journey/assets/*)
275 lines
6.4 KiB
Markdown
275 lines
6.4 KiB
Markdown
# 사용자별 로빙 연결 및 레벨 표시 문제 해결
|
|
|
|
## 작성일: 2025-08-25
|
|
## 작성자: happybell80
|
|
## 관련 서비스: auth-server, frontend-customer, robeing-gateway, rb8001
|
|
|
|
---
|
|
|
|
## 오후 1시 30분
|
|
|
|
### 문제 상황 1: 사용자별 로빙 연결 안됨
|
|
|
|
**증상**:
|
|
- `goeun2dc@gmail.com`으로 로그인 시 `rb10508_micro`로 연결됨
|
|
- 실제로는 `happybell80` → `rb8001`로 연결되어야 함
|
|
- DB에는 올바른 매핑이 있지만 실제 동작하지 않음
|
|
|
|
**DB 확인 결과**:
|
|
```sql
|
|
-- users 테이블
|
|
username: happybell80
|
|
email: goeun2dc@gmail.com
|
|
UUID: 1e16e9d5-59f3-54da-a661-8abeabff4230
|
|
|
|
-- workspace_member 테이블
|
|
happybell80 → rb8001 (포트 8001)
|
|
eagle0914 → rb10508_micro (포트 10508)
|
|
```
|
|
|
|
**원인 분석**:
|
|
auth-server의 gmail.py가 DB의 username을 사용하지 않고 이메일 기반 매핑 또는 이메일 앞부분 사용
|
|
|
|
---
|
|
|
|
## 오후 1시 45분
|
|
|
|
### 해결 1: auth-server JWT 토큰 수정
|
|
|
|
#### 수정 파일: auth-server/app/providers/gmail.py
|
|
|
|
**변경 전** (line 182-191):
|
|
```python
|
|
else:
|
|
# 기존 사용자 정보 업데이트
|
|
user.name = user_name
|
|
user.oauth_provider = 'google'
|
|
user.oauth_id = user_info.get('id', '')
|
|
db.commit()
|
|
logger.info(f"Existing user updated: {username} ({user_email})")
|
|
|
|
# 사용자 ID 사용 (UUID string)
|
|
user_id_str = str(user.id)
|
|
username = user.username # 문제: 새 사용자는 username이 없음
|
|
```
|
|
|
|
**변경 후**:
|
|
```python
|
|
else:
|
|
# 기존 사용자 정보 업데이트 및 username 가져오기
|
|
username = user.username if user.username else username # DB의 username 우선 사용
|
|
user.name = user_name
|
|
user.oauth_provider = 'google'
|
|
user.oauth_id = user_info.get('id', '')
|
|
db.commit()
|
|
logger.info(f"Existing user updated: {username} ({user_email})")
|
|
|
|
# 사용자 ID 사용 (UUID string)
|
|
user_id_str = str(user.id)
|
|
# username은 이미 설정됨 (신규: 매핑/생성, 기존: DB 값)
|
|
```
|
|
|
|
**결과**:
|
|
- JWT 토큰에 DB의 실제 username(`happybell80`) 포함
|
|
- Gateway가 올바른 로빙으로 라우팅
|
|
|
|
---
|
|
|
|
## 오후 2시 00분
|
|
|
|
### 문제 상황 2: 프론트엔드 사용자 표시
|
|
|
|
**증상**:
|
|
- UserMenu에서 email 앞부분만 표시
|
|
- ChatInterface에서 사용자 이름이 제대로 표시 안됨
|
|
|
|
**원인**:
|
|
- User 인터페이스에 username 필드 없음
|
|
- 표시 우선순위에서 username 누락
|
|
|
|
**해결 검토** (구현 예정):
|
|
```typescript
|
|
// auth-context.tsx
|
|
interface User {
|
|
id: string;
|
|
username?: string; // 추가 필요
|
|
email: string;
|
|
name?: string;
|
|
picture?: string;
|
|
}
|
|
|
|
// user-menu.tsx
|
|
const displayName = user?.username || user?.name || user?.id || user?.email?.split('@')[0];
|
|
```
|
|
|
|
---
|
|
|
|
## 오후 2시 30분
|
|
|
|
### 문제 상황 3: ChatInterface 하드코딩된 로빙 ID
|
|
|
|
**증상**:
|
|
- 모든 사용자에게 "RO-BEING #10508" 표시
|
|
- 실제 할당된 로빙 ID가 표시되지 않음
|
|
|
|
**원인**:
|
|
```tsx
|
|
// chat-interface.tsx line 441
|
|
<h3>RO-BEING #10508</h3> // 하드코딩
|
|
```
|
|
|
|
**해결**:
|
|
1. ChatInterface에 robeingId prop 추가
|
|
2. GameLayout에서 userRobeingId 전달
|
|
3. 동적 표시로 변경
|
|
|
|
```tsx
|
|
// game-layout.tsx
|
|
{React.cloneElement(centerPanel, { robeingId: userRobeingId })}
|
|
|
|
// chat-interface.tsx
|
|
interface ChatInterfaceProps {
|
|
robeingId?: string;
|
|
}
|
|
|
|
<h3>RO-BEING #{robeingId.replace('rb', '').replace('_micro', '')}</h3>
|
|
```
|
|
|
|
**결과**:
|
|
- 로그인 사용자별 올바른 로빙 ID 표시
|
|
- `happybell80` → "RO-BEING #8001"
|
|
- `eagle0914` → "RO-BEING #10508"
|
|
|
|
---
|
|
|
|
## 오후 2시 45분
|
|
|
|
### 문제 상황 4: 레벨 표시 문제
|
|
|
|
**증상**:
|
|
- 헤더에 레벨 1로 표시
|
|
- DB에는 레벨 20으로 저장되어 있음
|
|
- rb8001 서비스가 하드코딩된 레벨 1 반환
|
|
|
|
**분석**:
|
|
```python
|
|
# rb8001/main.py:116-130
|
|
@app.get("/stats")
|
|
async def get_stats():
|
|
return {
|
|
"robeing_id": "rb8001",
|
|
"stats": {
|
|
"memory": 10, # 하드코딩
|
|
"compute": 10, # 하드코딩
|
|
# ...
|
|
},
|
|
"level": 1 # 하드코딩
|
|
}
|
|
```
|
|
|
|
**API 호출 경로**:
|
|
1. Frontend: `getRobeingStats('rb8001')`
|
|
2. Gateway: `https://ro-being.com/gateway/api/stats/rb8001`
|
|
3. rb8001: 하드코딩된 레벨 1 반환
|
|
|
|
---
|
|
|
|
## 오후 3시 00분
|
|
|
|
### 레벨 문제 해결 방안
|
|
|
|
#### 옵션 1: rb8001 수정 (비권장)
|
|
- rb8001에 PostgreSQL 연결 추가
|
|
- 51123 서버 DB 조회 구현
|
|
- 프로덕션 서비스 수정 위험
|
|
|
|
#### 옵션 2: Gateway에서 DB 직접 조회 (권장)
|
|
- Gateway가 이미 51123 서버에 있음
|
|
- DB 접근 가능
|
|
- 중앙집중식 관리
|
|
- 모든 로빙 통합 처리
|
|
|
|
**Gateway 수정 계획**:
|
|
```python
|
|
@app.get("/api/stats/{robeing_id}")
|
|
async def get_stats(robeing_id: str):
|
|
# DB에서 직접 조회
|
|
conn = await asyncpg.connect(...)
|
|
row = await conn.fetchrow("""
|
|
SELECT * FROM robeing_stats
|
|
WHERE robeing_id = $1
|
|
""", robeing_id)
|
|
|
|
if row:
|
|
return {
|
|
"level": row['level'], # 실제 DB 값
|
|
"experience": row['experience'],
|
|
# ...
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 성과
|
|
|
|
### ✅ 완료된 작업
|
|
1. **auth-server 수정**
|
|
- DB username을 JWT에 포함
|
|
- 사용자별 올바른 로빙 연결
|
|
|
|
2. **frontend-customer 수정**
|
|
- ChatInterface 동적 로빙 ID 표시
|
|
- GameLayout에서 robeingId prop 전달
|
|
|
|
### 🔄 진행 중인 작업
|
|
1. **Gateway 레벨 조회**
|
|
- DB 직접 조회로 변경 필요
|
|
- rb8001 하드코딩 문제 해결
|
|
|
|
### 📋 추가 작업 필요
|
|
1. **Frontend User 타입 개선**
|
|
- username 필드 추가
|
|
- 표시 우선순위 조정
|
|
|
|
---
|
|
|
|
## 교훈
|
|
|
|
### 1. 시스템 전체 데이터 흐름 파악 중요
|
|
- Auth → Gateway → Robeing → Frontend
|
|
- 각 단계에서 데이터 변환 확인 필요
|
|
|
|
### 2. 하드코딩 제거 필수
|
|
- rb8001의 하드코딩된 stats
|
|
- ChatInterface의 하드코딩된 ID
|
|
- 동적 데이터 사용 원칙
|
|
|
|
### 3. DB와 서비스 동기화
|
|
- DB 데이터와 서비스 응답 불일치
|
|
- 단일 진실 소스(DB) 원칙 준수
|
|
|
|
### 4. JWT 토큰 설계
|
|
- username을 primary identifier로 사용
|
|
- UUID는 내부적으로만 사용
|
|
- 일관된 사용자 식별 체계
|
|
|
|
---
|
|
|
|
## 다음 단계
|
|
|
|
1. **Gateway 수정 완료**
|
|
- `/api/stats/{robeing_id}` DB 조회 구현
|
|
- 테스트 및 배포
|
|
|
|
2. **Frontend 사용자 정보 개선**
|
|
- User 인터페이스 확장
|
|
- username 우선 표시
|
|
|
|
3. **서버 배포**
|
|
- auth-server 재시작
|
|
- Gateway 재시작
|
|
- 사용자 재로그인 유도
|
|
|
|
---
|
|
|
|
**문서 끝** |