# Gmail 토큰 만료 및 대화 저장 실패 문제 해결 가이드
## 작성일: 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 상태: 모든 사용자 토큰 만료
SELECT username, access_token IS NOT NULL as has_token,
expires_at < extract(epoch from now()) as is_expired
FROM gmail_token;
결과:
happybell80 | t (있음) | t (만료됨)
0914eagle | t (있음) | t (만료됨)
cdctfm | t (있음) | t (만료됨)
```
**문제**: access_token은 있지만 만료되어 사용 불가
---
## 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_token
DB-->>Email: access_token: expired ❌
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_token
SET access_token, refresh_token
Auth-->>Front: 인증 완료
```
---
## 3. 해결 방안
### 3.1 해결책 - 토큰 갱신 또는 재인증
```bash
# 1. 토큰 갱신 (만료된 경우)
curl -X POST "http://localhost:9000/api/gmail/refresh/1e16e9d5-59f3-54da-a661-8abeabff4230"
# 2. 갱신 실패 시 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, access_token IS NOT NULL FROM gmail_token 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 토큰 자동 갱신 (✅ 해결완료 2025-08-27)
**skill-email이 Google 라이브러리를 직접 사용하여 자동 갱신 구현 완료**
- auth-server API 연동 없이 독립적 처리
- `creds.refresh(Request())`로 자동 갱신
- 갱신된 토큰 DB 자동 저장
---
## 4. 실행 단계별 가이드
### Step 1: 현재 상태 확인 (5분)
```bash
# 1. 토큰 상태 확인
export PGPASSWORD=robeings
psql -h localhost -U robeings -d main_db -c \
"SELECT u.username, gt.access_token IS NOT NULL as has_token,
gt.expires_at < extract(epoch from now()) as is_expired,
gt.metadata->>'email' as email
FROM user u
LEFT JOIN gmail_token gt ON u.id = gt.user_id
WHERE u.username IN ('happybell80', '0914eagle', 'cdctfm');"
```
### Step 2: 토큰 갱신 또는 재인증 (15분)
```bash
# 1. 토큰 갱신 시도 (happybell80 계정)
curl -X POST "http://localhost:9000/api/gmail/refresh/1e16e9d5-59f3-54da-a661-8abeabff4230"
# 2. 갱신 실패 시 OAuth URL 생성
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 access_token IS NOT NULL as success
FROM gmail_token
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. 검증 체크리스트
- [ ] 모든 사용자의 access_token 유효성 확인
- [ ] 수동 브리핑 실행 시 이메일 포함 확인
- [ ] 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/`~~ (사용 안 함)
---
## 7. 대화 저장 문제 (추가 발견)
### 7.1 문제 상황
- **증상**: Slack DM 대화가 PostgreSQL에 저장 안됨
- **ChromaDB**: ✅ 정상 저장
- **PostgreSQL**: ❌ 저장 실패 (conversation_log 테이블 0 rows)
### 7.2 대화 저장 플로우 (현재: State Service 사용 안 함)
```mermaid
sequenceDiagram
participant User as Slack User
participant RB as rb8001
(51124:8001)
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->>PG: 직접 INSERT INTO conversation_log
PG-->>RB: ✅ 저장 성공
Note over RB: State Service 없이
직접 DB 연결
```
### 7.3 근본 원인 (현재: 해결됨)
**~~State Service 환경변수 오류~~** → **State Service 사용 중단**:
- State Service는 더 이상 사용하지 않음
- rb8001이 직접 PostgreSQL에 연결
### 7.4 현재 구조
```bash
# rb8001이 직접 DB 연결 (51124 서버)
DATABASE_URL=postgresql://robeings:robeings@192.168.0.100:5432/main_db
# State Service 없이 직접 연결
```
---
## 예상 소요 시간: 1시간 30분
- Gmail 토큰 갱신: 10분
- ~~State Service DB 설정~~: 필요 없음 (직접 DB 연결)