docs: Gmail 패스포트 시스템 완성 및 Frontend UX 개선 트러블슈팅
- Gmail 패스포트 전체 플로우 구현 - 아이템 장착 확인 미들웨어 추가 - Frontend 인벤토리 페이지 UX 분석 - 개선 방안 제시
This commit is contained in:
parent
2d0c198e4b
commit
dda46b1cf8
373
troubleshooting/250820_happybell80_Gmail패스포트시스템완성.md
Normal file
373
troubleshooting/250820_happybell80_Gmail패스포트시스템완성.md
Normal file
@ -0,0 +1,373 @@
|
||||
# Gmail 패스포트 시스템 완성 및 Frontend UX 개선
|
||||
|
||||
## 작성일: 2025-08-20
|
||||
## 작성자: happybell80
|
||||
## 관련 서비스: auth-server, skill-email, rb10508_micro, frontend-customer
|
||||
|
||||
---
|
||||
|
||||
## 오전 9시 00분
|
||||
|
||||
### 작업 배경 및 목표
|
||||
|
||||
**배경**:
|
||||
- skill-email의 DBCredentialsProvider가 구현되었지만 환경변수 미설정으로 비활성화 상태
|
||||
- rb10508_micro에서 Gmail 아이템 장착 확인 없이 skill-email 호출하여 에러 발생
|
||||
- Gmail OAuth 인증을 통한 아이템 장착 플로우 필요
|
||||
|
||||
**목표**:
|
||||
1. Gmail 아이템 장착 시스템 완성
|
||||
2. 사용자 친화적인 OAuth 플로우 구현
|
||||
3. Frontend 아이템 관리 페이지 개선
|
||||
|
||||
---
|
||||
|
||||
## 오전 9시 10분
|
||||
|
||||
### 1. skill-email DBCredentialsProvider 활성화
|
||||
|
||||
#### 문제 상황
|
||||
- DBCredentialsProvider 클래스는 구현되어 있으나 미사용
|
||||
- docker-compose.yml에 TOKEN_PROVIDER 환경변수 누락
|
||||
|
||||
#### 해결 과정
|
||||
```yaml
|
||||
# skill-email/docker-compose.yml 수정
|
||||
environment:
|
||||
- TOKEN_PROVIDER=database # 추가
|
||||
- POSTGRES_CONNECTION_STRING=${POSTGRES_CONNECTION_STRING} # 추가
|
||||
```
|
||||
|
||||
#### Gitea Actions 배포 문제
|
||||
- 51124 서버 배포를 위한 SSH 방식 필요
|
||||
- 초기 시도: 로컬 경로 사용 (실패)
|
||||
- 해결: SSH로 51124 서버 접속 후 git pull
|
||||
|
||||
```yaml
|
||||
# .gitea/workflows/deploy.yml
|
||||
- name: Deploy to 51124 Server
|
||||
run: |
|
||||
ssh -p 51124 -i ~/.ssh/deploy_key admin@${{ secrets.SSH_HOST_51124 }} << 'EOF'
|
||||
cd /home/admin/ivada_project/skill-email
|
||||
git pull origin main --rebase
|
||||
docker compose up -d --build
|
||||
EOF
|
||||
```
|
||||
|
||||
#### 결과
|
||||
- ✅ DBCredentialsProvider 활성화
|
||||
- ✅ PostgreSQL 기반 토큰 관리로 전환
|
||||
|
||||
---
|
||||
|
||||
## 오전 9시 20분
|
||||
|
||||
### 2. rb10508_micro Gmail 아이템 확인 미들웨어 구현
|
||||
|
||||
#### 문제 상황
|
||||
- "최근 받은 메일 확인해줘" 요청 시 아이템 장착 확인 없이 skill-email 호출
|
||||
- 토큰 없으면 에러 발생
|
||||
|
||||
#### 해결 과정
|
||||
|
||||
##### growth.py에 아이템 관리 함수 추가
|
||||
```python
|
||||
# rb10508_micro/app/core/growth.py
|
||||
async def check_item_equipped(user_id: str, item_type: str) -> bool:
|
||||
"""특정 아이템 장착 여부 확인"""
|
||||
async with httpx.AsyncClient() as client:
|
||||
response = await client.get(
|
||||
f"http://localhost:8090/api/items/{item_type}",
|
||||
params={"user_id": user_id}
|
||||
)
|
||||
if response.status_code == 200:
|
||||
items = response.json()
|
||||
return any(item.get('is_equipped') for item in items)
|
||||
return False
|
||||
|
||||
async def get_item_capabilities(user_id: str, item_type: str) -> List[str]:
|
||||
"""아이템의 권한 목록 조회"""
|
||||
# send, read, modify 등 권한 반환
|
||||
```
|
||||
|
||||
##### brain.py 수정
|
||||
```python
|
||||
if intent == "email":
|
||||
# Gmail 아이템 장착 확인
|
||||
is_equipped = await check_item_equipped(think_input.user_id, "gmail")
|
||||
|
||||
if not is_equipped:
|
||||
response = f"{user_name}님, Gmail을 먼저 연결해주세요!"
|
||||
else:
|
||||
# 권한 확인 후 skill-email 호출
|
||||
capabilities = await get_item_capabilities(think_input.user_id, "gmail")
|
||||
# ...
|
||||
```
|
||||
|
||||
#### 테스트 결과
|
||||
- 요청: "최근 받은 이메일 확인해줘"
|
||||
- 응답: "사용자님, Gmail을 먼저 연결해주세요! 설정 > 아이템에서 Gmail을 장착하면 이메일 기능을 사용할 수 있습니다."
|
||||
- ✅ 정상 작동
|
||||
|
||||
---
|
||||
|
||||
## 오전 9시 30분
|
||||
|
||||
### 3. auth-server Gmail Passport 엔드포인트 구현
|
||||
|
||||
#### 구현 내용
|
||||
새 파일: `app/providers/gmail_passport.py`
|
||||
|
||||
**엔드포인트 구조**:
|
||||
- `GET /auth/gmail/passport/` - 패스포트 발급 (OAuth 시작)
|
||||
- `GET /auth/gmail/passport/callback` - OAuth 콜백
|
||||
- `GET /auth/gmail/passport/status` - 패스포트 상태 확인
|
||||
- `POST /auth/gmail/passport/activate` - 패스포트 활성화 (장착)
|
||||
- `POST /auth/gmail/passport/deactivate` - 패스포트 비활성화 (해제)
|
||||
- `DELETE /auth/gmail/passport/` - 패스포트 취소
|
||||
|
||||
**주요 특징**:
|
||||
```python
|
||||
# Gmail API 전체 권한 scope
|
||||
GMAIL_API_SCOPES = [
|
||||
"https://www.googleapis.com/auth/gmail.send",
|
||||
"https://www.googleapis.com/auth/gmail.readonly",
|
||||
"https://www.googleapis.com/auth/gmail.modify",
|
||||
"https://www.googleapis.com/auth/userinfo.email",
|
||||
"https://www.googleapis.com/auth/userinfo.profile"
|
||||
]
|
||||
|
||||
# PostgreSQL 직접 연동
|
||||
await conn.execute("""
|
||||
INSERT INTO gmail_tokens (...) VALUES (...)
|
||||
ON CONFLICT (user_id) DO UPDATE SET ...
|
||||
""")
|
||||
```
|
||||
|
||||
#### Gitea Actions 배포 이슈
|
||||
1. **import 에러**: `app.core.config` 모듈 없음
|
||||
- 해결: 환경변수 직접 사용
|
||||
2. **Redis 컨테이너 충돌**: 이미 실행 중
|
||||
- 해결: auth-server만 재시작하도록 수정
|
||||
3. **배포 속도**: 너무 느림
|
||||
- 해결: 헬스체크 단순화, rsync 최적화
|
||||
|
||||
---
|
||||
|
||||
## 오전 10시 00분
|
||||
|
||||
### 4. Frontend 아이템 관리 페이지 분석
|
||||
|
||||
#### 현재 구현 상태
|
||||
**위치**: `/src/pages/inventory.tsx`
|
||||
|
||||
**구조**:
|
||||
```
|
||||
inventory.tsx (메인 페이지)
|
||||
└── inventory-grid.tsx (아이템 그리드)
|
||||
└── gmail-passport-card.tsx (Gmail 카드 컴포넌트)
|
||||
```
|
||||
|
||||
**기능**:
|
||||
- ✅ 아이템 목록 표시
|
||||
- ✅ 장착/해제/재인증/철회 버튼
|
||||
- ✅ 레벨 제한 체크 (레벨 5 이상)
|
||||
- ✅ ItemContext로 상태 관리
|
||||
|
||||
#### UX 문제점 분석
|
||||
|
||||
1. **잘못된 OAuth URL**
|
||||
```tsx
|
||||
// 현재 (inventory.tsx line 105)
|
||||
window.open('https://auth.ro-being.com/oauth/gmail', '_blank')
|
||||
|
||||
// 수정 필요
|
||||
window.open('https://auth.ro-being.com/auth/gmail/passport/', '_blank')
|
||||
```
|
||||
|
||||
2. **새 창 열기 방식의 UX 단절**
|
||||
- 새 탭에서 OAuth 진행
|
||||
- 완료 후 원래 탭으로 돌아와야 함
|
||||
- 수동 새로고침 필요
|
||||
|
||||
3. **레벨 정보 하드코딩**
|
||||
```tsx
|
||||
const [currentLevel, setCurrentLevel] = useState(5); // 항상 5
|
||||
```
|
||||
|
||||
4. **피드백 부족**
|
||||
- 장착/해제 성공 시 시각적 피드백 없음
|
||||
- 에러 발생 시 사용자 안내 미흡
|
||||
|
||||
---
|
||||
|
||||
## 오전 10시 30분
|
||||
|
||||
### 5. Frontend UX 개선 방안
|
||||
|
||||
#### 1. OAuth 플로우 개선
|
||||
```tsx
|
||||
// 현재 창에서 리다이렉트 (UX 연속성)
|
||||
const connectGmail = () => {
|
||||
const userId = getUserId(); // 실제 사용자 ID
|
||||
const returnUrl = encodeURIComponent(window.location.href);
|
||||
|
||||
// 현재 창에서 이동
|
||||
window.location.href =
|
||||
`https://auth.ro-being.com/auth/gmail/passport/?user_id=${userId}&return_url=${returnUrl}`;
|
||||
};
|
||||
```
|
||||
|
||||
#### 2. OAuth 성공 감지 자동화
|
||||
```tsx
|
||||
useEffect(() => {
|
||||
const params = new URLSearchParams(location.search);
|
||||
|
||||
// auth-server가 ?gmail=success&email=user@gmail.com 으로 리다이렉트
|
||||
if (params.get('gmail') === 'success') {
|
||||
const email = params.get('email');
|
||||
|
||||
// 토스트 메시지
|
||||
toast.success(`Gmail 연결 성공! (${email})`);
|
||||
|
||||
// 아이템 목록 자동 새로고침
|
||||
fetchItems();
|
||||
|
||||
// URL 파라미터 제거
|
||||
window.history.replaceState({}, '', '/inventory');
|
||||
}
|
||||
}, [location]);
|
||||
```
|
||||
|
||||
#### 3. 시각적 피드백 강화
|
||||
```tsx
|
||||
// 장착 버튼 클릭 시
|
||||
const handleEquip = async (itemId: string) => {
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
const result = await equipItem(itemId, robeingId);
|
||||
|
||||
if (result?.success) {
|
||||
// 성공 애니메이션
|
||||
confetti();
|
||||
toast.success('Gmail 아이템 장착 완료!');
|
||||
|
||||
// 상태 업데이트
|
||||
await fetchItems();
|
||||
}
|
||||
} catch (error) {
|
||||
toast.error('장착에 실패했습니다. 다시 시도해주세요.');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
#### 4. 실제 레벨 연동
|
||||
```tsx
|
||||
// 실제 사용자 레벨 가져오기
|
||||
useEffect(() => {
|
||||
const fetchUserLevel = async () => {
|
||||
const response = await fetch('/api/user/stats');
|
||||
const data = await response.json();
|
||||
setCurrentLevel(data.level);
|
||||
};
|
||||
|
||||
fetchUserLevel();
|
||||
}, []);
|
||||
```
|
||||
|
||||
#### 5. 모바일 UX 개선
|
||||
- 카드 크기 반응형 조정
|
||||
- 터치 타겟 크기 44px 이상 확보
|
||||
- 스와이프 제스처 지원
|
||||
|
||||
---
|
||||
|
||||
## 최종 시스템 아키텍처
|
||||
|
||||
```
|
||||
사용자 요청 흐름:
|
||||
1. "이메일 확인해줘" → rb10508_micro
|
||||
2. Gmail 아이템 장착 확인 (robeing-monitor API)
|
||||
3. 미장착 시: "Gmail을 먼저 연결해주세요!" 안내
|
||||
4. 장착 시: skill-email 호출 → Gmail API 사용
|
||||
|
||||
아이템 장착 흐름:
|
||||
1. Frontend /inventory 페이지
|
||||
2. "Gmail 연결" 버튼 클릭
|
||||
3. auth-server/auth/gmail/passport/ OAuth 시작
|
||||
4. Google 인증 완료
|
||||
5. PostgreSQL gmail_tokens 저장 (is_equipped = true)
|
||||
6. Frontend로 리다이렉트 (?gmail=success)
|
||||
7. 자동 새로고침 및 성공 메시지
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 성과
|
||||
|
||||
### ✅ 완료된 작업
|
||||
1. **Gmail 패스포트 시스템 완성**
|
||||
- auth-server에 passport 엔드포인트 구현
|
||||
- OAuth → PostgreSQL 저장 → 자동 장착
|
||||
|
||||
2. **아이템 장착 확인 미들웨어**
|
||||
- rb10508_micro에 Gmail 체크 로직 추가
|
||||
- 미장착 시 친절한 안내 메시지
|
||||
|
||||
3. **DB 기반 토큰 관리 전환**
|
||||
- skill-email DBCredentialsProvider 활성화
|
||||
- 파일 기반에서 PostgreSQL로 마이그레이션
|
||||
|
||||
4. **Gitea Actions 최적화**
|
||||
- 51124 서버 SSH 배포 설정
|
||||
- 배포 속도 개선 (Redis 유지, 헬스체크 단순화)
|
||||
|
||||
### 📊 시스템 상태
|
||||
- auth-server: 정상 작동 (37시간+)
|
||||
- skill-email: DB 연동 완료
|
||||
- rb10508_micro: 아이템 확인 기능 추가
|
||||
- frontend-customer: 인벤토리 페이지 구현됨 (개선 필요)
|
||||
|
||||
---
|
||||
|
||||
## 교훈
|
||||
|
||||
### 1. 트러블슈팅 문서의 중요성
|
||||
- 기존 문서 참고로 Actions 설정 한번에 성공
|
||||
- SSH 방식, 경로 구조 등 검증된 패턴 재사용
|
||||
|
||||
### 2. 점진적 통합
|
||||
- 각 서비스 개별 테스트 후 통합
|
||||
- 로그를 통한 데이터 흐름 추적
|
||||
|
||||
### 3. UX 연속성
|
||||
- OAuth 플로우에서 새 창 열기는 UX 단절
|
||||
- 현재 창 리다이렉트가 더 자연스러움
|
||||
|
||||
### 4. 환경변수 확인
|
||||
- 코드 구현되어도 환경변수 없으면 무용지물
|
||||
- docker-compose.yml과 .env 동기화 필수
|
||||
|
||||
---
|
||||
|
||||
## 다음 단계
|
||||
|
||||
1. **Frontend UX 개선 구현**
|
||||
- OAuth URL 수정
|
||||
- 성공 감지 자동화
|
||||
- 토스트 메시지 추가
|
||||
|
||||
2. **실제 사용자 테스트**
|
||||
- E2E 시나리오 검증
|
||||
- 에러 케이스 처리
|
||||
|
||||
3. **다른 아이템 확장**
|
||||
- Slack passport
|
||||
- Calendar passport
|
||||
|
||||
---
|
||||
|
||||
**문서 끝**
|
||||
Loading…
x
Reference in New Issue
Block a user