DOCS/300_architecture/sequences/email_sequences.md
happybell80 cec78add31 Add: 이메일 시스템 전체 시퀀스 다이어그램 문서
- Gmail OAuth 인증 플로우 (프론트엔드/Slack)
- Gmail 아이템 장착/해제 시퀀스
- 이메일 발송 플로우 (프론트엔드/Slack)
- 토큰 재인증 및 오류 처리
- 이메일 조회 및 AI 작성 시나리오
- 서비스 간 통신 포트 및 DB 스키마 문서화
2025-08-19 14:51:45 +09:00

16 KiB

이메일 시스템 시퀀스 다이어그램

작성일: 2025-08-19

작성자: Claude (51123 서버 관리자)

상태: 초안


목차

  1. Gmail OAuth 인증
  2. Gmail 아이템 장착
  3. 이메일 발송 - 프론트엔드
  4. 이메일 발송 - Slack
  5. 토큰 재인증
  6. 아이템 미장착 오류 처리

1. Gmail OAuth 인증

1.1 최초 Gmail 연결 (프론트엔드 시작)

sequenceDiagram
    participant User as 사용자
    participant Front as 프론트엔드
    participant Gateway as Gateway(8100)
    participant Auth as auth-server(9000)
    participant Google as Google OAuth
    participant DB as PostgreSQL

    User->>Front: Gmail 연결 버튼 클릭
    Front->>Gateway: POST /api/auth/gmail/connect
    Gateway->>Auth: 인증 요청 전달
    
    Auth->>Auth: state 토큰 생성
    Auth->>DB: state 임시 저장
    Auth->>Auth: OAuth URL 생성
    Note over Auth: client_id, redirect_uri,<br/>scopes, state 포함
    
    Auth-->>Gateway: OAuth URL 반환
    Gateway-->>Front: 리다이렉트 URL
    Front->>Google: 브라우저 리다이렉트
    
    User->>Google: Google 계정 로그인
    User->>Google: 권한 승인
    Note over Google: gmail.send<br/>gmail.readonly<br/>gmail.modify
    
    Google->>Auth: 인증 코드 콜백
    Note over Auth: /api/auth/gmail/callback
    
    Auth->>DB: state 검증
    Auth->>Google: 토큰 교환 요청
    Google-->>Auth: access_token, refresh_token
    
    Auth->>DB: gmail_tokens 테이블 저장
    Note over DB: user_id, email,<br/>tokens (암호화),<br/>scopes, metadata
    
    Auth-->>Front: 인증 완료 리다이렉트
    Front->>Front: 성공 메시지 표시

1.2 Slack에서 Gmail 연결

sequenceDiagram
    participant User as 사용자
    participant Slack as Slack Client
    participant RB as rb10508_micro
    participant Gateway as Gateway(8100)
    participant Auth as auth-server(9000)
    participant DB as PostgreSQL

    User->>Slack: "Gmail 연결해줘"
    Slack->>RB: 메시지 전달
    
    RB->>RB: 의도 분류 (Gmail 연결)
    RB->>Gateway: POST /api/auth/gmail/connect
    Gateway->>Auth: Slack user_id 포함 요청
    
    Auth->>DB: slack_user_mapping 조회
    Note over Auth: Slack ID → User ID 변환
    
    Auth->>Auth: OAuth URL 생성 (state 포함)
    Auth-->>Gateway: OAuth URL
    Gateway-->>RB: URL 반환
    
    RB-->>Slack: 인증 링크 메시지
    Note over Slack: "Gmail 연결을 위해<br/>아래 링크를 클릭하세요"
    
    User->>User: 링크 클릭 (브라우저 열림)
    Note over User: 이후 플로우는<br/>프론트엔드와 동일

2. Gmail 아이템 장착

sequenceDiagram
    participant User as 사용자
    participant Front as 프론트엔드
    participant Gateway as Gateway(8100)
    participant Auth as auth-server(9000)
    participant Monitor as robeing-monitor(9024)
    participant RB as rb10508_micro
    participant DB as PostgreSQL

    User->>Front: 인벤토리 페이지 접속
    Front->>Gateway: GET /api/items/gmail
    Gateway->>Auth: JWT 토큰 검증
    Auth-->>Gateway: user_id 확인
    
    Gateway->>Monitor: 아이템 목록 요청
    Monitor->>DB: gmail_tokens 조회
    Note over DB: user_id로 필터링
    
    Monitor->>DB: robeing_stats 조회
    Note over DB: 레벨 정보 확인
    
    DB-->>Monitor: 토큰 목록, 레벨 정보
    Monitor->>Monitor: capabilities 계산
    Note over Monitor: scopes → capabilities 변환<br/>토큰 본문은 제외
    
    Monitor-->>Gateway: 아이템 목록
    Gateway-->>Front: 응답
    Front->>Front: 아이템 카드 표시
    
    User->>Front: Gmail 패스포트 장착 클릭
    Front->>Gateway: POST /api/items/gmail/{userId}/equip
    Note over Gateway: Body: {robeing_id: "rb10508_micro"}
    
    Gateway->>Auth: JWT 검증
    Auth-->>Gateway: 인증 확인
    
    Gateway->>Monitor: 장착 요청
    Monitor->>DB: robeing_stats 레벨 확인
    
    alt 레벨 < 5
        Monitor-->>Gateway: INSUFFICIENT_LEVEL
        Gateway-->>Front: 레벨 부족 에러
        Front->>Front: "레벨 5가 되면<br/>사용 가능해요!" 표시
    else 레벨 >= 5
        Monitor->>DB: gmail_tokens 업데이트
        Note over DB: is_equipped = true<br/>equipped_to = "rb10508_micro"
        
        Monitor->>DB: gmail_audit_logs 기록
        Note over DB: action: "equip"<br/>user_id, robeing_id, timestamp
        
        Monitor->>RB: 장착 알림 (선택적)
        Note over RB: 캐시 갱신
        
        Monitor-->>Gateway: 장착 성공
        Gateway-->>Front: 성공 응답
        Front->>Front: UI 업데이트
        Note over Front: 장착 상태 표시<br/>애니메이션 효과
    end

3. 이메일 발송 - 프론트엔드

sequenceDiagram
    participant User as 사용자
    participant Front as 프론트엔드
    participant Gateway as Gateway(8100)
    participant RB as rb10508_micro
    participant Monitor as robeing-monitor(9024)
    participant Skill as skill-email(8501)
    participant DB as PostgreSQL
    participant Gmail as Gmail API

    User->>Front: 이메일 작성 폼 열기
    User->>Front: 수신자, 제목, 본문 입력
    User->>Front: 발송 버튼 클릭
    
    Front->>Gateway: POST /api/robeing/email/send
    Note over Gateway: JWT 토큰 포함<br/>to, subject, body
    
    Gateway->>RB: 이메일 발송 요청
    
    RB->>Monitor: GET /api/items/gmail/status
    Note over Monitor: 장착 상태 확인
    Monitor->>DB: gmail_tokens 조회
    DB-->>Monitor: 장착 정보
    
    alt Gmail 아이템 미장착
        Monitor-->>RB: NOT_EQUIPPED
        RB-->>Gateway: 아이템 미장착 에러
        Gateway-->>Front: "Gmail 패스포트를<br/>먼저 장착해주세요"
    else Gmail 아이템 장착됨
        Monitor-->>RB: 장착 확인 (token_id)
        
        RB->>Skill: POST /send-email
        Note over Skill: user_id, to,<br/>subject, body
        
        Skill->>DB: gmail_tokens 조회
        Note over DB: user_id와 is_equipped 확인
        DB-->>Skill: access_token (복호화)
        
        Skill->>Gmail: Gmail API 호출
        Note over Gmail: POST /gmail/v1/users/me/messages/send
        
        alt 토큰 만료
            Gmail-->>Skill: 401 Unauthorized
            Skill->>DB: refresh_token으로 갱신
            Skill->>Gmail: 재시도
        end
        
        Gmail-->>Skill: 발송 성공 (message_id)
        
        Skill->>DB: 발송 로그 저장
        Note over DB: conversation_logs 또는<br/>email_send_history
        
        Skill-->>RB: 발송 결과
        RB->>DB: robeing_stats 경험치 증가
        Note over DB: email_sent_count++<br/>experience += 10
        
        RB-->>Gateway: 성공 응답
        Gateway-->>Front: 발송 완료
        Front->>Front: 성공 메시지 표시
    end

4. 이메일 발송 - Slack

sequenceDiagram
    participant User as 사용자
    participant Slack as Slack Client
    participant RB as rb10508_micro
    participant Monitor as robeing-monitor(9024)
    participant Skill as skill-email(8501)
    participant DB as PostgreSQL
    participant Gmail as Gmail API

    User->>Slack: "종태님한테 회의 일정 메일 보내줘"
    Slack->>RB: 메시지 전달 (user_id: U0925SXQFDK)
    
    RB->>RB: 의도 분류
    Note over RB: INTENT: EMAIL_SEND<br/>수신자: 종태님<br/>내용: 회의 일정
    
    RB->>DB: slack_user_mapping 조회
    Note over DB: U0925SXQFDK → user_id
    DB-->>RB: user_id, name: "김종태"
    
    RB->>Monitor: Gmail 아이템 상태 확인
    Monitor->>DB: gmail_tokens 조회
    
    alt 아이템 미장착
        DB-->>Monitor: is_equipped = false
        Monitor-->>RB: NOT_EQUIPPED
        RB-->>Slack: "Gmail 패스포트를 먼저 장착해주세요.<br/>설정에서 Gmail을 연결할 수 있어요."
    else 아이템 장착됨
        DB-->>Monitor: is_equipped = true
        Monitor-->>RB: EQUIPPED (token_id)
        
        RB->>RB: 이메일 내용 생성
        Note over RB: LLM으로 메일 본문 작성<br/>"안녕하세요 종태님,<br/>회의 일정 관련..."
        
        RB->>DB: 수신자 이메일 조회
        Note over DB: "종태님" → goeun2dc@gmail.com
        DB-->>RB: 이메일 주소
        
        RB->>Skill: POST /send-email
        Note over Skill: to: goeun2dc@gmail.com<br/>subject: "회의 일정 안내"<br/>body: LLM 생성 내용
        
        Skill->>DB: gmail_tokens 조회
        DB-->>Skill: access_token
        
        Skill->>Gmail: 이메일 발송
        Gmail-->>Skill: 성공 (message_id)
        
        Skill-->>RB: 발송 완료
        
        RB->>DB: 대화 로그 저장
        Note over DB: conversation_logs에<br/>이메일 발송 기록
        
        RB-->>Slack: "종태님께 회의 일정 메일을<br/>발송했습니다."
    end

5. 토큰 재인증

sequenceDiagram
    participant User as 사용자
    participant Front as 프론트엔드
    participant Monitor as robeing-monitor(9024)
    participant Auth as auth-server(9000)
    participant Google as Google OAuth
    participant DB as PostgreSQL

    Note over Front: 토큰 만료 감지<br/>(API 호출 시 401)
    
    Front->>Front: 재인증 필요 알림 표시
    User->>Front: 재인증 버튼 클릭
    
    Front->>Monitor: POST /api/items/gmail/{userId}/reauth
    Monitor->>Auth: 재인증 요청
    
    Auth->>DB: 기존 토큰 정보 조회
    Note over DB: email, scopes 확인
    
    Auth->>Auth: OAuth URL 생성
    Note over Auth: login_hint로<br/>기존 이메일 전달
    
    Auth-->>Monitor: OAuth URL
    Monitor-->>Front: 리다이렉트 URL
    
    Front->>Google: 브라우저 리다이렉트
    User->>Google: 재인증 (간소화된 플로우)
    Google->>Auth: 인증 코드 콜백
    
    Auth->>Google: 토큰 교환
    Google-->>Auth: 새 access_token, refresh_token
    
    Auth->>DB: gmail_tokens 업데이트
    Note over DB: 새 토큰으로 교체<br/>updated_at 갱신
    
    Auth->>DB: gmail_audit_logs 기록
    Note over DB: action: "reauth"
    
    Auth-->>Front: 재인증 완료
    Front->>Front: 아이템 상태 갱신
    Note over Front: "재인증 완료" 메시지

6. 아이템 미장착 오류 처리

sequenceDiagram
    participant User as 사용자
    participant Slack as Slack/프론트
    participant RB as rb10508_micro
    participant Monitor as robeing-monitor(9024)
    participant DB as PostgreSQL

    User->>Slack: "이메일 보내줘"
    Slack->>RB: 이메일 요청
    
    RB->>Monitor: Gmail 아이템 확인
    Monitor->>DB: gmail_tokens 조회
    
    DB-->>Monitor: 결과
    
    alt 토큰 없음
        Monitor-->>RB: NO_TOKEN
        RB-->>Slack: "Gmail 계정을 먼저 연결해주세요.<br/>설정 → Gmail 연결"
    else 토큰 있지만 미장착
        Monitor-->>RB: NOT_EQUIPPED
        RB-->>Slack: "Gmail 패스포트가 인벤토리에 있어요.<br/>먼저 장착해주세요."
    else 레벨 부족 (레벨 < 5)
        Monitor-->>RB: INSUFFICIENT_LEVEL
        RB-->>Slack: "Gmail 기능은 레벨 5부터 사용 가능해요.<br/>현재 레벨: 3"
    else 권한 부족 (gmail.send 없음)
        Monitor-->>RB: INSUFFICIENT_SCOPE
        RB-->>Slack: "이메일 발송 권한이 필요해요.<br/>Gmail 재인증이 필요합니다."
    else 토큰 만료
        Monitor-->>RB: TOKEN_EXPIRED
        RB-->>Slack: "Gmail 인증이 만료되었어요.<br/>재인증이 필요합니다."
    end

7. 이메일 조회 (받은 메일함)

sequenceDiagram
    participant User as 사용자
    participant Slack as Slack Client
    participant RB as rb10508_micro
    participant Skill as skill-email(8501)
    participant DB as PostgreSQL
    participant Gmail as Gmail API

    User->>Slack: "최근 메일 확인해줘"
    Slack->>RB: 메시지 전달
    
    RB->>RB: 의도 분류 (EMAIL_LIST)
    RB->>DB: Gmail 아이템 확인
    
    alt 아이템 장착 확인됨
        RB->>Skill: GET /list-emails
        Note over Skill: maxResults: 10<br/>q: "is:unread"
        
        Skill->>DB: gmail_tokens 조회
        DB-->>Skill: access_token
        
        Skill->>Gmail: GET /gmail/v1/users/me/messages
        Gmail-->>Skill: 메일 목록 (message_ids)
        
        Skill->>Gmail: 각 메일 상세 조회 (병렬)
        Note over Gmail: GET /messages/{id}
        Gmail-->>Skill: 메일 상세 정보
        
        Skill->>Skill: 메일 요약 생성
        Note over Skill: 발신자, 제목,<br/>시간, 미리보기
        
        Skill-->>RB: 메일 목록
        
        RB->>RB: 포맷팅
        Note over RB: "📧 받은 메일 (10건)<br/>1. 김종태 - 회의 일정<br/>2. GitHub - PR 리뷰..."
        
        RB-->>Slack: 메일 목록 표시
    end

8. AI 메일 작성 + 발송

sequenceDiagram
    participant User as 사용자
    participant Front as 프론트엔드
    participant RB as rb10508_micro
    participant LLM as LLM Service
    participant Skill as skill-email(8501)
    participant Gmail as Gmail API

    User->>Front: "프로젝트 진행 상황 메일 작성"
    Front->>RB: AI 작성 요청
    
    RB->>RB: 컨텍스트 수집
    Note over RB: 프로젝트 정보<br/>최근 대화 내용<br/>사용자 스타일
    
    RB->>LLM: 메일 생성 요청
    Note over LLM: 프롬프트:<br/>"프로젝트 진행 상황을<br/>전문적으로 작성"
    
    LLM-->>RB: 생성된 메일
    Note over RB: 제목: "8월 프로젝트 진행 현황"<br/>본문: 상세 내용
    
    RB-->>Front: 초안 표시
    Front->>Front: 편집 가능한 폼 표시
    
    User->>Front: 수정 후 발송 클릭
    Front->>RB: 최종 발송 요청
    
    RB->>Skill: 이메일 발송
    Note over Skill: 수정된 내용으로 발송
    
    Skill->>Gmail: 발송
    Gmail-->>Skill: 성공
    
    Skill-->>RB: 완료
    RB-->>Front: "메일이 발송되었습니다"

주요 오류 코드 및 처리

오류 코드 설명 사용자 메시지
NO_TOKEN Gmail 토큰 없음 "Gmail 계정을 먼저 연결해주세요"
NOT_EQUIPPED 아이템 미장착 "Gmail 패스포트를 먼저 장착해주세요"
INSUFFICIENT_LEVEL 레벨 부족 "레벨 5가 되면 사용 가능해요"
TOKEN_EXPIRED 토큰 만료 "Gmail 재인증이 필요합니다"
INSUFFICIENT_SCOPE 권한 부족 "추가 권한이 필요합니다"
NETWORK_ERROR 네트워크 오류 "일시적인 오류입니다. 잠시 후 다시 시도해주세요"

서비스 간 통신 포트

서비스 포트 역할
Gateway 8100 API 라우팅, JWT 검증
auth-server 9000 OAuth 처리, 토큰 관리
robeing-monitor 9024 아이템 상태 관리
rb10508_micro 10508 메인 로빙 서비스
skill-email 8501 Gmail API 호출
PostgreSQL 5432 데이터 저장소

데이터베이스 테이블

gmail_tokens

  • id: UUID
  • user_id: UUID (users 테이블 참조)
  • robeing_id: VARCHAR (통일된 컬럼명)
  • email: VARCHAR
  • access_token: TEXT (암호화)
  • refresh_token: TEXT (암호화)
  • scopes: TEXT[]
  • is_equipped: BOOLEAN
  • equipped_to: VARCHAR
  • metadata: JSONB
  • created_at: TIMESTAMP
  • updated_at: TIMESTAMP

gmail_audit_logs

  • id: SERIAL
  • user_id: VARCHAR
  • robeing_id: VARCHAR
  • action: VARCHAR (equip, unequip, reauth, revoke)
  • success: BOOLEAN
  • details: JSONB
  • created_at: TIMESTAMP

robeing_stats

  • id: UUID
  • user_id: UUID (users 테이블 참조)
  • robeing_id: VARCHAR
  • level: INTEGER
  • experience: INTEGER
  • email_sent_count: INTEGER
  • created_at: TIMESTAMP
  • updated_at: TIMESTAMP

다음 단계

  1. 구현 우선순위

    • skill-email DB 연결 (FileProvider → DBProvider)
    • rb10508_micro Gmail 의도 분류 추가
    • 아이템 장착 확인 미들웨어
    • 에러 처리 표준화
  2. 테스트 시나리오

    • E2E: OAuth → 장착 → 발송
    • 오류 케이스: 미장착, 레벨 부족, 토큰 만료
    • 부하 테스트: 동시 다발 요청
  3. 모니터링

    • Gmail API 사용량 추적
    • 토큰 만료 예측
    • 발송 성공률 대시보드

문서 끝