diff --git a/troubleshooting/250822_happybell80_사용자격리_404에러_해결.md b/troubleshooting/250822_happybell80_사용자격리_404에러_해결.md new file mode 100644 index 0000000..968f29f --- /dev/null +++ b/troubleshooting/250822_happybell80_사용자격리_404에러_해결.md @@ -0,0 +1,243 @@ +# 사용자 격리 및 404 에러 해결 + +## 날짜: 2025-08-22 +## 작성자: happybell80 & Claude +## 관련 서비스: rb10508_micro, robeing-gateway, auth-server, robeing-monitor + +--- + +## 1. 문제 상황 요약 + +### 발견된 문제들 +1. **모든 사용자가 "default"로 처리** + - info@ro-being.com과 goeun2dc@gmail.com이 같은 대화 기록 공유 + - 보안 및 프라이버시 심각한 문제 + +2. **OAuth 사용자 DB 저장 안 됨** + - info@ro-being.com이 로그인했지만 DB에 없음 + - auth-server의 DB 저장 코드가 주석 처리됨 + +3. **404 에러 지속 발생** + - `/api/items/gmail` 엔드포인트 404 + - `/api/stats/{robeing_id}` 엔드포인트 404 + +--- + +## 2. 원인 분석 + +### 2.1 사용자 격리 문제 + +#### 근본 원인 체인 +``` +Frontend (JWT) → Gateway (username) → rb10508 (default) → ChromaDB (공유) +``` + +#### 문제점들 +- rb10508_micro의 `MessageRequest`에 `user_id` 기본값 "default_user" 하드코딩 +- Gateway가 username을 UUID로 변환하지 않음 +- JWT 파싱 로직이 잘못되어 사용자 식별 실패 + +### 2.2 OAuth DB 저장 문제 + +#### auth-server/app/providers/gmail.py:163-175 +```python +# TODO: 실제 DB 세션 사용 +# db = next(get_db()) +# user = db.query(User).filter(User.email == user_email).first() +# ... (주석 처리된 DB 저장 코드) +``` + +### 2.3 404 에러 원인 + +#### 라우팅 체인 문제 +``` +Frontend → Nginx → Gateway → robeing-monitor + ↓ + 404 (경로 불일치) +``` + +- 프론트엔드: `/api/items/gmail` 요청 +- robeing-monitor: `/api/gmail`만 구현 +- Gateway 프록시 설정 누락 + +--- + +## 3. 해결 과정 + +### 3.1 Phase 1: 사용자 격리 수정 + +#### rb10508_micro/app/api/endpoints.py +```python +# Before +class MessageRequest(BaseModel): + user_id: Optional[str] = "default_user" # 문제! + +# After +class MessageRequest(BaseModel): + user_id: Optional[str] = None # 기본값 제거 + +# 임시 ID 생성 로직 추가 +if not user_id: + client_ip = req.client.host if req.client else "unknown" + user_id = f"guest_{client_ip}_{datetime.now().strftime('%Y%m%d%H%M%S')}" +``` + +### 3.2 Phase 2: OAuth DB 저장 활성화 + +#### auth-server/app/providers/gmail.py +```python +# 주석 해제 및 수정 +db = SessionLocal() +try: + user = db.query(User).filter(User.email == user_email).first() + if not user: + user = User( + id=uuid.uuid4(), + email=user_email, + username=username, + name=user_name, + oauth_provider='google', + oauth_id=user_info.get('id', '') + ) + db.add(user) + db.commit() + logger.info(f"New user created: {username} ({user_email})") +``` + +### 3.3 Phase 3: Gateway UUID 변환 + +#### robeing-gateway/app/main.py +```python +# Username을 UUID로 변환 +from app.database import get_user_by_username +user_uuid = x_user_id + +if x_user_id and x_user_id != "default": + user_info = await get_user_by_username(x_user_id) + if user_info: + user_uuid = user_info['user_id'] # UUID 사용 + logger.info(f"Username to UUID: {x_user_id} → {user_uuid}") +``` + +### 3.4 Phase 4: JWT 파싱 개선 + +#### robeing-gateway/app/main.py +```python +def get_verified_user(authorization: Optional[str] = Header(None)): + if not authorization or not authorization.startswith("Bearer "): + logger.warning("No Authorization header or invalid format") + return "default" + + try: + token = authorization.replace("Bearer ", "") + payload = jwt.decode(token, JWT_SECRET_KEY, algorithms=["HS256"]) + + # JWT payload 로깅 (디버깅용) + logger.info(f"JWT payload: {payload}") + + # sub (subject)가 username임 + username = payload.get("sub") or payload.get("username") or payload.get("user_id") + + if username: + logger.info(f"Authenticated user: {username}") + return username +``` + +### 3.5 Phase 5: 404 에러 해결 + +#### 시도 1: robeing-monitor에 alias 추가 +```python +@router.get("/gmail") +@router.get("/items/gmail") # 프론트엔드 호환성 +``` + +#### 시도 2: Gateway에서 경로 변환 +```python +# /api/items/gmail → /api/gmail로 변환 +if path.startswith("gmail"): + actual_path = path +else: + actual_path = f"items/{path}" +``` + +#### 시도 3: Frontend API 경로 수정 +```typescript +// Before +const response = await fetch(`/api/stats/${robeingId}`); + +// After +const response = await fetch(`${ROBEING_API_URL}/api/stats/${robeingId}`); +``` + +--- + +## 4. 테스트 결과 + +### 4.1 성공한 부분 +- ✅ OAuth DB 저장: info@ro-being.com 사용자 생성 확인 +- ✅ ChromaDB 정상 작동: 13개 컬렉션, 524개 문서 +- ✅ 메모리 저장 가능 +- ✅ POST 요청 도달 시작 + +### 4.2 남은 문제 +- ⚠️ 일부 사용자는 여전히 "default"로 처리 +- ⚠️ `/api/items/gmail` 404 지속 (Nginx 설정 필요) + +--- + +## 5. 파일명 정리 + +### robing → robeing 변경 +- `robing-api.ts` → `robeing-api.ts` +- `robing-avatar.png` → `robeing-avatar.png` + +**"robing"은 금지된 용어** + +--- + +## 6. 아키텍처 논의 + +### robeing-monitor의 존재 이유 +- **철학적**: 로빙의 "아이템 인벤토리" 개념 +- **기술적**: 불필요한 중간 계층 + +### 로빙 철학 +- 존재형 에이전트: 도구가 아닌 동료 +- 성장하는 디지털 생명체 +- 게임화된 인터페이스 (레벨, 스탯, 아이템) + +--- + +## 7. 교훈 + +### 7.1 ID 체계 일관성 +- Frontend: username (JWT) +- Backend: UUID (PostgreSQL) +- 변환 로직 필수 + +### 7.2 코드 주석 주의 +- TODO 주석은 반드시 추적 +- 핵심 기능을 주석 처리하면 안 됨 + +### 7.3 디버깅 전략 +1. 각 서비스 개별 테스트 +2. 로그를 통한 데이터 흐름 추적 +3. curl로 직접 테스트 + +### 7.4 철학과 기술의 균형 +- 기술적 효율성 vs 프로젝트 비전 +- 로빙의 게임화 철학 존중 필요 + +--- + +## 8. 관련 커밋 + +- rb10508_micro: 사용자 격리 수정 +- auth-server: OAuth DB 저장 활성화 +- robeing-gateway: UUID 변환 및 JWT 파싱 개선 +- robeing-monitor: 경로 alias 추가 +- frontend-customer: 파일명 정리 및 API 경로 수정 + +--- + +**문서 끝** \ No newline at end of file