From d79b55ef45437f9379ae727123b0f7564a90c371 Mon Sep 17 00:00:00 2001 From: happybell80 Date: Tue, 19 Aug 2025 08:59:50 +0900 Subject: [PATCH] =?UTF-8?q?Gmail=20=EC=95=84=EC=9D=B4=ED=85=9C=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20=EA=B3=84=ED=9A=8D=20=EC=88=98=EB=A6=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Gmail passport 아이템 시스템 설계 - 작업 분담: 종태(프론트), 희재(통합), 서버관리자(인프라) - robeing_id로 컬럼명 통일 - 레벨 5 제한, passport 슬롯 정의 - DB 테이블 구조 수정 (robing_id → robeing_id) --- 250818_gmail_tokens_database_setup.md | 10 +- .../250819_gmail_item_implementation_plan.md | 372 ++++++++++++++++++ 2 files changed, 377 insertions(+), 5 deletions(-) create mode 100644 plans/250819_gmail_item_implementation_plan.md diff --git a/250818_gmail_tokens_database_setup.md b/250818_gmail_tokens_database_setup.md index e9c2738..f8a1e41 100644 --- a/250818_gmail_tokens_database_setup.md +++ b/250818_gmail_tokens_database_setup.md @@ -22,7 +22,7 @@ Password: robeings CREATE TABLE gmail_tokens ( id SERIAL PRIMARY KEY, user_id VARCHAR(100) UNIQUE NOT NULL, - robing_id VARCHAR(50), + robeing_id VARCHAR(50), token_data JSONB NOT NULL, oauth_config JSONB, scopes JSONB, @@ -84,7 +84,7 @@ CREATE TABLE gmail_tokens ( ```sql -- 기본 인덱스 CREATE INDEX idx_gmail_tokens_user_id ON gmail_tokens(user_id); -CREATE INDEX idx_gmail_tokens_robing_id ON gmail_tokens(robing_id); +CREATE INDEX idx_gmail_tokens_robeing_id ON gmail_tokens(robeing_id); -- JSON 검색용 GIN 인덱스 CREATE INDEX idx_gmail_tokens_token_data ON gmail_tokens USING GIN (token_data); @@ -125,7 +125,7 @@ EXECUTE FUNCTION update_updated_at_column(); ``` ### 5.2 현재 저장된 데이터 -| user_id | robing_id | 권한 상태 | 이메일 발송 가능 | +| user_id | robeing_id | 권한 상태 | 이메일 발송 가능 | |---------|-----------|-----------|-----------------| | heejae | rb8001 | gmail.modify만 있음 | ❌ 불가능 | | test | rb8001 | gmail.send + modify | ✅ 가능 | @@ -148,7 +148,7 @@ FROM gmail_tokens WHERE user_id = 'test'; -- 이메일 발송 가능한 사용자 찾기 -SELECT user_id, robing_id +SELECT user_id, robeing_id FROM gmail_tokens WHERE scopes @> '["https://www.googleapis.com/auth/gmail.send"]'; ``` @@ -179,7 +179,7 @@ WHERE metadata->>'slack_user_id' = 'U091UNVE41M'; -- 특정 로빙의 Gmail 계정 찾기 SELECT user_id, metadata->>'email' as gmail_account FROM gmail_tokens -WHERE robing_id = 'rb8001'; +WHERE robeing_id = 'rb8001'; ``` --- diff --git a/plans/250819_gmail_item_implementation_plan.md b/plans/250819_gmail_item_implementation_plan.md new file mode 100644 index 0000000..c587ade --- /dev/null +++ b/plans/250819_gmail_item_implementation_plan.md @@ -0,0 +1,372 @@ +# Gmail 아이템 구현 계획 + +## 작성일: 2025-08-19 +## 작성자: Claude (with 종태) +## 상태: 계획 수립 + +--- + +## 1. 개요 + +### 목적 +Gmail 자격증명을 "API 아이템"으로 정의하고, robeing의 장착형 아이템 시스템에 통합 + +### 핵심 원칙 +- Gmail OAuth 토큰을 극비 데이터로 취급 +- 아이템 장착/해제 메타포로 권한 관리 +- RBAC+ABAC 하이브리드 접근 제어 +- 레벨 5 이상에서 사용 가능 + +### 관련 문서 +- `/250817_email_skill_integration_status.md` - 현황 분석 +- `/250818_gmail_tokens_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_tokens.id + userId: string; // gmail_tokens.user_id + robeing_id?: string; // gmail_tokens.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_tokens 테이블) +``` + +### 서비스별 역할 + +#### auth-server +- Gmail OAuth 플로우 처리 +- gmail_tokens 테이블 관리 +- 토큰 갱신 로직 + +#### robeing-monitor (9024) +- 아이템 상태 관리 +- 장착/해제 로직 +- 레벨 요구사항 체크 +- 아이템 인벤토리 조회 + +#### rb8001 +- 아이템 사용 로직 +- skill-email 호출 +- 사용자 컨텍스트 관리 + +#### skill-email (8501) +- Gmail API 실제 호출 +- 이메일 작성/발송 +- DB 기반 토큰 조회 + +--- + +## 4. 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: 백엔드 기초 +- [ ] 필요 테이블 생성 + - robeing_stats 테이블 (레벨 관리) + - gmail_audit_logs 테이블 (감사 로그) + - gmail_tokens에 is_equipped, equipped_to 컬럼 추가 +- [ ] skill-email DB 연결 코드 작성 + - FileCredentialsProvider → DBCredentialsProvider 전환 + - PostgreSQL 연결 설정 추가 (192.168.219.45) +- [ ] 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.219.45 +POSTGRES_PORT=5432 + +# 공통 +POSTGRES_DB=auth_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.219.45:5432/auth_db + +# skill-email (51124 서버) +TOKEN_PROVIDER=database # file → database +POSTGRES_CONNECTION_STRING=postgresql://robeings:robeings@192.168.219.45:5432/auth_db + +# robeing-monitor (51124 서버) +PORT=9024 +SERVICE_NAME=robeing-monitor +DATABASE_URL=postgresql://robeings:robeings@192.168.219.45:5432/auth_db +``` + +--- + +## 8. 데이터 매핑 (추후 구현) + +### Slack User ID ↔ Gmail 계정 매핑 +- 위치: 추후 결정 (workspace_members 또는 별도 테이블) +- 구조: +```sql +-- 옵션 1: workspace_members 확장 +ALTER TABLE workspace_members +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_tokens 테이블 생성 완료 +- 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 설정 + +--- + +**문서 끝** \ No newline at end of file