From c01c266e59c565ff4012e820dd6614a4e8d4f948 Mon Sep 17 00:00:00 2001 From: happybell80 Date: Fri, 29 Aug 2025 12:17:59 +0900 Subject: [PATCH] =?UTF-8?q?Slack=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EB=AC=B8?= =?UTF-8?q?=EC=84=9C=20=EA=B0=9C=EC=84=A0=20=EB=B0=8F=20UUID5=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - UUID5 → UUID 매핑 테이블 조회 방식으로 전면 변경 - Slack/Gmail 로그인 엔드포인트 구조 통일 (/login/, /login/callback) - localStorage 'token' 키로 통일, JWT 24시간, refresh 없음 - OAuth는 auth-server 직접, API는 Gateway 경유 명시 - 불필요한 의사코드 제거 --- .../sequences/auth_login_sequences.md | 36 +++++----- 300_architecture/uuid_conversion_system.md | 35 +++++----- ...250828_frontend_slack_login_mockup_plan.md | 70 ++++++++++--------- plans/250828_slack_integration_level3_plan.md | 44 +++++++----- .../250827_UUID_username_혼용_CRITICAL.md | 2 +- ...UUID_통합_및_사용자_격리_계획.md | 2 +- ...250828_slack_auth_integration_completed.md | 10 +-- 7 files changed, 109 insertions(+), 90 deletions(-) diff --git a/300_architecture/sequences/auth_login_sequences.md b/300_architecture/sequences/auth_login_sequences.md index 26ba7da..7561b0d 100644 --- a/300_architecture/sequences/auth_login_sequences.md +++ b/300_architecture/sequences/auth_login_sequences.md @@ -143,23 +143,25 @@ sequenceDiagram SlackAPI-->>Auth: access_token, user info Note over Auth: Slack User ID: U0925SXQFDK - Auth->>Auth: UUID5 생성 - Note over Auth: namespace: 6ba7b810-9dad-11d1-80b4-00c04fd430c8
name: Slack User ID
UUID5 = uuid5(namespace, slack_id) + Auth->>DB: SELECT user_id FROM slack_user_mapping WHERE slack_user_id=? + Note over DB: Slack ID로 매핑 테이블 조회 - Auth->>DB: SELECT * FROM users WHERE id=? - Note over DB: UUID5로 직접 조회 - alt 신규 사용자 + alt 매핑 존재 + DB-->>Auth: user_id (UUID) + Auth->>DB: SELECT * FROM users WHERE id=? + Note over DB: UUID로 사용자 정보 조회 + DB-->>Auth: 사용자 정보 + Auth->>DB: UPDATE users SET last_login=NOW() + else 매핑 없음 (신규) + Auth->>Auth: UUID 생성 (uuid.uuid4()) Auth->>Auth: username 생성 Note over Auth: slack_{slack_id[:8]} Auth->>DB: INSERT INTO users - Note over DB: id: UUID5
username: slack_U0925SXQ
email: slack.email - else 기존 사용자 - Auth->>DB: UPDATE users + Note over DB: id: UUID
username: slack_U0925SXQ
email: slack.email + Auth->>DB: INSERT INTO slack_user_mapping + Note over DB: slack_user_id, user_id(UUID), workspace_id end - Auth->>DB: INSERT INTO slack_users - Note over DB: slack_user_id, user_id(UUID), team_id - Auth-->>Slack: 로그인 성공 메시지 ``` @@ -216,10 +218,10 @@ flowchart TD D -->|No| F["uuid.uuid4() 생성"] B -->|Slack OAuth| G[Slack ID 받음] - G --> H["UUID5 생성
uuid5(namespace, slack_id)"] - H --> I{기존 UUID 존재?} + G --> H[slack_user_mapping 테이블 조회] + H --> I{매핑 존재?} I -->|Yes| E - I -->|No| J[UUID5로 새 사용자] + I -->|No| J["uuid.uuid4() 생성
매핑 테이블에 저장"] B -->|테스트 사용자| K[수동 UUID 할당] K --> L["하드코딩 UUID
aaaaaaaa-aaaa..."] @@ -307,7 +309,7 @@ stateDiagram-v2 식별 체계: Primary Key: UUID (36자) - Google 사용자: uuid4() 랜덤 생성 - - Slack 사용자: uuid5(namespace, slack_id) 결정적 생성 + - Slack 사용자: uuid4() 랜덤 생성 후 매핑 테이블 저장 Unique Keys: - email (OAuth provider에서 제공) - username (사용자 정의 또는 자동 생성) @@ -317,8 +319,8 @@ stateDiagram-v2 - users.id (UUID) ← slack_user_mapping.user_id - users.id (UUID) ← robeing_stats.user_id -UUID5 Namespace: - 6ba7b810-9dad-11d1-80b4-00c04fd430c8 +매핑 방식: + slack_user_mapping 테이블을 통한 Slack ID → UUID 직접 조회 ``` --- diff --git a/300_architecture/uuid_conversion_system.md b/300_architecture/uuid_conversion_system.md index cda7043..9c1963c 100644 --- a/300_architecture/uuid_conversion_system.md +++ b/300_architecture/uuid_conversion_system.md @@ -7,7 +7,7 @@ ## 1. 개요 -RO-BEING 시스템의 UUID 변환 체계 문서입니다. Google OAuth는 UUID4, Slack은 51123 DB 매핑 API를 사용합니다. +RO-BEING 시스템의 UUID 변환 체계 문서입니다. Google OAuth와 Slack 모두 UUID4를 생성하며, Slack은 slack_user_mapping 테이블을 통해 매핑합니다. --- @@ -18,7 +18,7 @@ RO-BEING 시스템의 UUID 변환 체계 문서입니다. Google OAuth는 UUID4, | 타입 | 생성 방식 | 용도 | 특징 | |------|----------|------|------| | UUID4 | 랜덤 생성 | Google OAuth 사용자 | auth-server에서 생성 | -| UUID5 | 네임스페이스 해시 | robeing-monitor 사용 중 | namespace 확인 필요 | +| UUID | 매핑 테이블 조회 | Slack 사용자 | slack_user_mapping 테이블 사용 | | DB 매핑 | slack_user_mapping | Slack 사용자 매핑 | 실제 사용 여부 확인 필요 | ### 2.2 네임스페이스 @@ -70,12 +70,12 @@ class GoogleAuthHandler: return new_user_id ``` -### 3.2 Slack 사용자 (UUID5) +### 3.2 Slack 사용자 (UUID 매핑) ```mermaid flowchart LR A[Slack 이벤트] --> B[Slack User ID] - B --> C[UUID5 생성] + B --> C[slack_user_mapping 조회] C --> D[네임스페이스 + Slack ID] D --> E[SHA-1 해시] E --> F[결정적 UUID] @@ -92,11 +92,12 @@ class SlackUserHandler: NAMESPACE = uuid.UUID('6ba7b810-9dad-11d1-80b4-00c04fd430c8') def get_user_uuid(self, slack_user_id: str) -> str: - """Slack User ID를 UUID5로 변환""" - return str(uuid.uuid5(self.NAMESPACE, slack_user_id)) + """Slack User ID를 UUID로 변환 (매핑 테이블 조회)""" + # slack_user_mapping 테이블에서 조회 + return get_uuid_from_mapping(slack_user_id) async def get_or_create_user(self, slack_user_id: str, slack_user_info: dict): - # UUID5 생성 (항상 같은 결과) + # UUID 매핑 조회 (테이블에서 조회) user_uuid = self.get_user_uuid(slack_user_id) # 기존 사용자 확인 @@ -197,18 +198,18 @@ INSERT INTO users (id, username, email, name) VALUES ('cccccccc-cccc-cccc-cccc-cccccccccccc', 'test_user', 'test@example.com', 'Test User'); ``` -### 5.2 Slack 테스트 사용자 UUID5 예시 +### 5.2 Slack 테스트 사용자 UUID 예시 ```python # Slack User ID 예시 slack_ids = { - "U0925SXQFDK": "종태", # UUID5: 생성된 값 - "U0123ABCDEF": "테스트" # UUID5: 생성된 값 + "U0925SXQFDK": "종태", # UUID: 매핑 테이블 조회 + "U0123ABCDEF": "테스트" # UUID: 매핑 테이블 조회 } -# UUID5 생성 예시 +# UUID 매핑 조회 예시 for slack_id, name in slack_ids.items(): - user_uuid = uuid.uuid5(NAMESPACE, slack_id) + user_uuid = get_uuid_from_mapping(slack_id) # DB 조회 print(f"{name} ({slack_id}): {user_uuid}") ``` @@ -321,7 +322,7 @@ async def debug_uuid(username: str): | 문제 | 원인 | 해결 방법 | |------|------|----------| -| UUID 불일치 | Slack ID 변경 | UUID5는 결정적이므로 같은 Slack ID는 항상 같은 UUID | +| UUID 불일치 | Slack ID 변경 | 매핑 테이블을 통해 일관된 UUID 관리 | | 중복 UUID | UUID4 충돌 (매우 드물음) | 재생성 또는 UNIQUE 제약 확인 | | 변환 실패 | username 없음 | users 테이블 username 필드 확인 | | 캐시 불일치 | TTL 만료 전 DB 변경 | 캐시 무효화 또는 TTL 단축 | @@ -333,7 +334,7 @@ async def debug_uuid(username: str): SELECT CASE WHEN id::text LIKE '________-____-4___-____-____________' THEN 'UUID4 (Google)' - WHEN id::text LIKE '________-____-5___-____-____________' THEN 'UUID5 (Slack)' + WHEN source = 'slack' THEN 'UUID (Slack 매핑)' ELSE 'Other' END as uuid_type, COUNT(*) as count @@ -345,12 +346,12 @@ SELECT username, id, oauth_provider FROM users WHERE username = 'happybell80'; --- Slack 사용자 UUID5 검증 +-- Slack 사용자 UUID 검증 SELECT username, id, id = uuid_generate_v5('6ba7b810-9dad-11d1-80b4-00c04fd430c8'::uuid, - SUBSTRING(username FROM 7)) as is_valid_uuid5 + SUBSTRING(username FROM 7)) as is_valid_uuid FROM users WHERE oauth_provider = 'slack'; ``` @@ -379,7 +380,7 @@ class SecureUUIDHandler: ### 10.2 UUID 추측 방지 - UUID4: 122비트 랜덤 엔트로피로 추측 불가능 -- UUID5: Slack ID를 모르면 생성 불가능 +- UUID 매핑: Slack ID로 테이블 조회 필요 - 네임스페이스 비공개 유지 (소스코드에서만 관리) --- diff --git a/plans/250828_frontend_slack_login_mockup_plan.md b/plans/250828_frontend_slack_login_mockup_plan.md index 86475ac..7282f1a 100644 --- a/plans/250828_frontend_slack_login_mockup_plan.md +++ b/plans/250828_frontend_slack_login_mockup_plan.md @@ -9,37 +9,41 @@ ## 1. 개요 -Google OAuth 외에 Slack으로도 처음 회원가입/로그인 가능하도록 Frontend 목업 구현. +Google OAuth와 Slack 로그인 모두 레벨과 무관하게 제공. Frontend 목업 구현. +- **모든 레벨**: Google OAuth + Slack 로그인 (둘 다 사용 가능) +- **레벨 2**: Gmail 권한 아이템 획득 +- **레벨 3**: Slack 아이템 획득 (봇 설치, 대화 동기화 등) - **회원가입**: Slack 계정으로 처음 로그인하는 사용자도 자동 가입 -- **Slack 권한(스코프)**: 추후 아이템으로 별도 관리 예정 - **현재 목표**: Frontend 목업만 구현, auth-server 연동은 향후 과제 ### 확인된 설정 (auth-server/.env) - **Slack Client ID**: `9073915808149.9085704341778` - **Slack Client Secret**: `5f8701a3c97a9e0b406817f44f5dbb5f` -- **Redirect URI**: `https://auth.ro-being.com/auth/slack/callback` +- **Redirect URI**: `https://auth.ro-being.com/auth/slack/login/callback` --- -## 2. 목업 구현 (Phase 1) +## 2. 백엔드 통합 계획 -### 2.1 UI 컴포넌트 -```typescript -// components/slack-login-button.tsx -const SlackLoginButton = () => { - return ( - - ); -}; -``` +상세 구현은 [250828_slack_integration_level3_plan.md](./250828_slack_integration_level3_plan.md) 참조 -### 2.2 목업 로그인 핸들러 +**핵심 요약**: +- Phase 1: Sign in with Slack (OIDC 로그인) + - `/auth/slack/login/`: OAuth URL 생성 및 리다이렉트 + - `/auth/slack/login/callback`: 토큰 교환, UUID 매핑, JWT 발급 +- Phase 2: Slack 패스포트 (레벨 3 아이템) + - `/auth/slack/passport/*`: Gmail과 동일한 패스포트 구조 + - 봇 설치, workspace 토큰 저장, 활성화/비활성화 +- Phase 3: 대화 동기화 (Slack ↔ Frontend) + +--- + +## 3. Frontend 목업 구현 + +### 3.1 UI 컴포넌트 +Slack 로그인 버튼 추가 + +### 3.2 목업 로그인 핸들러 ```typescript const handleMockLogin = () => { // Slack이 제공하는 사용자 정보 시뮬레이션 @@ -76,8 +80,8 @@ const handleMockLogin = () => { exp: Date.now() + 86400000 })); - // localStorage 키 (문서 확인됨) - localStorage.setItem('token', mockToken); // 또는 'auth_token' + // localStorage 키 통일 + localStorage.setItem('token', mockToken); // 'token'으로 통일 localStorage.setItem('authProvider', 'slack'); // Google과 구분 // 로그인 후 원래 페이지로 복귀 @@ -101,20 +105,20 @@ VITE_AUTH_SERVER_URL=https://auth.ro-being.com ``` ### 3.2 OAuth URL 생성 +state 생성 → sessionStorage 저장 → Slack OAuth URL 생성 + +### 3.3 auth-server 연동 + ```typescript -const generateSlackAuthUrl = () => { - const state = crypto.randomUUID(); - sessionStorage.setItem('slack_oauth_state', state); - - return `https://slack.com/oauth/v2/authorize?` + - `client_id=${SLACK_CLIENT_ID}&` + - `scope=openid,profile,email&` + - `redirect_uri=${encodeURIComponent(REDIRECT_URI)}&` + - `state=${state}`; -}; +- OAuth 로그인: `${VITE_AUTH_SERVER_URL}/auth/slack/login/` 직접 연결 +- API 호출: `/api/auth/slack/passport/*` Gateway 경유 ``` -### 3.3 auth-server 연동 +### 3.4 JWT 및 Storage 정책 +- **localStorage**: `token` 키로 통일 (auth_token 사용 안함) +- **JWT 만료**: 24시간, refresh token 없음 +- **OAuth State**: sessionStorage 사용 +- **User ID**: UUID 형식으로 저장 **현재 구현된 엔드포인트:** - **Slack 매핑 API**: `GET /api/slack/mapping/{slack_user_id}` ✅ 동작 확인 - 반환: `{ user_id, username, email, robeing_id }` diff --git a/plans/250828_slack_integration_level3_plan.md b/plans/250828_slack_integration_level3_plan.md index d6f86f3..fe78f01 100644 --- a/plans/250828_slack_integration_level3_plan.md +++ b/plans/250828_slack_integration_level3_plan.md @@ -10,16 +10,17 @@ ## 1. 개요 ### 목표 -- **레벨 1-2**: 일반 로그인 (Google OAuth) -- **레벨 3+**: Slack 통합 활성화 (**확인 필요**: Frontend 레벨 3 버튼 구현 여부) - - Slack OIDC 로그인 +- **모든 레벨**: Google OAuth + Slack 로그인 (둘 다 사용 가능) +- **레벨 2**: Gmail 권한 아이템 획득 (Gmail API 접근) +- **레벨 3**: Slack 아이템 획득 (**확인 필요**: Frontend 레벨 3 버튼 구현 여부) - Workspace 봇 설치 - 대화 동기화 (Frontend ↔ Slack) - 멘션(@) 및 슬래시(/) 명령 -### 현재 상태 (DOCS 확인됨) -- **기존**: `/auth/slack/command`, `/auth/slack/login`, `/auth/slack/callback` 일부 구현됨 -- **UUID 생성**: UUID5 방식 구현됨 (namespace: 6ba7b810-9dad-11d1-80b4-00c04fd430c8) +### 현재 상태 및 정책 +- **엔드포인트**: `/auth/slack/login/`, `/auth/slack/login/callback` 구조 +- **localStorage**: `token` 키 통일, JWT 24시간, refresh 없음 +- **OAuth**: auth-server 직접, API는 Gateway 경유 - **테이블**: slack_workspaces, slack_user_mapping 존재 --- @@ -31,24 +32,37 @@ Frontend → auth-server → Slack OIDC → UUID 생성 → JWT 발급 ``` -**구현**: +**백엔드 엔드포인트**: +- `GET /auth/slack/login/` - OAuth 시작 +- `GET /auth/slack/login/callback` - 토큰 교환, UUID 매핑, JWT 발급 +- `GET /api/slack/mapping/{slack_user_id}` - UUID 조회 + +**구현 상세**: 1. Slack 앱 설정에서 "Sign in with Slack" 활성화 (OpenID Connect) - - Redirect URL: `https://auth-server/auth/slack/callback` + - Redirect URL: `https://auth.ro-being.com/auth/slack/login/callback` 2. User Token 스코프: `openid`, `profile`, `email` (로그인용) 3. 콜백에서 `openid.connect.userInfo` 호출하여 사용자 정보 획득 -4. DB 저장: users 테이블에 slack_user_id, slack_team_id 추가 +4. DB 저장: users 테이블 UUID, slack_user_mapping 매핑 저장 **주의**: `identity.*` 레거시 스코프는 사용 금지 ### Phase 2: Add to Slack (단기 3-5일) ``` -Frontend(레벨3) → auth-server → OAuth 2.0 → 봇 토큰 저장 +Frontend(Slack 아이템 획득) → auth-server → OAuth 2.0 → 봇 토큰 저장 ``` +**Slack 패스포트 엔드포인트**: +- `GET /auth/slack/passport/` - 봇 설치 OAuth 시작 +- `GET /auth/slack/passport/callback` - bot_token 저장 +- `GET /auth/slack/passport/status` - 아이템 상태 확인 +- `POST /auth/slack/passport/activate` - 아이템 장착 +- `POST /auth/slack/passport/deactivate` - 아이템 해제 +- `DELETE /auth/slack/passport/` - 아이템 취소 + **구현**: 1. OAuth 2.0 플로우 (**별도**: Sign in with Slack과 분리) - Add to Slack 버튼: `https://slack.com/oauth/v2/authorize?...` - - 콜백: `/auth/slack/install/callback` + - 콜백: `/auth/slack/passport/callback` 2. Bot Token Scopes: ``` 읽기: channels:read, groups:read, channels:history, @@ -70,11 +84,9 @@ Slack Event → rb8001 → DB → SSE/WebSocket → Frontend - Request URL: `rb8001/slack/events` - 이벤트: `message.channels`, `message.groups`, `message.im`, `message.mpim`, `app_mention` - 쓰레드: `message.message_replied` 이벤트 존재하나 `thread_ts` 확인 권장 -2. **3초 규칙**: challenge 검증 및 이벤트 ACK 3초 내 필수 -3. 채널 타입: C(공개), G(비공개/그룹), D(DM) -4. conversation_logs 저장: team_id, channel_id, thread_ts -5. 초기 동기화: `conversations.history`로 백필 -6. **Rate Limits**: Events API 시간당 30,000건 (초당 ~8건), Web API는 메서드별 상이 +2. 채널 타입: C(공개), G(비공개/그룹), D(DM) +3. conversation_logs 저장: team_id, channel_id, thread_ts +4. 초기 동기화: `conversations.history`로 백필 ### Phase 4: 명령 처리 (중기 1-2주) ``` diff --git a/troubleshooting/250827_UUID_username_혼용_CRITICAL.md b/troubleshooting/250827_UUID_username_혼용_CRITICAL.md index e04fd69..43f56df 100644 --- a/troubleshooting/250827_UUID_username_혼용_CRITICAL.md +++ b/troubleshooting/250827_UUID_username_혼용_CRITICAL.md @@ -55,7 +55,7 @@ SELECT id::text as user_id # PostgreSQL UUID를 문자열로 변환 ``` **확인된 사항**: - username → UUID 변환은 DB 조회로만 수행 (계산된 변환 없음) -- UUID4 형식만 사용 (UUID5 사용 안 함) +- UUID4 형식만 사용 (UUID 표준 형식) - users 테이블에 username 없으면 변환 실패 ### 2.3 rb8001 (51124) - 확인 완료 diff --git a/troubleshooting/250828_UUID_통합_및_사용자_격리_계획.md b/troubleshooting/250828_UUID_통합_및_사용자_격리_계획.md index 3f228f0..ae1eed9 100644 --- a/troubleshooting/250828_UUID_통합_및_사용자_격리_계획.md +++ b/troubleshooting/250828_UUID_통합_및_사용자_격리_계획.md @@ -63,7 +63,7 @@ workspace (로빙 1개) - [x] slack_user_mapping 테이블 활성화 (확인됨) - [x] Gateway API /api/slack/{slack_id}/uuid 구현 - [x] rb8001에서 Slack ID → UUID 변환 구현 -- [ ] robeing-monitor UUID5 제거 (선택사항) +- [ ] robeing-monitor UUID 변환 개선 (선택사항) ### Phase 3: 사용자 격리 ✅ 완료 (2025-08-28 18:15) - [x] ChromaDB 사용자별 컬렉션 (rb8001_{user_uuid}) diff --git a/troubleshooting/250828_slack_auth_integration_completed.md b/troubleshooting/250828_slack_auth_integration_completed.md index ae67bc2..4cb8efd 100644 --- a/troubleshooting/250828_slack_auth_integration_completed.md +++ b/troubleshooting/250828_slack_auth_integration_completed.md @@ -41,7 +41,7 @@ ### rb8001 ID 처리 ✅ 완료 | 기존 방식 | 개선 완료 | 상태 | |----------|----------|------| -| UUID5(DNS namespace, slack_id) | 51123 매핑 API 호출 | ✅ 완료 | +| UUID 생성(DNS namespace, slack_id) | 51123 매핑 API 호출 | ✅ 완료 | | 로컬 변환으로 UUID 생성 | 실제 DB 매핑 사용 | ✅ 완료 | | skill-email에 Slack ID 전달 | UUID 전달로 통일 | ✅ 완료 | @@ -62,10 +62,10 @@ echo "JWT_SECRET_KEY=[REDACTED]" >> \ docker restart skill-email ``` -### 단계 2: rb8001 UUID5 → API 매핑 전환 +### 단계 2: rb8001 UUID → API 매핑 전환 ```python # /rb8001/app/skills/email_integration.py 수정 -# 기존: user_uuid = str(uuid.uuid5(namespace, user_id)) +# 기존: user_uuid = str(uuid.uuid(namespace, user_id)) # 변경: async def get_uuid_from_slack(slack_id: str): response = await httpx.get( @@ -88,7 +88,7 @@ await http_client.post(url, json=data, headers=headers) | 우선순위 | 작업 | 위치 | 상태 | |---------|------|------|------| | 1 | ~~skill-email JWT_SECRET_KEY 설정~~ | ~~51124 서버~~ | ✅ 완료 | -| 2 | ~~UUID5 → 매핑 API 전환~~ | ~~rb8001~~ | ✅ 완료 | +| 2 | ~~UUID → 매핑 API 전환~~ | ~~rb8001~~ | ✅ 완료 | | 3 | ~~서비스 간 인증 헤더 추가~~ | ~~rb8001, skill-email~~ | ✅ 완료 | | 4 | Slack OAuth auth-server 경유 | auth-server, frontend | 🔜 향후 | @@ -110,7 +110,7 @@ curl http://192.168.219.45:9000/api/slack/mapping/U0925SXQFDK - rb8001, skill-email INTERNAL_API_KEY 설정 완료 #### 2단계: ID 체계 통합 ✅ -- rb8001 UUID5 → 51123 매핑 API 전환 완료 +- rb8001 UUID → 51123 매핑 API 전환 완료 - 실제 DB 매핑으로 데이터 일관성 확보 #### 3단계: 서비스 간 인증 ✅