diff --git a/troubleshooting/20251002_slack_bot_403_error.md b/troubleshooting/20251002_slack_bot_403_error.md new file mode 100644 index 0000000..93936d7 --- /dev/null +++ b/troubleshooting/20251002_slack_bot_403_error.md @@ -0,0 +1,120 @@ +# Slack 봇 메시지 403 에러 처리 + +## 발생 일시 +2025-10-02 13:29 ~ 13:31 + +## 현상 +robeing-gateway 로그에서 지속적인 403 Forbidden 에러 발생 + +### 에러 로그 +``` +app.services.slack_proxy - WARNING - No UUID found for Slack user U0935RJ60V6 +app.routers.slack - ERROR - User not registered: team_id=T0925SXPS4D, slack_user_id=U0935RJ60V6 +``` + +### 패턴 +- **빈도**: 1-2분마다 반복 발생 +- **HTTP 응답**: 403 Forbidden +- **영향**: 불필요한 에러 로그 생성, 리소스 낭비 + +## 원인 분석 + +### 문제의 핵심 +`U0935RJ60V6`는 로빙(Robeing) 봇의 Slack User ID로, 봇이 메시지를 보낼 때마다 게이트웨이가 이를 일반 사용자 메시지로 처리하려고 시도 + +### 상세 분석 +1. **현재 로직** + - 모든 Slack 이벤트에 대해 UUID 매핑 요구 + - 봇 메시지도 사용자 등록 검증 시도 + - UUID가 없으면 403 반환 + +2. **정상 동작 vs 비정상 동작** + - 정상: `U0925SXQFDK`(사용자) → UUID 변환 성공 → rb8001 전달 → 200 OK + - 비정상: `U0935RJ60V6`(봇) → UUID 찾기 실패 → 403 Forbidden + +## 해결 방안 + +### 1. 즉시 적용 가능한 수정 +`/home/admin/robeing-gateway/app/routers/slack.py` 수정 + +#### 방법 1: 하드코딩 (빠른 수정) +```python +# Line 56-57 사이에 추가 +team_id, slack_user_id = extract_team_and_user_from_event(body) + +# Skip bot messages +if slack_user_id == "U0935RJ60V6": + logger.info(f"Skipping bot message from {slack_user_id}") + return JSONResponse({"ok": True}, status_code=200) + +logger.info(f"Slack event from team: {team_id}, user: {slack_user_id}") +``` + +#### 방법 2: 환경변수 활용 (권장) +1. `.env` 파일에 추가: + ``` + SLACK_BOT_USER_ID=U0935RJ60V6 + ``` + +2. 코드 수정: + ```python + import os + + SLACK_BOT_USER_ID = os.getenv("SLACK_BOT_USER_ID") + + # Line 56-57 사이에 추가 + if slack_user_id == SLACK_BOT_USER_ID: + logger.info(f"Skipping bot message from {slack_user_id}") + return JSONResponse({"ok": True}, status_code=200) + ``` + +### 2. 장기적 개선 방안 + +#### Slack 이벤트 타입별 처리 +```python +# event 타입 확인 +event_type = body.get("event", {}).get("type") +event_subtype = body.get("event", {}).get("subtype") + +# bot_message 서브타입 필터링 +if event_subtype == "bot_message": + logger.debug(f"Skipping bot_message from {slack_user_id}") + return JSONResponse({"ok": True}, status_code=200) +``` + +#### 봇 ID 목록 관리 +여러 봇을 사용하는 경우 환경변수에 쉼표로 구분: +``` +SLACK_BOT_USER_IDS=U0935RJ60V6,U1234567890 +``` + +## 적용 절차 + +1. 로컬 개발 환경에서 코드 수정 +2. Git push → Gitea Actions 자동 배포 +3. 게이트웨이 재시작 확인 +4. 로그 모니터링으로 403 에러 해결 확인 + +## 검증 방법 + +```bash +# 403 에러 확인 +docker logs robeing-gateway --tail 100 | grep "U0935RJ60V6" + +# 수정 후 정상 동작 확인 +docker logs robeing-gateway --tail 100 | grep "Skipping bot message" +``` + +## 교훈 + +1. **봇과 사용자 구분 필수**: Slack 이벤트 처리 시 봇 메시지는 별도 처리 필요 +2. **환경변수 활용**: 봇 ID 등 변경 가능한 값은 환경변수로 관리 +3. **이벤트 타입 확인**: Slack의 subtype 필드 활용으로 더 정확한 필터링 가능 + +## 관련 파일 +- `/home/admin/robeing-gateway/app/routers/slack.py` +- `/home/admin/robeing-gateway/.env` + +## 참고사항 +- Slack Bot User ID는 워크스페이스마다 다를 수 있음 +- 봇 메시지 필터링은 성능 향상과 로그 정리에 도움 \ No newline at end of file