DOCS/troubleshooting/250820_happybell80_Gmail패스포트시스템완성.md
happybell80 dda46b1cf8 docs: Gmail 패스포트 시스템 완성 및 Frontend UX 개선 트러블슈팅
- Gmail 패스포트 전체 플로우 구현
- 아이템 장착 확인 미들웨어 추가
- Frontend 인벤토리 페이지 UX 분석
- 개선 방안 제시
2025-08-20 10:38:15 +09:00

9.9 KiB

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 환경변수 누락

해결 과정

# skill-email/docker-compose.yml 수정
environment:
  - TOKEN_PROVIDER=database  # 추가
  - POSTGRES_CONNECTION_STRING=${POSTGRES_CONNECTION_STRING}  # 추가

Gitea Actions 배포 문제

  • 51124 서버 배포를 위한 SSH 방식 필요
  • 초기 시도: 로컬 경로 사용 (실패)
  • 해결: SSH로 51124 서버 접속 후 git pull
# .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에 아이템 관리 함수 추가
# 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 수정
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/ - 패스포트 취소

주요 특징:

# 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
// 현재 (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')
  1. 새 창 열기 방식의 UX 단절
  • 새 탭에서 OAuth 진행
  • 완료 후 원래 탭으로 돌아와야 함
  • 수동 새로고침 필요
  1. 레벨 정보 하드코딩
const [currentLevel, setCurrentLevel] = useState(5); // 항상 5
  1. 피드백 부족
  • 장착/해제 성공 시 시각적 피드백 없음
  • 에러 발생 시 사용자 안내 미흡

오전 10시 30분

5. Frontend UX 개선 방안

1. OAuth 플로우 개선

// 현재 창에서 리다이렉트 (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 성공 감지 자동화

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. 시각적 피드백 강화

// 장착 버튼 클릭 시
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. 실제 레벨 연동

// 실제 사용자 레벨 가져오기
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

문서 끝