diff --git a/250818_gmail_tokens_database_setup.md b/250818_gmail_tokens_database_setup.md new file mode 100644 index 0000000..e9c2738 --- /dev/null +++ b/250818_gmail_tokens_database_setup.md @@ -0,0 +1,257 @@ +# Gmail Tokens 데이터베이스 구성 + +## 작성일: 2025-08-18 +## 작성자: Claude (with heejae) + +--- + +## 1. 테이블 생성 정보 + +### 1.1 데이터베이스 접속 정보 +```bash +Host: localhost +Port: 5432 +Database: auth_db +User: robeings +Password: robeings +``` + +### 1.2 생성된 테이블: `gmail_tokens` + +```sql +CREATE TABLE gmail_tokens ( + id SERIAL PRIMARY KEY, + user_id VARCHAR(100) UNIQUE NOT NULL, + robing_id VARCHAR(50), + token_data JSONB NOT NULL, + oauth_config JSONB, + scopes JSONB, + metadata JSONB, + expiry TIMESTAMP, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); +``` + +--- + +## 2. JSONB 컬럼 구조 + +### 2.1 token_data (필수) +```json +{ + "access_token": "ya29.xxxx", + "refresh_token": "1//xxxx", + "token_type": "Bearer" +} +``` + +### 2.2 oauth_config +```json +{ + "client_id": "xxx.apps.googleusercontent.com", + "client_secret": "GOCSPX-xxxx", + "token_uri": "https://oauth2.googleapis.com/token", + "auth_uri": "https://accounts.google.com/o/oauth2/auth" +} +``` + +### 2.3 scopes +```json +[ + "https://www.googleapis.com/auth/gmail.send", + "https://www.googleapis.com/auth/gmail.readonly", + "https://www.googleapis.com/auth/gmail.modify" +] +``` + +### 2.4 metadata +```json +{ + "email": "user@gmail.com", + "display_name": "사용자명", + "account_type": "gmail", + "slack_user_id": "U091UNVE41M", + "source_file": "original_filename.json", + "imported_at": "2025-08-18" +} +``` + +--- + +## 3. 인덱스 구성 + +```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); + +-- JSON 검색용 GIN 인덱스 +CREATE INDEX idx_gmail_tokens_token_data ON gmail_tokens USING GIN (token_data); +CREATE INDEX idx_gmail_tokens_oauth_config ON gmail_tokens USING GIN (oauth_config); +``` + +--- + +## 4. 자동 업데이트 트리거 + +```sql +-- updated_at 자동 갱신 함수 +CREATE OR REPLACE FUNCTION update_updated_at_column() +RETURNS TRIGGER AS $$ +BEGIN + NEW.updated_at = CURRENT_TIMESTAMP; + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +-- 트리거 생성 +CREATE TRIGGER update_gmail_tokens_updated_at +BEFORE UPDATE ON gmail_tokens +FOR EACH ROW +EXECUTE FUNCTION update_updated_at_column(); +``` + +--- + +## 5. 마이그레이션 완료 데이터 + +### 5.1 원본 파일 위치 +``` +/home/admin/auth-server/tokens/ +├── heejae_gmail.json +├── test_gmail.json +└── unknown_gmail.json +``` + +### 5.2 현재 저장된 데이터 +| user_id | robing_id | 권한 상태 | 이메일 발송 가능 | +|---------|-----------|-----------|-----------------| +| heejae | rb8001 | gmail.modify만 있음 | ❌ 불가능 | +| test | rb8001 | gmail.send + modify | ✅ 가능 | +| unknown | NULL | 프로필 권한만 | ❌ 불가능 | + +### 5.3 권한 문제 +- **중요**: `gmail.modify`만으로는 이메일 발송 불가 +- 이메일 발송하려면 `gmail.send` 권한 필수 +- heejae 계정은 재인증 필요 + +--- + +## 6. 유용한 쿼리 + +### 6.1 토큰 조회 +```sql +-- 특정 사용자 토큰 조회 +SELECT token_data->>'access_token' as access_token +FROM gmail_tokens +WHERE user_id = 'test'; + +-- 이메일 발송 가능한 사용자 찾기 +SELECT user_id, robing_id +FROM gmail_tokens +WHERE scopes @> '["https://www.googleapis.com/auth/gmail.send"]'; +``` + +### 6.2 토큰 업데이트 +```sql +-- 액세스 토큰 갱신 +UPDATE gmail_tokens +SET token_data = jsonb_set( + token_data, + '{access_token}', + '"new_access_token"' +) +WHERE user_id = 'test'; + +-- 스코프 추가 +UPDATE gmail_tokens +SET scopes = scopes || '["https://www.googleapis.com/auth/gmail.send"]'::jsonb +WHERE user_id = 'heejae'; +``` + +### 6.3 메타데이터 활용 +```sql +-- Slack 사용자와 매핑 +SELECT * FROM gmail_tokens +WHERE metadata->>'slack_user_id' = 'U091UNVE41M'; + +-- 특정 로빙의 Gmail 계정 찾기 +SELECT user_id, metadata->>'email' as gmail_account +FROM gmail_tokens +WHERE robing_id = 'rb8001'; +``` + +--- + +## 7. Python 연동 예시 + +```python +import psycopg2 +import json +from psycopg2.extras import RealDictCursor + +# 연결 +conn = psycopg2.connect( + host="localhost", + database="auth_db", + user="robeings", + password="robeings" +) + +# 토큰 조회 +with conn.cursor(cursor_factory=RealDictCursor) as cur: + cur.execute(""" + SELECT + token_data->>'access_token' as access_token, + token_data->>'refresh_token' as refresh_token, + oauth_config, + scopes + FROM gmail_tokens + WHERE user_id = %s + """, ('test',)) + + token_info = cur.fetchone() + + # Google OAuth 객체 생성에 사용 + credentials = { + 'token': token_info['access_token'], + 'refresh_token': token_info['refresh_token'], + 'client_id': token_info['oauth_config']['client_id'], + 'client_secret': token_info['oauth_config']['client_secret'], + 'scopes': token_info['scopes'] + } +``` + +--- + +## 8. 다음 단계 TODO + +1. **권한 수정 필요** + - heejae 계정에 `gmail.send` 권한 추가 (재인증 필요) + - unknown 계정 용도 확인 및 권한 설정 + +2. **Slack 사용자 매핑** + - metadata에 slack_user_id 추가 + - Slack User ID ↔ Gmail 계정 매핑 테이블 고려 + +3. **토큰 자동 갱신** + - refresh_token 사용한 자동 갱신 로직 구현 + - expiry 필드 활용한 만료 체크 + +4. **보안 강화** + - 토큰 암호화 고려 + - 접근 로그 테이블 추가 + +5. **skill-email 서비스 수정** + - 파일 기반 → DB 기반 토큰 조회로 변경 + - PostgreSQL 연결 설정 추가 + +--- + +## 9. 참고사항 + +- JSONB 타입 사용으로 유연한 스키마 확장 가능 +- GIN 인덱스로 JSON 내부 검색 성능 최적화 +- 트리거로 updated_at 자동 관리 +- 모든 토큰 정보가 중앙 집중식으로 관리됨 \ No newline at end of file