Slack 로그인 문서 개선 및 UUID5 제거

- UUID5 → UUID 매핑 테이블 조회 방식으로 전면 변경
- Slack/Gmail 로그인 엔드포인트 구조 통일 (/login/, /login/callback)
- localStorage 'token' 키로 통일, JWT 24시간, refresh 없음
- OAuth는 auth-server 직접, API는 Gateway 경유 명시
- 불필요한 의사코드 제거
This commit is contained in:
happybell80 2025-08-29 12:17:59 +09:00
parent 9db8dcec76
commit c01c266e59
7 changed files with 109 additions and 90 deletions

View File

@ -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<br/>name: Slack User ID<br/>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<br/>username: slack_U0925SXQ<br/>email: slack.email
else 기존 사용자
Auth->>DB: UPDATE users
Note over DB: id: UUID<br/>username: slack_U0925SXQ<br/>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 생성<br/>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() 생성<br/>매핑 테이블에 저장"]
B -->|테스트 사용자| K[수동 UUID 할당]
K --> L["하드코딩 UUID<br/>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 직접 조회
```
---

View File

@ -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로 테이블 조회 필요
- 네임스페이스 비공개 유지 (소스코드에서만 관리)
---

View File

@ -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 (
<button
className="slack-login-btn"
onClick={handleMockLogin}
>
<img src="/assets/integrations/slack-logo.svg" />
Sign in with Slack
</button>
);
};
```
상세 구현은 [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 }`

View File

@ -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주)
```

View File

@ -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) - 확인 완료

View File

@ -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})

View File

@ -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단계: 서비스 간 인증 ✅