From a8b8a12aa44110f6acbc38bc9ca4edd5ca5fecd6 Mon Sep 17 00:00:00 2001 From: happybell80 Date: Mon, 15 Sep 2025 15:02:23 +0900 Subject: [PATCH] =?UTF-8?q?Update=20Slack=20=EB=A9=94=EC=8B=9C=EC=A7=95=20?= =?UTF-8?q?=EC=9A=B4=EC=98=81=20=EB=9F=B0=EB=B6=81=20-=20=EC=99=84?= =?UTF-8?q?=EC=A0=84=ED=8C=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 모든 파일 경로와 함수명 추가 - 포맷/토큰/채널/스레드/DM 공통점 추가 - 차이점 요약 섹션 추가 - 엔드투엔드 흐름 요약 추가 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- ...ppybell80_Slack_메시징_운영_런북.md | 134 +++++++++++++++++- 1 file changed, 129 insertions(+), 5 deletions(-) diff --git a/troubleshooting/250915_happybell80_Slack_메시징_운영_런북.md b/troubleshooting/250915_happybell80_Slack_메시징_운영_런북.md index 292c3b1..d02c5c5 100644 --- a/troubleshooting/250915_happybell80_Slack_메시징_운영_런북.md +++ b/troubleshooting/250915_happybell80_Slack_메시징_운영_런북.md @@ -8,10 +8,87 @@ ## 구성요소 -- **rb8001**: Slack 이벤트/인터랙티브 처리(app/router/slack_handler.py), DM 전송(app/skills/dm_skill.py), 뉴스 채널 게시(app/skills/news_posting_skill.py), 간단 뉴스 전송(app/skills/startup_news_skill.py). -- **robeing-gateway**: Slack Events/Interactive 프록시(POST /slack/events, POST /slack/interactive), 팀별 봇 토큰과 사용자 UUID 주입. -- **skill-slack**: 메시지 전송/수정 API 제공(POST /api/v1/messages/send, POST /api/v1/messages/update). -- **기타 서비스(skill-email, skill-news, robeing-monitor, rb10508_micro)**: Slack 메시지 전송 로직 없음. +### rb8001 (로빙 컨테이너) +- **파일: rb8001/main.py** + - 엔드포인트 + - `POST /api/slack/events` → `app.router.slack_handler.handle()` 위임 + - `POST /api/slack/interactive` → `app.router.slack_handler.handle_interactive()` 위임 + - `POST /api/dm/send`, `POST /api/dm/send-to-user`, `POST /api/dm/send-email-summary`, `POST /api/dm/send-daily-summary` → DM 스킬 호출 + - 스케줄 + - APScheduler로 헤드라인/뉴스/DM 작업을 트리거, 실제 전송은 각 스킬에서 Slack API 호출 + +- **파일: rb8001/app/router/slack_handler.py** + - 핵심 함수 + - `handle_slack_events(request)` → Slack Events 수신 처리 + - 토큰: Gateway가 전달한 `X-Slack-Bot-Token`로 `WebClient` 생성(팀별 토큰) + - 채널/스레드/DM 판단: + - DM: `event.channel_type == "im"` → thread_ts 없음 + - 스레드: `event.thread_ts` 유지 + - 멘션(app_mention)인데 스레드가 아니면 원본 `ts`를 `thread_ts`로 사용해 스레드 시작 + - 포맷: `chat_postMessage(channel, text, thread_ts?, unfurl_links=False, unfurl_media=False)` + - I/O: Slack 이벤트(JSON) → 내부 라우터 `router.route_message()` → Slack 메시지 전송 + - `process_slack_message_async(text, user_id, context)` → 실제 메시지 생성/전송 + - `handle_interactive(request)` → 인터랙티브 액션 처리 + - Slack 서명 검증 후 액션 분기 + - 게시 버튼 처리 시 비동기 `_handle_news_publish_with_update(...)` 실행 + - `response_url`로 에페메럴 업데이트 전송(JSON POST) + - `_handle_news_publish_with_update(...)` + - 뉴스 게시 처리 후 `response_url`로 진행/성공/실패 에페메럴 메시지 전송 + +- **파일: rb8001/app/skills/dm_skill.py** + - 토큰: settings.ROBEING_SLACK_BOT_TOKEN 또는 settings.SLACK_BOT_TOKEN + - DM 전송 + - `send_daily_dm(custom_message?)` → `chat_postMessage(channel=슬랙유저ID, text)` + - `send_dm_to_user(slack_id, message)` → `chat_postMessage(...)` + - `send_email_summary_dm()` → 이메일 요약 포함 DM, `unfurl_links=False` + - `send_daily_summary_dm()` → 이메일/뉴스 합친 모닝 브리핑 DM, 전송 후 뉴스 ID 기록 + - 형식: 모두 텍스트, 필요 시 링크 미리보기 비활성화 + +- **파일: rb8001/app/skills/news_posting_skill.py** + - 토큰: COMPANYX_SLACK_BOT_TOKEN + - 채널 메시지(블록) + - `send_news_for_posting(channel?)` → 블록 생성 후 `chat_postMessage(channel, blocks, text=fallback)` + - `add_status_to_message(channel, ts, blocks)` → `chat_update`로 블록 갱신 + - 인터랙티브 진행 업데이트 + - `send_slack_update(response_url, message)` → `response_url`로 JSON POST(원본 미교체) + +- **파일: rb8001/app/skills/startup_news_skill.py** + - 토큰: COMPANYX_SLACK_BOT_TOKEN + - 채널 메시지(텍스트) + - `WebClient.chat_postMessage(channel=env 채널, text=뉴스 요약)` + +- **파일: rb8001/app/router/dm_endpoint.py** + - 엔드포인트(내부용): /api/dm/send, /api/dm/send-to-user → dm_skill 호출 + - 자체 Slack 호출은 없음(스킬이 수행) + +### robeing-gateway (게이트웨이) +- **파일: robeing-gateway/app/main.py** + - POST /slack/events → rb8001로 프록시 + - 토큰: DB에서 팀별 봇 토큰 조회(`get_slack_bot_token(team_id)`) → 헤더 `X-Slack-Bot-Token` + - 사용자: Slack User ID→UUID 매핑(`slack_user_to_uuid`) → 헤더 `X-User-Id` + - I/O: Slack→Gateway→rb8001(`/api/slack/events`), 자체 Slack 전송 없음 + - POST /slack/interactive → rb8001로 프록시 + - Slack 서명/타임스탬프/봇토큰/UUID 헤더 전달 + - 자체 Slack 전송 없음 + +### skill-slack (슬랙 도우미 스킬) +- **파일: skill-slack/app/api/endpoints/messages.py** + - 토큰: settings.SLACK_BOT_TOKEN + - 엔드포인트 + - `POST /send` → `chat_postMessage(channel, text, blocks?)` + - `POST /update` → `chat_update(channel, ts, text?, blocks?)` + - 요청/응답 모델: app/models/requests.py(채널/텍스트/블록/ts/thread_ts 필드 정의), app/models/responses.py + - 현재 rb8001가 직접 호출하는 경로는 확인되지 않음(요약/액션 추출은 별도 API를 호출) + +- **파일: skill-slack/app/services/slack_client.py** + - Slack 데이터 조회용 HTTP 호출(threads, history, users.info) 구현 + - 메시지 전송은 위 /send가 수행 + +### 기타 서비스 +- robeing-monitor: Slack 메시지 전송 없음(아이템/프리퍼런스 API) +- skill-email/skill-news: Slack 메시지 전송 없음(내부 로직 또는 외부 서비스 호출) +- rb10508_micro: Slack 전송 없음(채널/스레드 ID를 컨텍스트로만 이동) +- frontend-base, auth-server: Slack OAuth/관리 API, Slack 메시지 전송 없음 ## 토큰/식별자 @@ -70,4 +147,51 @@ - **rb8001 slack_handler**: 토큰 유효성(auth_test), 채널/스레드/이벤트 타임스탬프, 전송 성공 여부를 로그로 남김. - **rb8001 dm_skill/news_posting_skill**: 사용자별 전송 결과, Slack API 에러를 로그로 남김. -- **게이트웨이**: Slack 팀/사용자 추출, 토큰/UUID 조회 결과, 프록시 응답 코드를 로그로 남김. \ No newline at end of file +- **게이트웨이**: Slack 팀/사용자 추출, 토큰/UUID 조회 결과, 프록시 응답 코드를 로그로 남김. + +## 포맷·토큰·채널/스레드/DM 공통점 + +### 공통 +- Slack SDK WebClient.chat_postMessage/chat_update 사용 또는 Slack response_url로 JSON POST +- 텍스트 기본, 뉴스의 경우 Block Kit 사용 +- 링크 미리보기 비활성화 옵션을 종종 사용(unfurl_links, unfurl_media) + +### 토큰 소스 +- rb8001 Slack 이벤트 응답: Gateway가 전달한 팀별 X-Slack-Bot-Token 사용 +- rb8001 DM: ROBEING_SLACK_BOT_TOKEN(없으면 SLACK_BOT_TOKEN) +- Company-X 뉴스: COMPANYX_SLACK_BOT_TOKEN +- skill-slack: 자체 SLACK_BOT_TOKEN + +### 채널/스레드/DM +- DM: channel=슬랙 유저 ID로 chat_postMessage (thread_ts 없이) +- 채널: channel=채널 ID, 뉴스 포스트는 Block Kit로 다중 메시지 가능 +- 스레드: 멘션이 비스레드면 원본 ts를 thread_ts로 사용해 스레드 시작, 기존 스레드는 thread_ts 유지 + +### 에페메럴/진행상황 +- 인터랙티브 후속 안내는 response_url로 에페메럴 메시지(원본 미교체, 삭제하지 않음) + +## 차이점 요약 + +### 전송 위치 +- 이벤트/인터랙티브 응답: rb8001 slack_handler가 채널/스레드로 직접 전송 +- 정기 DM: rb8001 dm_skill이 사용자 DM으로 전송 +- 뉴스 브로드캐스트: rb8001 news_posting_skill/startup_news_skill이 채널로 블록/텍스트 전송 + +### 스레드 처리 +- rb8001 slack_handler만 자동 스레드 생성/유지 로직 보유 +- skill-slack /send는 현재 코드에서 thread_ts를 파라미터로 받지만 미사용(전달 안 함) + +### 토큰 선택 +- rb8001 이벤트 응답은 게이트웨이로부터 팀별 토큰 주입(워크스페이스별 분리) +- DM/Company-X는 고정 환경변수 토큰 사용 + +## 엔드투엔드 흐름 요약 + +### Slack 이벤트 +- Slack → Gateway(/slack/events) → DB에서 팀별 봇 토큰/UUID 조회 → rb8001(/api/slack/events) → rb8001가 채널/스레드/DM 판정 후 chat_postMessage + +### Slack 인터랙티브 +- Slack → Gateway(/slack/interactive) → rb8001 → 액션 처리(뉴스 게시 등) → response_url로 진행/완료 에페메럴 메시지 + +### 스케줄링/DM/뉴스 +- APScheduler → rb8001 스킬 → chat_postMessage 또는 chat_update 사용해 DM/채널 전송 \ No newline at end of file