# Slack 봇 설치 URL 및 Event 수신 구조 분석 ## 작성일: 2025-09-02 ## 작성자: 51123 서버 관리자 ## 이슈: Slack 봇 설치 URL 직접 생성 및 Event URL 자동 설정 방안 --- ## 1. 현황 분석 ### 1.1 구현 완료 항목 - **OAuth 엔드포인트**: `/auth/slack/passport/install` (app/providers/slack.py:387) - **콜백 처리**: `/auth/slack/passport/callback` (app/providers/slack.py:456) - **Event 라우터**: `/slack/events/router` (app/api/slack_router.py:49) - **환경변수**: SLACK_CLIENT_ID, SLACK_CLIENT_SECRET 설정됨 - **DB 테이블**: slack_workspaces, slack_user_mapping 정상 존재 ### 1.2 문제점 - **State 저장**: 메모리 딕셔너리(oauth_states) 사용 → 직접 URL 생성 시 검증 실패 - **workspace_id**: 하드코딩 (app/providers/slack.py:422) → 실제 매핑 구현 필요 - **Event URL**: 봇 설치와 별개로 Slack App 설정에서 수동 등록 필요 ## 2. 해결 방안 ### 2.1 State 관리 개선 ```python # 현재: 메모리 딕셔너리 oauth_states[state] = {...} # line 436 # 개선: Redis 사용 (이미 구현된 Redis 활용) await redis_client.setex(f"oauth:state:{state}", 300, json.dumps(state_data)) ``` ### 2.2 Event URL 자동 설정 (Manifest API) ```python # 필요 환경변수 SLACK_APP_ID = "A..." # Slack App ID SLACK_APP_CONFIG_TOKEN = "xapp-..." # apps.manifest:write 스코프 # Manifest 업데이트 (봇 설치 콜백 후 1회) manifest = { "settings": { "event_subscriptions": { "request_url": "https://auth.ro-being.com/slack/events/router", "bot_events": ["app_mention", "message.channels", "message.groups", "message.im"] } } } ``` ### 2.3 직접 URL 생성 ```bash # OAuth URL 구조 https://slack.com/oauth/v2/authorize? client_id=9073915808149.9085704341778& scope=chat:write,channels:read,channels:history,groups:read,groups:history,im:read,im:history,users:read,team:read,files:read,app_mentions:read& redirect_uri=https://auth.ro-being.com/auth/slack/passport/callback& state={RANDOM_STATE} ``` ## 3. 실행 계획 ### 3.1 즉시 적용 가능 1. Slack App 설정에서 Event URL 수동 등록 (1회) 2. 현재 코드로 봇 설치 진행 가능 ### 3.2 코드 개선 필요 1. Redis로 state 저장 로직 변경 2. workspace_id 하드코딩 제거 (Line 422: 550e8400-e29b-41d4-a716-446655440000) 3. Manifest API 자동화 스크립트 추가 (현재 구현 없음) ### 3.3 Redis 사용 현황 (2025-09-02 추가) **엔드포인트별 state 저장 방식:** - `/auth/slack/login/` (Line 78-89): Redis 사용 (`await redis_client.setex()`) - `/auth/slack/passport/install` (Line 436): 메모리 dict 사용 (`oauth_states[state] = {}`) - `/auth/slack/passport/callback` (Line 490-494): 메모리 dict 읽기 (`oauth_states.pop(state)`) **전체 엔드포인트 목록 (7개):** 1. `/login/` - 사용자 로그인 (Redis) 2. `/login/callback` - 로그인 콜백 (Redis) 3. `/passport/install` - 봇 설치 (메모리 dict) 4. `/passport/callback` - 봇 설치 콜백 (메모리 dict) 5. `/passport/status/{workspace_id}` - 상태 확인 6. `/passport/uninstall/{workspace_id}` - 봇 제거 7. `/passport/token/{workspace_id}` - 토큰 조회 **문제점:** - 동일 파일(slack.py)에서 Redis와 메모리 dict 혼용 - 서버 재시작 시 영향: - 로그인 state: Redis에 저장되어 유지됨 - 봇 설치 state: 메모리에서 소실됨 - 봇 설치 진행 중 서버 재시작 시 콜백 실패 ## 4. 중요 발견사항 ### 4.1 Event URL 관련 - OAuth 설치 ≠ Event URL 설정 (별개 프로세스) - Manifest API로 자동 업데이트 가능 (apps.manifest.update) - Event 처리 엔드포인트: `/slack/events/router` (app/api/slack_router.py) - url_verification 처리 구현됨 (Line 76-77) - team_id로 workspace 식별 - Slack App 설정에서 수동 등록 필요 ### 4.2 Event 처리 흐름 (2025-09-02 확인) 1. Slack → `/slack/events/router` (중앙 수신) 2. team_id로 slack_workspaces 테이블 조회 3. workspace.robeing_port로 컨테이너 라우팅 4. `http://localhost:{port}/events`로 전달 (rb8001 아님) 5. 헤더 추가: X-Workspace-Id, X-Workspace-Subdomain ### 4.3 아키텍처 - 컨테이너별 라우팅: 각 workspace는 고유 robeing_port 보유 - 단일 Event URL로 모든 워크스페이스 처리 후 분산 - Interactivity/Slash Commands 없이도 기본 기능 충분 ## 5. 참고사항 - Event URL: `https://auth.ro-being.com/slack/events/router` (api 접두사 없음) - DB 스키마: DOCS 문서 업데이트 완료 (tables.md) - Python 모델: SlackWorkspace의 workspace_id는 실제로 company_id 사용 ### 5.1 PostgreSQL 테이블 현황 (2025-09-02) **slack_workspaces 테이블:** - 2개 워크스페이스 등록 (T035VFRKCN6, T097FCTDVEX) - 동일 app_id 사용: A092HLQA1NW - bot_user_id 저장됨 (U0988K1BLQY, U097FFP4QQ3) - 모두 is_active = true **관련 테이블:** - workspaces: robeing_port, subdomain 컬럼 보유 - workspace_member: workspace_id, user_id, robeing_id 매핑 - slack_user_mapping: 사용자 매핑 ### 5.2 Slack 설정 정보 **환경변수:** - SLACK_CLIENT_ID: 9073915808149.9085704341778 - SLACK_CLIENT_SECRET: 5f8701a3c97a9e0b406817f44f5dbb5f - SLACK_REDIRECT_URI: https://auth.ro-being.com/auth/slack/callback **Bot Scopes (11개):** chat:write, channels:read, channels:history, groups:read, groups:history, im:read, im:history, users:read, team:read, files:read, app_mentions:read ### 5.3 주요 문제점 (2025-09-02 해결됨) **workspace_id 하드코딩 문제 ✅ 해결:** - ~~TODO 주석만 있고 구현 안 됨~~ - ~~모든 사용자가 동일 workspace_id 사용 (550e8400-e29b-41d4-a716-446655440000)~~ - ~~workspace_member 조회 코드 주석 처리됨~~ **해결 내용:** 1. ~~WorkspaceMember 조회 로직 활성화 (Line 411-419)~~ → sqlalchemy text() 직접 쿼리로 변경 2. 하드코딩 UUID 제거 (Line 422) ✅ 3. is_active 체크 추가 ✅ 4. ~~WorkspaceMember import 추가~~ → 모델 없어서 제거, text() 사용 5. info@company-x.partners가 Company-X workspace (99d22d6b-d327-4fa4-bd2f-d228c11056e2)로 연결됨 ✅ **추가 해결 (2025-09-02):** - oauth_states 메모리 dict → Redis 전환 완료 - Line 436-446: `await redis_client.setex(f"oauth:passport:{state}", 300, ...)` - Line 490-502: Redis get/delete 사용 - 서버 재시작 시에도 state 유지됨 **WorkspaceMember 모델 이슈:** - app/models/workspace.py에 WorkspaceMember 클래스 정의 없음 - workspace_member 테이블 직접 쿼리로 해결 - ~~`SELECT workspace_id FROM workspace_member WHERE user_id = :user_id::uuid AND is_active = true`~~ - `SELECT workspace_id FROM workspace_member WHERE user_id = (:user_id)::uuid AND is_active = true` (괄호 필수) ### 5.4 추가 이슈 해결 (2025-09-02 저녁) **SLACK_REDIRECT_URI 불일치:** - .env: `/auth/slack/callback` → `/auth/slack/passport/callback` 수정 - Slack App 설정: 3개 URL 모두 등록 (callback, login/callback, passport/callback) **SlackWorkspace 모델 불일치:** - 모델 정의: `company_id` (Line 44, ForeignKey는 company.id) - 코드 사용: `workspace_id` 시도 → `company_id`로 수정 필요 - Line 542, 557, 631, 674, 713: workspace_id → company_id - DB 현실: company 테이블 없음, workspaces 테이블 사용 중 **Company-X 설정 상태:** - workspace_id: 99d22d6b-d327-4fa4-bd2f-d228c11056e2 - 총 8명: company-x.partners(6) + sigong-ip.com(2) - info@company-x.partners: OWNER role - ~~**봇 설치 실패**: Foreign Key 에러~~ → **해결 완료** ### 5.5 최종 이슈 (✅ 해결 완료) **Foreign Key 문제 해결:** - 모델: `ForeignKey("company.id")` 참조 - ~~실제 DB: company 테이블 없음~~ → **company 테이블 존재 확인됨** - 해결 내용: 1. company 테이블에 Company-X 레코드 추가 (ID: 99d22d6b-d327-4fa4-bd2f-d228c11056e2) 2. 기존 slack_workspaces 레코드의 company_id 업데이트 완료 3. Foreign Key 제약 조건 정상 작동 **최종 DB 상태 (2025-09-02 20:40):** - company 테이블: Company-X (8001 포트, active 상태) - workspaces 테이블: Company-X (8명 멤버) - slack_workspaces: T097FCTDVEX → Company-X 연결 완료 - 봇 설치 준비 완료 ## 6. Company-X 봇 설치 완료 (2025-09-02 23:00) ### 6.1 설치 완료 정보 **Company-X 봇 설치 성공:** - Team ID: T09C98KB933 - Team Name: COMPANY X - Bot User ID: U09DWLARFQQ - App ID: A092HLQA1NW - Bot Token: 저장 완료 - 11개 권한 모두 부여됨 **결과:** - 봇 설치 프로세스 정상 완료 - slack_workspaces 테이블에 저장됨 - Event URL 수동 등록 필요 --- ## 7. 후속 작업 - 멀티 워크스페이스 토큰 관리 문제는 별도 문서 참조 - 참고: [250903_slack_multi_workspace_token_issue.md](./250903_slack_multi_workspace_token_issue.md)