diff --git a/troubleshooting/250809_happybell80_username시스템구축.md b/troubleshooting/250809_happybell80_username시스템구축.md new file mode 100644 index 0000000..3895506 --- /dev/null +++ b/troubleshooting/250809_happybell80_username시스템구축.md @@ -0,0 +1,248 @@ +# Username 시스템 구축 및 사용자 식별 개선 + +작성일: 2025년 8월 9일 +작성자: happybell80 + +## 오후 5시 30분 + +### 사용자 식별 문제 - "User"만 표시되는 현상 + +#### 문제 상황 +- 로그인 후 사용자명이 "User"로만 표시 +- happybell80(실제 사용자 ID)이 표시되지 않음 +- 로빙과 통신 시 사용자 식별 불가능 + +#### 원인 분석 + +1. **데이터 구조 혼란** + ``` + Google Email: goeun2dc@gmail.com + User ID (UUID): aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa + Username: happybell80 (저장할 곳 없음) + ``` + +2. **JWT 토큰 문제** + - 토큰에 email, username 정보 누락 + - `{"sub": "unknown"}`만 포함 + +3. **DB 스키마 문제** + - users 테이블에 username 필드 없음 + - 이메일과 사용자 ID 매핑 불가능 + +#### 해결 과정 + +##### 1단계: DB 스키마 변경 + +```sql +-- users 테이블에 username 필드 추가 +ALTER TABLE users ADD COLUMN username VARCHAR(50) UNIQUE; +``` + +**파일 수정:** +- `app/models/user.py`: username 필드 추가 +- `migrations/add_user_workspace_tables.sql`: 스키마 업데이트 + +##### 2단계: Auth-server Username 처리 + +```python +# app/providers/gmail.py +# 이메일 → username 매핑 +email_to_username = { + 'goeun2dc@gmail.com': 'happybell80', + 'eagle0914@gmail.com': 'eagle0914', +} +username = email_to_username.get(user_email, user_email.split('@')[0]) + +# JWT 토큰 생성 +jwt_token = create_access_token(data={ + "sub": username, # username을 subject로 사용 + "email": user_email, + "name": user_name, + "username": username +}) +``` + +##### 3단계: 프론트엔드 표시 개선 + +```javascript +// auth-context.tsx +const username = payload.username || userId; +setUser({ + id: username, // username을 ID로 사용 + email: email, + name: name +}); + +// user-menu.tsx +const displayName = user?.name || user?.id || user?.email?.split('@')[0] || 'User'; +``` + +#### 결과 +- 로그인 시 "happybell80" 정상 표시 +- 게임 API 호출 시 올바른 user_id 전달 +- 로빙과 사용자 정확한 매핑 + +--- + +## 오후 6시 00분 + +### 프론트엔드 리팩토링 및 빌드 오류 해결 + +#### 문제 상황 +1. 중복된 로그인 UI 코드 +2. 프로필 클릭 시 로그아웃 실행 +3. wouter의 useNavigate 없음 오류 +4. 로그인 후 페이지 리다이렉트 문제 + +#### 해결 과정 + +##### UserMenu 컴포넌트 통합 + +**생성: `src/components/user-menu.tsx`** +- 로그인/프로필 UI 통합 +- DropdownMenu로 로그아웃 분리 +- Header와 GameLayout에서 재사용 + +```typescript +export function UserMenu({ variant = 'default', showName = true }) { + // 로그인 버튼 또는 프로필 드롭다운 + if (!isAuthenticated) { + return ; + } + + return ( + + + {/* 프로필 이미지/아이콘 */} + + + 로그아웃 + + + ); +} +``` + +##### wouter 라우팅 수정 + +```typescript +// 변경 전 +import { useNavigate } from "wouter"; // 에러! +const [, navigate] = useNavigate(); + +// 변경 후 +import { useLocation } from "wouter"; +const [, setLocation] = useLocation(); +setLocation('/game'); // 페이지 이동 +``` + +##### 페이지 리로드 제거 + +```javascript +// 변경 전 +window.location.reload(); // 현재 페이지 잃음 + +// 변경 후 +window.history.replaceState(null, '', window.location.pathname); +``` + +#### 결과 +- 코드 50% 감소 +- 빌드 오류 해결 +- UX 개선 (프로필 드롭다운, 페이지 유지) + +--- + +## 오후 6시 30분 + +### 로빙 엔드포인트 불일치 문제 + +#### 문제 상황 +``` +Gateway → /api/chat 요청 +rb10508_micro → /api/message만 지원 +결과: 404 Not Found +``` + +#### 해결 과정 + +##### rb10508_micro 엔드포인트 추가 + +```python +# app/api/endpoints.py +@router.post("/chat") +async def chat_endpoint(request: MessageRequest): + """Gateway/nginx 호환 chat 엔드포인트 - /message의 alias""" + return await message_endpoint(request) +``` + +##### 포트 충돌 해결 +- rb10508_test 컨테이너 제거 +- rb10508_micro만 10508 포트 사용 + +#### 결과 +- Gateway와 로빙 통신 정상화 +- 404 에러 해결 + +--- + +## 교훈 및 베스트 프랙티스 + +### 1. **사용자 식별 설계** +- Username은 시스템 전체에서 일관되게 사용 +- UUID는 내부용, Username은 표시용 +- 이메일은 로그인용으로만 사용 + +### 2. **JWT 토큰 설계** +```json +{ + "sub": "happybell80", // 주 식별자 + "email": "goeun2dc@gmail.com", + "name": "김종태", + "username": "happybell80" // 명시적 username +} +``` + +### 3. **컴포넌트 재사용** +- 중복 UI는 즉시 컴포넌트화 +- Props로 변형 가능하게 설계 +- 한 곳에서 관리 + +### 4. **라우터 호환성** +- wouter는 경량 라우터 (useLocation만 제공) +- react-router-dom과 API 다름 +- 라이브러리 특성 먼저 확인 + +### 5. **포트 관리** +- 컨테이너별 고유 포트 할당 +- network_mode: host 사용 시 주의 +- 재배포 시 포트 해제 대기 필요 + +### 6. **점진적 마이그레이션** +- DB 스키마 변경은 신중하게 +- 기존 데이터 호환성 고려 +- 하드코딩 → DB 조회로 단계적 전환 + +--- + +## 최종 시스템 구성 + +### 사용자 플로우 +1. Google OAuth 로그인 (goeun2dc@gmail.com) +2. Username 매핑 (happybell80) +3. JWT 토큰 발급 (username 포함) +4. 프론트엔드 표시 (김종태 or happybell80) +5. 로빙 API 호출 (user_id: happybell80) + +### 데이터 매핑 +``` +Email → Username → Display Name +goeun2dc@gmail.com → happybell80 → 김종태 +eagle0914@gmail.com → eagle0914 → Eagle +``` + +### 핵심 파일 +- `auth-server/app/models/user.py` - username 필드 +- `auth-server/app/providers/gmail.py` - 매핑 로직 +- `frontend-customer/src/components/user-menu.tsx` - 통합 UI +- `frontend-customer/src/contexts/auth-context.tsx` - 토큰 처리 \ No newline at end of file