From cec78add314d165ab26e0cf30a5ae2de3512a6f8 Mon Sep 17 00:00:00 2001 From: happybell80 Date: Tue, 19 Aug 2025 14:51:45 +0900 Subject: [PATCH] =?UTF-8?q?Add:=20=EC=9D=B4=EB=A9=94=EC=9D=BC=20=EC=8B=9C?= =?UTF-8?q?=EC=8A=A4=ED=85=9C=20=EC=A0=84=EC=B2=B4=20=EC=8B=9C=ED=80=80?= =?UTF-8?q?=EC=8A=A4=20=EB=8B=A4=EC=9D=B4=EC=96=B4=EA=B7=B8=EB=9E=A8=20?= =?UTF-8?q?=EB=AC=B8=EC=84=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Gmail OAuth 인증 플로우 (프론트엔드/Slack) - Gmail 아이템 장착/해제 시퀀스 - 이메일 발송 플로우 (프론트엔드/Slack) - 토큰 재인증 및 오류 처리 - 이메일 조회 및 AI 작성 시나리오 - 서비스 간 통신 포트 및 DB 스키마 문서화 --- 300_architecture/sequences/email_sequences.md | 544 ++++++++++++++++++ 1 file changed, 544 insertions(+) create mode 100644 300_architecture/sequences/email_sequences.md diff --git a/300_architecture/sequences/email_sequences.md b/300_architecture/sequences/email_sequences.md new file mode 100644 index 0000000..f3492e4 --- /dev/null +++ b/300_architecture/sequences/email_sequences.md @@ -0,0 +1,544 @@ +# 이메일 시스템 시퀀스 다이어그램 + +## 작성일: 2025-08-19 +## 작성자: Claude (51123 서버 관리자) +## 상태: 초안 + +--- + +## 목차 +1. [Gmail OAuth 인증](#1-gmail-oauth-인증) +2. [Gmail 아이템 장착](#2-gmail-아이템-장착) +3. [이메일 발송 - 프론트엔드](#3-이메일-발송---프론트엔드) +4. [이메일 발송 - Slack](#4-이메일-발송---slack) +5. [토큰 재인증](#5-토큰-재인증) +6. [아이템 미장착 오류 처리](#6-아이템-미장착-오류-처리) + +--- + +## 1. Gmail OAuth 인증 + +### 1.1 최초 Gmail 연결 (프론트엔드 시작) + +```mermaid +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,
scopes, state 포함 + + Auth-->>Gateway: OAuth URL 반환 + Gateway-->>Front: 리다이렉트 URL + Front->>Google: 브라우저 리다이렉트 + + User->>Google: Google 계정 로그인 + User->>Google: 권한 승인 + Note over Google: gmail.send
gmail.readonly
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,
tokens (암호화),
scopes, metadata + + Auth-->>Front: 인증 완료 리다이렉트 + Front->>Front: 성공 메시지 표시 +``` + +### 1.2 Slack에서 Gmail 연결 + +```mermaid +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 연결을 위해
아래 링크를 클릭하세요" + + User->>User: 링크 클릭 (브라우저 열림) + Note over User: 이후 플로우는
프론트엔드와 동일 +``` + +--- + +## 2. Gmail 아이템 장착 + +```mermaid +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 변환
토큰 본문은 제외 + + 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가 되면
사용 가능해요!" 표시 + else 레벨 >= 5 + Monitor->>DB: gmail_tokens 업데이트 + Note over DB: is_equipped = true
equipped_to = "rb10508_micro" + + Monitor->>DB: gmail_audit_logs 기록 + Note over DB: action: "equip"
user_id, robeing_id, timestamp + + Monitor->>RB: 장착 알림 (선택적) + Note over RB: 캐시 갱신 + + Monitor-->>Gateway: 장착 성공 + Gateway-->>Front: 성공 응답 + Front->>Front: UI 업데이트 + Note over Front: 장착 상태 표시
애니메이션 효과 + end +``` + +--- + +## 3. 이메일 발송 - 프론트엔드 + +```mermaid +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 토큰 포함
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 패스포트를
먼저 장착해주세요" + else Gmail 아이템 장착됨 + Monitor-->>RB: 장착 확인 (token_id) + + RB->>Skill: POST /send-email + Note over Skill: user_id, to,
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 또는
email_send_history + + Skill-->>RB: 발송 결과 + RB->>DB: robeing_stats 경험치 증가 + Note over DB: email_sent_count++
experience += 10 + + RB-->>Gateway: 성공 응답 + Gateway-->>Front: 발송 완료 + Front->>Front: 성공 메시지 표시 + end +``` + +--- + +## 4. 이메일 발송 - Slack + +```mermaid +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
수신자: 종태님
내용: 회의 일정 + + 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 패스포트를 먼저 장착해주세요.
설정에서 Gmail을 연결할 수 있어요." + else 아이템 장착됨 + DB-->>Monitor: is_equipped = true + Monitor-->>RB: EQUIPPED (token_id) + + RB->>RB: 이메일 내용 생성 + Note over RB: LLM으로 메일 본문 작성
"안녕하세요 종태님,
회의 일정 관련..." + + RB->>DB: 수신자 이메일 조회 + Note over DB: "종태님" → goeun2dc@gmail.com + DB-->>RB: 이메일 주소 + + RB->>Skill: POST /send-email + Note over Skill: to: goeun2dc@gmail.com
subject: "회의 일정 안내"
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에
이메일 발송 기록 + + RB-->>Slack: "종태님께 회의 일정 메일을
발송했습니다." + end +``` + +--- + +## 5. 토큰 재인증 + +```mermaid +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: 토큰 만료 감지
(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로
기존 이메일 전달 + + 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: 새 토큰으로 교체
updated_at 갱신 + + Auth->>DB: gmail_audit_logs 기록 + Note over DB: action: "reauth" + + Auth-->>Front: 재인증 완료 + Front->>Front: 아이템 상태 갱신 + Note over Front: "재인증 완료" 메시지 +``` + +--- + +## 6. 아이템 미장착 오류 처리 + +```mermaid +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 계정을 먼저 연결해주세요.
설정 → Gmail 연결" + else 토큰 있지만 미장착 + Monitor-->>RB: NOT_EQUIPPED + RB-->>Slack: "Gmail 패스포트가 인벤토리에 있어요.
먼저 장착해주세요." + else 레벨 부족 (레벨 < 5) + Monitor-->>RB: INSUFFICIENT_LEVEL + RB-->>Slack: "Gmail 기능은 레벨 5부터 사용 가능해요.
현재 레벨: 3" + else 권한 부족 (gmail.send 없음) + Monitor-->>RB: INSUFFICIENT_SCOPE + RB-->>Slack: "이메일 발송 권한이 필요해요.
Gmail 재인증이 필요합니다." + else 토큰 만료 + Monitor-->>RB: TOKEN_EXPIRED + RB-->>Slack: "Gmail 인증이 만료되었어요.
재인증이 필요합니다." + end +``` + +--- + +## 7. 이메일 조회 (받은 메일함) + +```mermaid +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
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: 발신자, 제목,
시간, 미리보기 + + Skill-->>RB: 메일 목록 + + RB->>RB: 포맷팅 + Note over RB: "📧 받은 메일 (10건)
1. 김종태 - 회의 일정
2. GitHub - PR 리뷰..." + + RB-->>Slack: 메일 목록 표시 + end +``` + +--- + +## 8. AI 메일 작성 + 발송 + +```mermaid +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: 프로젝트 정보
최근 대화 내용
사용자 스타일 + + RB->>LLM: 메일 생성 요청 + Note over LLM: 프롬프트:
"프로젝트 진행 상황을
전문적으로 작성" + + LLM-->>RB: 생성된 메일 + Note over RB: 제목: "8월 프로젝트 진행 현황"
본문: 상세 내용 + + 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 사용량 추적 + - [ ] 토큰 만료 예측 + - [ ] 발송 성공률 대시보드 + +--- + +**문서 끝** \ No newline at end of file