# Gmail 토큰 NULL 및 대화 저장 실패 문제 해결 가이드 ## 작성일: 2025-08-25 ## 작성자: 서버 관리자 ## 상태: 해결 진행중 ## 영향: - 매일 9시 브리핑 이메일 수집 실패 (사용자 3명) - PostgreSQL 대화 저장 실패 (State Service DB 설정 오류) --- ## 1. 문제 상황 ### 1.1 증상 - **발생 시간**: 매일 오전 9시 (KST) - **영향 사용자**: - happybell80 (goeun2dc@gmail.com) - 0914eagle (0914eagle@gmail.com) - cdctfm (cdctfm@gmail.com) - **현상**: 이메일 요약 없이 뉴스만 포함된 불완전한 브리핑 전송 ### 1.2 근본 원인 ```sql -- 현재 DB 상태: 모든 사용자 token_data가 NULL SELECT username, has_token, is_equipped FROM gmail_tokens; 결과: happybell80 | f (NULL) | t (장착됨) -- 모순 상태 0914eagle | f (NULL) | t (장착됨) -- 모순 상태 cdctfm | f (NULL) | t (장착됨) -- 모순 상태 ``` **문제**: is_equipped=true이지만 실제 token_data=NULL --- ## 2. 시스템 플로우 분석 ### 2.1 일일 브리핑 플로우 ```mermaid sequenceDiagram participant Cron as Gateway Cron
(매일 9시) participant RB as rb8001
(51124:8001) participant Email as skill-email
(51124:8501) participant DB as PostgreSQL
(main_db) participant Slack as Slack API Cron->>RB: POST /api/cron/daily-summary RB->>Email: GET /messages?user_id={slack_id} Email->>DB: SELECT token_data FROM gmail_tokens DB-->>Email: token_data: NULL ❌ Email-->>RB: 500 Internal Server Error RB->>Slack: 불완전한 브리핑 전송
(이메일 없이 뉴스만) ``` ### 2.2 Gmail OAuth 플로우 (재인증 필요) ```mermaid sequenceDiagram participant User as 사용자 participant Front as 프론트엔드 participant Auth as auth-server
(51123:9000) participant Google as Google OAuth participant DB as PostgreSQL User->>Front: Gmail 연결 클릭 Front->>Auth: GET /api/gmail/auth?user_id={uuid} Auth->>Auth: OAuth URL 생성 Auth-->>Front: Redirect to Google Front->>Google: 사용자 리다이렉트 User->>Google: 권한 승인 Google->>Auth: Callback with code Auth->>Google: Exchange code for tokens Google-->>Auth: access_token, refresh_token Auth->>DB: UPDATE gmail_tokens
SET token_data = {...} Auth-->>Front: 인증 완료 ``` --- ## 3. 해결 방안 ### 3.1 해결책 - 관리자 대신 인증 ```bash # 1. 테스트 계정으로 OAuth 인증 URL 생성 curl -X GET "http://localhost:9000/api/gmail/auth?user_id=1e16e9d5-59f3-54da-a661-8abeabff4230" # 2. 반환된 URL을 브라우저에서 열어 Google 로그인 # 3. 권한 승인 후 콜백 확인 # 4. 토큰 저장 확인 export PGPASSWORD=robeings psql -h localhost -U robeings -d main_db -c \ "SELECT user_id, token_data IS NOT NULL FROM gmail_tokens WHERE user_id = '1e16e9d5-59f3-54da-a661-8abeabff4230';" # 5. 브리핑 수동 테스트 curl -X POST http://192.168.219.52:8001/api/cron/daily-summary \ -H "Content-Type: application/json" \ -H "Authorization: Bearer cron-secret-2024" ``` ### 3.2 해결책 - skill-email 토큰 자동 갱신 #### auth-server의 기존 갱신 API 활용 ```python # skill-email 서비스에 추가 async def auto_refresh_token(user_id: str): """만료된 토큰 자동 갱신""" try: # 1. refresh_token으로 새 access_token 획득 response = await httpx.post( f"http://auth-server:9000/api/gmail/refresh/{user_id}" ) if response.status_code == 200: logger.info(f"Token refreshed for {user_id}") return True elif response.status_code == 401: # refresh_token도 만료 → 재인증 필요 await notify_reauth_needed(user_id) return False except Exception as e: logger.error(f"Token refresh failed: {e}") return False ``` --- ## 4. 실행 단계별 가이드 ### Step 1: 현재 상태 확인 (5분) ```bash # 1. 토큰 상태 확인 export PGPASSWORD=robeings psql -h localhost -U robeings -d main_db -c \ "SELECT u.username, gt.token_data IS NOT NULL as has_token, gt.is_equipped, gt.metadata->>'email' as email FROM users u LEFT JOIN gmail_tokens gt ON u.id = gt.user_id WHERE u.username IN ('happybell80', '0914eagle', 'cdctfm');" ``` ### Step 2: 테스트 계정 인증 (15분) ```bash # 1. OAuth URL 생성 (happybell80 계정) curl -s "http://localhost:9000/api/gmail/auth?user_id=1e16e9d5-59f3-54da-a661-8abeabff4230" | jq -r '.auth_url' # 2. 브라우저에서 URL 열고 Google 계정으로 로그인 # 3. 권한 승인 (이메일 읽기, 쓰기, 수정) # 4. 인증 성공 확인 psql -h localhost -U robeings -d main_db -c \ "SELECT token_data->'access_token' IS NOT NULL as success FROM gmail_tokens WHERE user_id = '1e16e9d5-59f3-54da-a661-8abeabff4230';" ``` ### Step 3: 브리핑 테스트 (10분) ```bash # 1. 수동 브리핑 실행 curl -X POST http://192.168.219.52:8001/api/cron/daily-summary \ -H "Content-Type: application/json" \ -H "Authorization: Bearer cron-secret-2024" # 2. 실시간 로그 모니터링 docker logs robeing-gateway -f 2>&1 | grep -E "daily|gmail|email" # 3. Slack DM 확인 # happybell80 사용자의 Slack DM에 브리핑이 도착했는지 확인 ``` ### Step 4: 다른 사용자 처리 (20분) ```bash # 0914eagle 계정 인증 curl -s "http://localhost:9000/api/gmail/auth?user_id=b6ea2ee0-a15a-5cf4-93a9-a9ca20d4c4a0" | jq -r '.auth_url' # cdctfm 계정 인증 curl -s "http://localhost:9000/api/gmail/auth?user_id=69ae4ea9-a15f-5110-9f5d-6568e380fcfb" | jq -r '.auth_url' ``` --- ## 5. 검증 체크리스트 - [ ] 모든 사용자의 token_data NOT NULL 확인 - [ ] 수동 브리핑 실행 시 이메일 포함 확인 - [ ] Slack DM으로 완전한 브리핑 수신 확인 --- ## 6. 관련 파일 - **auth-server**: `/home/admin/auth-server/app/api/gmail_refresh.py` - **skill-email**: `skill-email/main.py` (51124 서버) - **State Service**: `/home/heejae/robeing-state-service/` (51124 서버) --- ## 7. 대화 저장 문제 (추가 발견) ### 7.1 문제 상황 - **증상**: Slack DM 대화가 PostgreSQL에 저장 안됨 - **ChromaDB**: ✅ 정상 저장 - **PostgreSQL**: ❌ 저장 실패 (conversation_logs 테이블 0 rows) ### 7.2 대화 저장 플로우 ```mermaid sequenceDiagram participant User as Slack User participant RB as rb8001
(51124:8001) participant State as State Service
(51124:8507) participant Chroma as ChromaDB
(51124:8000) participant PG as PostgreSQL
(51123:5432) User->>RB: "하이" RB->>RB: 메시지 처리 RB-->>User: "안녕하세요, 김종태님!" RB->>Chroma: store_memory() Chroma-->>RB: ✅ 저장 성공
ID: 2a776b26... RB->>State: POST /api/logs/rb8001/conversation State->>PG: INSERT INTO conversation_logs
❌ DB 연결 실패 Note over State,PG: 잘못된 DB 이름:
localhost:5433/auth_db
(main_db여야 함) State-->>RB: 500 Internal Server Error Note over RB: 에러 로깅만,
서비스 계속 동작 ``` ### 7.3 근본 원인 **State Service 환경변수 오류**: ```bash # 현재 (잘못된 DB 이름) DATABASE_URL=postgresql://robeings:robeings@localhost:5433/auth_db # 문제: auth_db가 존재하지 않음 (main_db 사용해야 함) # 올바른 설정 (SSH 터널 사용) DATABASE_URL=postgresql://robeings:robeings@localhost:5433/main_db # 5433은 SSH 터널 포트 (51124:5433 → 51123:5432) ``` ### 7.4 해결 방법 ```bash # 1. SSH 터널 확인 (51124 서버) ps aux | grep "5433:localhost:5432" # 없으면 생성: ssh -N -L 5433:localhost:5432 admin@192.168.219.45 & # 2. State Service 환경변수 수정 (51124 서버) cd /home/heejae/robeing-state-service vim .env # auth_db → main_db로 수정 docker compose down && docker compose up -d --build ``` --- ## 예상 소요 시간: 1시간 30분 - Gmail 토큰 문제: 1시간 - State Service DB 설정: 30분