# Gmail 아이템 구현 계획 ## 작성일: 2025-08-19 ## 작성자: Claude (with 종태) ## 상태: 계획 수립 --- ## 1. 개요 ### 목적 Gmail 자격증명을 "API 아이템"으로 정의하고, robeing의 장착형 아이템 시스템에 통합 ### 핵심 원칙 - Gmail OAuth 토큰을 극비 데이터로 취급 - 아이템 장착/해제 메타포로 권한 관리 - RBAC+ABAC 하이브리드 접근 제어 - 레벨 5 이상에서 사용 가능 ### 관련 문서 - `/250817_email_skill_integration_status.md` - 현황 분석 - `/250818_gmail_token_database_setup.md` - DB 구성 완료 - `/ideas/250818_claude_robeing_레벨업_체감_시스템_설계.md` - 아이템 시스템 설계 --- ## 2. 아이템 정의 ### 기본 속성 ```typescript { type: 'accessory', slot: 'passport_gmail', name: 'Gmail Passport', level_requirement: 5 // rarity 제거 - 불필요 } ``` ### 데이터 모델 ```typescript type GmailCredentialItem = { id: string; // gmail_token.id userId: string; // gmail_token.user_id robeing_id?: string; // gmail_token.robeing_id (통일) type: 'accessory'; slot: 'passport_gmail'; name: string; // metadata.display_name || email email: string; // metadata.email scopes: string[]; // scopes 배열 status: 'ready' | 'reauth_required' | 'insufficient_scope'; capabilities: { send: boolean; // gmail.send 스코프 존재 여부 read: boolean; // gmail.readonly 스코프 존재 여부 modify: boolean; // gmail.modify 스코프 존재 여부 }; expiry?: string; createdAt: string; updatedAt: string; }; ``` --- ## 3. 아키텍처 ### 서비스 구조 ``` 프론트엔드 (React) ↓ robeing-gateway (인증/라우팅) ↓ rb8001:8001 (메인 robeing) ↓ ↓ skill-email:8501 robeing-monitor:9024 (이메일 발송) (아이템 상태 관리) ↓ ↓ PostgreSQL (gmail_token 테이블) ``` ### 서비스별 역할 #### auth-server - Gmail OAuth 플로우 처리 - gmail_token 테이블 관리 - 토큰 갱신 로직 #### robeing-monitor (9024) - 아이템 상태 관리 - 장착/해제 로직 - 레벨 요구사항 체크 - 아이템 인벤토리 조회 #### rb8001 - 아이템 사용 로직 - skill-email 호출 - 사용자 컨텍스트 관리 #### skill-email (8501) - Gmail API 실제 호출 - 이메일 작성/발송 - DB 기반 토큰 조회 --- ## 4. 시퀀스 다이어그램 ### 아이템 장착 플로우 ```mermaid sequenceDiagram participant User as 사용자 participant Front as 프론트엔드 participant Auth as auth-server(9000) participant Gateway as Gateway(8100) participant Monitor as robeing-monitor(9024) participant RB as rb8001 participant DB as PostgreSQL User->>Front: Gmail 아이템 장착 클릭 Front->>Gateway: POST /api/items/gmail/:userId/equip Gateway->>Auth: JWT 토큰 검증 Auth-->>Gateway: 사용자 정보 확인 alt 인증 실패 Gateway-->>Front: UNAUTHORIZED else 인증 성공 Gateway->>Monitor: 장착 요청 전달 Monitor->>DB: gmail_token 소유권 확인 Monitor->>DB: robeing_stats 조회 (레벨 체크) DB-->>Monitor: 레벨 정보 alt 레벨 < 5 Monitor-->>Front: INSUFFICIENT_LEVEL else 레벨 >= 5 Monitor->>DB: gmail_token 업데이트 Note over DB: is_equipped=true
equipped_to=robeing_id Monitor->>DB: gmail_audit_logs 기록 Monitor-->>RB: 장착 완료 알림 Monitor-->>Front: 장착 성공 end end ``` ### 이메일 발송 플로우 ```mermaid sequenceDiagram participant User as 사용자 participant Front as 프론트엔드 participant RB as rb8001 participant Monitor as robeing-monitor(9024) participant Skill as skill-email(8501) participant DB as PostgreSQL participant Gmail as Gmail API User->>Front: "이메일 보내줘" 요청 Front->>RB: 메시지 전달 RB->>Monitor: Gmail 아이템 장착 확인 Monitor->>DB: gmail_token 조회 DB-->>Monitor: 장착 상태 & 토큰 정보 alt 아이템 미장착 Monitor-->>RB: ITEM_NOT_EQUIPPED RB-->>Front: "Gmail 아이템을 먼저 장착해주세요" else 아이템 장착됨 Monitor-->>RB: 장착 확인 RB->>Skill: 이메일 발송 요청 Skill->>DB: 토큰 조회 DB-->>Skill: access_token Skill->>Gmail: API 호출 Gmail-->>Skill: 발송 결과 Skill-->>RB: 성공/실패 RB-->>Front: 결과 메시지 end ``` ### 재인증 플로우 ```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: 토큰 만료 상태 표시 User->>Front: 재인증 버튼 클릭 Front->>Monitor: POST /api/items/gmail/:userId/reauth Monitor->>Auth: OAuth URL 요청 Auth->>Auth: state 생성 Auth-->>Monitor: OAuth URL Monitor-->>Front: 리다이렉트 URL Front->>Google: OAuth 페이지로 이동 User->>Google: 로그인 & 권한 승인 Google->>Auth: 인증 코드 콜백 Auth->>Google: 토큰 교환 Google-->>Auth: access_token, refresh_token Auth->>DB: gmail_token 업데이트 Auth-->>Front: 인증 완료 Front->>Front: 아이템 상태 갱신 ``` --- ## 5. API 설계 ### robeing-monitor (9024) 엔드포인트 #### 아이템 목록 조회 ``` GET /api/items/gmail Response: { equipped: GmailCredentialItem | null, available: GmailCredentialItem[] } ``` #### 아이템 장착 ``` POST /api/items/gmail/:userId/equip Body: { robeing_id: string } Response: { success: boolean, message: string, audit_id: string } ``` #### 재인증 시작 ``` POST /api/items/gmail/:userId/reauth Response: { auth_url: string, state: string } ``` #### 아이템 철회 ``` DELETE /api/items/gmail/:userId Response: { success: boolean, audit_id: string } ``` ### 권한 체크 플로우 1. Gateway: JWT 토큰 검증 2. robeing-monitor: 레벨 5 이상 확인 3. robeing-monitor: 아이템 소유권 확인 4. rb8001: 최종 사용 권한 확인 --- ## 5. 보안 정책 ### 데이터 등급 - **극비**: access_token, refresh_token, client_secret - **기밀**: oauth_config, scopes - **일반**: email, display_name, status ### 접근 제어 - 토큰 본문은 절대 프론트엔드 노출 금지 - capabilities는 scopes에서 파생하여 표시 - 모든 민감 작업 감사 로그 기록 ### 감사 로그 ```sql CREATE TABLE gmail_audit_logs ( id SERIAL PRIMARY KEY, user_id VARCHAR(100), robeing_id VARCHAR(50), action VARCHAR(50), -- equip, reauth, revoke success BOOLEAN, details JSONB, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); ``` --- ## 6. 구현 단계 ### Phase 1: 백엔드 기초 - [x] 필요 테이블 생성 - robeing_stats 테이블 (레벨 관리) - gmail_audit_logs 테이블 (감사 로그) - gmail_token에 is_equipped, equipped_to 컬럼 추가 - [x] skill-email DB 연결 코드 작성 (희재) - FileCredentialsProvider → DBCredentialsProvider 전환 - PostgreSQL 연결 설정 추가 (localhost:5433 SSH 터널) - oauth_config 컬럼에서 client_id/secret 가져오기 구현 - [x] robeing-monitor 서비스 구축 - 기존 robeing-state-service 확장 - 포트 9024로 변경 - 아이템 관리 API 추가 ### Phase 2: 통합 연결 - [ ] rb8001 환경변수 설정 ```bash SKILL_EMAIL_URL=http://localhost:8501 STATE_SERVICE_URL=http://localhost:9024 ``` - [ ] rb8001 ↔ skill-email 연결 테스트 - [ ] rb8001 ↔ robeing-monitor 연결 테스트 ### Phase 3: 프론트엔드 - [ ] 인벤토리 UI 컴포넌트 개발 - 아이템 카드 리스트 - 장착 상태 표시 - 재인증 버튼 - [ ] robeing-api.ts 확장 - Gmail 아이템 API 호출 함수 - 에러 핸들링 ### Phase 4: 테스트 및 검증 - [ ] 장착/해제 플로우 테스트 - [ ] 재인증 플로우 테스트 - [ ] 권한 부족 시나리오 테스트 - [ ] 감사 로그 확인 --- ## 7. 환경변수 표준 ### 공통 PostgreSQL 설정 ```bash # 51123 서버에서 POSTGRES_HOST=localhost POSTGRES_PORT=5432 # 51124 서버에서 POSTGRES_HOST=192.168.0.100 POSTGRES_PORT=5432 # 공통 POSTGRES_DB=main_db POSTGRES_USER=robeings POSTGRES_PASSWORD=robeings ``` ### 서비스별 설정 ```bash # rb8001 (51124 서버) SKILL_EMAIL_URL=http://localhost:8501 # host 모드이므로 localhost STATE_SERVICE_URL=http://localhost:9024 DATABASE_URL=postgresql://robeings:robeings@192.168.0.100:5432/main_db # skill-email (51124 서버) TOKEN_PROVIDER=database # file → database POSTGRES_CONNECTION_STRING=postgresql://robeings:robeings@192.168.0.100:5432/main_db # robeing-monitor (51124 서버) PORT=9024 SERVICE_NAME=robeing-monitor DATABASE_URL=postgresql://robeings:robeings@192.168.0.100:5432/main_db ``` --- ## 8. 데이터 매핑 (추후 구현) ### Slack User ID ↔ Gmail 계정 매핑 - 위치: 추후 결정 (workspace_member 또는 별도 테이블) - 구조: ```sql -- 옵션 1: workspace_member 확장 ALTER TABLE workspace_member ADD COLUMN gmail_account VARCHAR(255); -- 옵션 2: 별도 매핑 테이블 CREATE TABLE user_gmail_mapping ( slack_user_id VARCHAR(100) PRIMARY KEY, gmail_account VARCHAR(255), robeing_id VARCHAR(50) ); ``` --- ## 9. 성공 지표 ### 기능적 요구사항 - [ ] 레벨 5 이상 사용자만 Gmail 아이템 장착 가능 - [ ] 토큰 만료 시 자동 재인증 안내 - [ ] 권한 부족(gmail.send 없음) 시 명확한 안내 ### 비기능적 요구사항 - [ ] 토큰 정보 프론트엔드 미노출 - [ ] 모든 민감 작업 감사 로그 기록 - [ ] 서비스 간 통신 안정성 확보 --- ## 10. 리스크 및 대응 ### 리스크 1: 토큰 노출 - 대응: 모든 API에서 토큰 필드 제거, capabilities만 반환 ### 리스크 2: 서비스 간 통신 실패 - 대응: 재시도 로직, Circuit Breaker 패턴 적용 ### 리스크 3: 레벨 체크 우회 - 대응: 다층 검증 (Gateway → Monitor → rb8001) --- ## 11. 결정된 표준 ### 에러 메시지 - **형식**: 개발 친화적 에러 코드 ``` GMAIL_AUTH_FAILED INSUFFICIENT_LEVEL TOKEN_EXPIRED PASSPORT_REJECTED ``` ### 응답 형식 ```typescript { status: "success" | "error", data?: any, error?: string } ``` ### UI/UX - **아이콘**: Gmail 로고 사용 - **애니메이션**: 매우 간단한 페이드인/아웃 - **메시지 톤**: 친근한 안내 - "레벨 5가 되면 사용 가능해요!" - "Gmail 재인증이 필요해요" ### 정책 - **캐싱**: 필요시에만 적용 (기본적으로 실시간) - **재시도**: 3회, 지수 백오프 - **감사 로그**: 외부 백업 연동 (이미 구축됨) - **장착 제한**: 계정당 1개 Gmail passport만 허용 --- ## 12. 참고사항 ### 현재 상태 (2025-08-19) - gmail_token 테이블 생성 완료 - rb8001 정상 작동 (GEMINI_USE_CLI=false) - skill-email 파일 기반 동작 중 (DB 전환 필요) - 프론트 인벤토리 UI 미구현 ### 주요 결정사항 - 아이템 슬롯: `passport_gmail` (패스포트 슬롯) - 레벨 제한: 5 (robeing_stats 테이블 생성 필요) - 서비스 포트: skill-email(8501), robeing-monitor(9024) - 컬럼명: robeing_id로 통일 (DB 수정 완료) - Gateway 포트: 8100 (추후 8000으로 변경 예정) - 소유 구조: User가 아이템 소유 → Robeing에게 장착 ### 다음 액션 1. skill-email DB 연결 코드 작성 2. robeing-monitor 서비스 구축 3. 프론트 인벤토리 UI 개발 4. 전체 통합 테스트 ### 작업 분담 - **종태**: 프론트엔드 (인벤토리 UI, robeing-api.ts, Context 상태) - **희재**: rb8001 통합, skill-email DB 연결 - **서버 관리자**: 테이블 생성, robeing-monitor(9024) 구축, Gateway 설정 --- **문서 끝**