DOCS/plans/completed/250819_rb8001_gmail_integration_completed.md

10 KiB

rb8001과 skill-email Gmail 통합 완료 보고서

작업일: 2025-08-19

작업자: 희재

상태: 완료


1. 작업 개요

목적

rb8001이 Gmail 기능을 사용할 수 있도록 skill-email 서비스와 통합

배경

  • skill-email은 DB 기반 토큰 관리로 전환 완료
  • rb8001이 사용자의 Gmail 요청을 감지하고 처리할 수 있도록 통합 필요
  • Gmail 아이템 장착 상태 확인 및 권한 관리 필요

2. 구현 내용

2.1 환경변수 설정

파일: /home/heejae/rb8001/.env

# Skill Services
SKILL_EMAIL_URL=http://localhost:8501
MONITOR_SERVICE_URL=http://localhost:9024

# PostgreSQL for Gmail tokens (SSH tunnel)
POSTGRES_CONNECTION_STRING=postgresql://robeings:robeings@localhost:5433/main_db

2.2 Gmail 통합 모듈 구현

파일: /home/heejae/rb8001/app/skills/email_integration.py

주요 클래스: EmailIntegration

Gmail 스킬 통합을 담당하는 핵심 모듈

핵심 메서드

  1. check_gmail_equipped(user_id)

    async def check_gmail_equipped(self, user_id: str) -> bool:
        # PostgreSQL에서 직접 장착 상태 확인
        # 5분 캐싱으로 성능 최적화
        cur.execute("""
            SELECT COUNT(*) FROM gmail_tokens 
            WHERE user_id = %s AND is_equipped = true
        """, (user_id,))
    
    • gmail_tokens 테이블의 is_equipped 확인
    • 캐시 TTL: 300초 (5분)
    • DB 연결 실패 시 False 반환
  2. parse_email_intent(message)

    def parse_email_intent(self, message: str) -> Optional[Dict[str, Any]]:
        # 이메일 관련 키워드 감지
        # 발송/조회/답장 의도 분류
        # 수신자, 제목, 내용 추출
    
    • 키워드: "이메일", "메일", "보내", "전송", "확인", "조회", "답장"
    • 정규표현식으로 수신자 추출: ([가-힣]+님?)(?:한테|에게|께)
    • 이메일 주소 패턴: [a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}
  3. process_email_request(message, user_id, channel)

    async def process_email_request(
        self, 
        message: str, 
        user_id: str,
        channel: str = None
    ) -> Tuple[bool, str]:
        # 1. Gmail 장착 확인
        # 2. 이메일 의도 파싱
        # 3. skill-email 서비스 호출
        # 4. 응답 처리
    

    처리 플로우:

    • 미장착 시: "Gmail 패스포트를 먼저 장착해주세요! 🎫"
    • 발송 요청: POST /process 엔드포인트 호출
    • 조회 요청: GET /messages 엔드포인트 호출
    • 토큰 만료: 재인증 안내 메시지
  4. handle_reauth(user_id)

    async def handle_reauth(self, user_id: str) -> Tuple[bool, str]:
        # robeing-monitor 서비스에 재인증 요청
        # OAuth URL 생성 및 반환
    

2.3 라우터 통합

파일: /home/heejae/rb8001/app/router/router.py

변경 내용

# Import 추가
from app.skills.email_integration import email_integration

# route_message 메서드에 Gmail 처리 추가
async def route_message(self, message: str, user_id: str, channel: str, thread_ts: str = None):
    # 0. 슬래시 명령어 처리
    # ...
    
    # 0.5. Gmail 요청 확인 및 처리 (새로 추가)
    email_result = await email_integration.process_email_request(message, user_id, channel)
    if email_result[0] or email_result[1] is not None:
        return {
            "success": email_result[0],
            "message": email_result[1],
            "content": email_result[1],
            "service": "gmail",
            "execution_plan": {"intent": "email", "skills": ["email"]}
        }
    
    # 1. 기존 Brain 기반 라우팅
    # ...

처리 우선순위:

  1. 슬래시 명령어 (/memory, /stats 등)
  2. Gmail 요청 (이메일 발송/조회)
  3. 일반 Brain 기반 라우팅

3. 테스트 구현

3.1 통합 테스트 스크립트

파일: /home/heejae/rb8001/test_gmail_integration.py

테스트 케이스

  1. 장착 상태 확인

    • U091UNVE41M (전희재): is_equipped=True
    • U0925SXQFDK (종태): is_equipped=False
  2. 의도 파싱 테스트

    • "종태님한테 회의 일정 메일 보내줘" → action: send, to: 종태님
    • "최근 메일 확인해줘" → action: list, limit: 5
  3. 프로세스 테스트

    • 미장착 사용자 → 장착 안내 메시지
    • 장착된 사용자 → skill-email 호출

3.2 테스트 결과

=== rb8001 Gmail Integration Test ===

[Test: 장착 상태 확인]
User U091UNVE41M: Gmail equipped = True

[Test: 이메일 발송 의도 파싱]
Parsed intent: {'action': 'send', 'to': '종태님', 'subject': '회의 일정 안내', 'body': '...'}

[Test: 이메일 조회 의도 파싱]
Parsed intent: {'action': 'list', 'limit': 5}

[Test: 이메일 처리 (미장착)]
Success: False
Message: Gmail 패스포트를 먼저 장착해주세요! 🎫

[Test: 이메일 처리 (장착됨)]
Success: True
Message: 이메일을 보내기 위해 다음 정보가 필요합니다...

4. API 통신

4.1 skill-email 엔드포인트

  • POST /process: 대화형 이메일 처리
  • GET /messages: 이메일 목록 조회
  • GET /health: 서비스 상태 확인

4.2 요청/응답 형식

발송 요청

{
    "message": "종태님한테 회의 일정 메일 보내줘",
    "user_id": "U091UNVE41M",
    "channel": "C123456",
    "robeing_id": "rb8001"
}

응답

{
    "success": true,
    "content": "이메일 처리 메시지",
    "data": {
        "type": "need_more_info|send|error",
        "draft": {...},
        "missing_fields": ["to", "subject"]
    }
}

5. 보안 및 권한 관리

5.1 장착 확인

  • is_equipped=true인 토큰만 사용 가능
  • 사용자별 개별 확인 (Slack User ID 기반)

5.2 캐싱

  • 장착 상태 5분 캐싱
  • DB 부하 감소 및 응답 속도 개선

5.3 에러 처리

  • DB 연결 실패 → 기본값 False (안전한 실패)
  • 토큰 만료 → 재인증 안내
  • 네트워크 타임아웃 → 30초 제한

6. 디렉토리 구조

/home/heejae/rb8001/
├── .env                              # 환경변수 (수정됨)
├── app/
│   ├── skills/                      # 새로 생성
│   │   └── email_integration.py     # Gmail 통합 모듈
│   ├── router/
│   │   └── router.py                # 라우터 (수정됨)
│   └── ...
└── test_gmail_integration.py        # 테스트 스크립트

7. 데이터 플로우

사용자 메시지 (Slack)
    ↓
rb8001 (router.py)
    ↓
Gmail 의도 감지
    ↓
장착 상태 확인 (PostgreSQL)
    ↓
skill-email 호출 (HTTP)
    ↓
Gmail API 실행
    ↓
응답 반환
    ↓
Slack 메시지 전송

8. 주요 성과

  1. 통합 완료

    • rb8001이 Gmail 요청 감지 및 처리 가능
    • skill-email 서비스와 완전 연동
  2. 권한 관리

    • Gmail 아이템 장착 상태 확인
    • 미장착 시 친절한 안내 메시지
  3. 성능 최적화

    • 5분 캐싱으로 DB 부하 감소
    • 30초 타임아웃으로 무한 대기 방지
  4. 유연한 구조

    • 의도 파싱과 서비스 호출 분리
    • 확장 가능한 아키텍처

9. 문제 해결

9.1 권한 오류

  • 문제: /home/heejae/rb8001/app/skills/ 디렉토리 생성 실패
  • 해결: sudo mkdir -pchmod 777 적용

9.2 의도 파싱

  • 문제: "test@example.com에게" 형식 파싱 실패
  • 해결: 이메일 정규표현식 패턴 추가

9.3 모듈 임포트

  • 문제: psycopg2 모듈 위치
  • 해결: 함수 내부에서 동적 임포트

10. 사용 시나리오

시나리오 1: 이메일 발송

사용자: @rb8001 종태님한테 회의 일정 메일 보내줘
rb8001: (장착 확인) → (의도 파싱) → (skill-email 호출)
skill-email: 이메일 주소가 필요합니다. 종태님의 이메일은?
사용자: goeun2dc@gmail.com
skill-email: (이메일 발송) → 성공 메시지

시나리오 2: 미장착 사용자

사용자: @rb8001 이메일 보내줘
rb8001: Gmail 패스포트를 먼저 장착해주세요! 🎫
        `/inventory` 명령어로 인벤토리를 확인할 수 있습니다.

시나리오 3: 메일 조회

사용자: @rb8001 최근 메일 확인해줘
rb8001: 📧 최근 이메일:
        1. *회의 일정 안내*
           발신: 김종태
           날짜: 2025-08-19
        ...

11. 향후 개선사항

즉시 필요

  • Docker 컨테이너 재빌드 및 배포
  • Slack 실제 환경 테스트
  • 에러 로깅 강화

추후 개선

  • 사용자 이름 → 이메일 주소 자동 매핑
  • 답장 기능 구현
  • 첨부파일 지원
  • 이메일 검색 기능
  • 대화 컨텍스트 유지 (연속 대화)

12. 의존성

Python 패키지

  • httpx: 비동기 HTTP 클라이언트
  • psycopg2-binary: PostgreSQL 연결
  • asyncio: 비동기 처리

외부 서비스

  • skill-email (포트 8501)
  • PostgreSQL (SSH 터널 5433 → 5432)
  • robeing-monitor (포트 9024, 선택적)

13. 참고 명령어

# 통합 테스트 실행
cd /home/heejae/rb8001 && python3 test_gmail_integration.py

# skill-email 상태 확인
curl http://localhost:8501/health

# 이메일 발송 테스트
curl -X POST http://localhost:8501/process \
  -H "Content-Type: application/json" \
  -d '{"message": "...", "user_id": "U091UNVE41M", ...}'

# PostgreSQL 장착 상태 확인
python3 -c "
import psycopg2
conn = psycopg2.connect('postgresql://robeings:robeings@localhost:5433/main_db')
cur = conn.cursor()
cur.execute('SELECT user_id, is_equipped FROM gmail_tokens')
for row in cur.fetchall():
    print(f'{row[0]}: equipped={row[1]}')
"

14. 검증 체크리스트

  • 환경변수 설정 완료
  • EmailIntegration 클래스 구현
  • 장착 상태 확인 동작
  • 의도 파싱 정확도
  • skill-email API 호출 성공
  • 라우터 통합 완료
  • 에러 처리 동작
  • 캐싱 메커니즘 동작
  • 테스트 스크립트 통과
  • 실제 Gmail API 호출 (토큰 유효성)
  • Slack 실환경 테스트

작업 완료: 2025-08-19 다음 단계: Docker 배포 및 실환경 테스트