DOCS/journey/troubleshooting/250902_slack_bot_install_url_analysis.md
Claude-51124 22557e7132 docs: 오래된 트러블슈팅 아카이브 및 구조 정리
- 7-8월 초기 구축 문서 12개를 _archive/troubleshooting/2025_07-08_initial_setup/로 이동
- book/300_architecture/390_human_in_the_loop_intent_learning.md를 journey/research/intent_classification/로 이동 (개발 여정 문서)
- 빈 폴더 제거 (journey/assets/*)
2025-11-17 14:06:05 +09:00

8.7 KiB

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 관리 개선

# 현재: 메모리 딕셔너리
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)

# 필요 환경변수
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 생성

# 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 설정 정보

환경변수:

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. 후속 작업