docs: Username 시스템 구축 트러블슈팅 문서
- 사용자 식별 문제 해결 (User → happybell80) - 프론트엔드 리팩토링 및 빌드 오류 - 로빙 엔드포인트 불일치 해결 - JWT 토큰 설계 및 username 매핑 전략
This commit is contained in:
parent
1fd3532a59
commit
99acb38162
248
troubleshooting/250809_happybell80_username시스템구축.md
Normal file
248
troubleshooting/250809_happybell80_username시스템구축.md
Normal file
@ -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 <Button onClick={() => setShowLoginDialog(true)}>로그인</Button>;
|
||||
}
|
||||
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger>
|
||||
{/* 프로필 이미지/아이콘 */}
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuItem onClick={logout}>로그아웃</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
##### 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` - 토큰 처리
|
||||
Loading…
x
Reference in New Issue
Block a user