# 트러블슈팅: Slack 이벤트 중복 및 슬래시 명령어 처리 문제

## 발생 시간
- 2025년 9월 14일 14:15

## 문제 상황

### 1. 중복 응답 문제
`@Ro-being /search 에이전트 acp` 입력 시 동일한 응답이 2번 전송됨

### 2. 로그 분석
```
14:15:52 - app_mention 이벤트 (Event ID: Ev09EPV4FU6T)
14:15:53 - message 이벤트 (Event ID: Ev09EPV4GB1V)
14:15:57 - 첫 번째 응답 전송
14:15:58 - 두 번째 응답 전송
```

## 원인 분석

### 1. Slack Event Subscriptions 설정
```
Subscribe to bot events:
✅ app_mention - 멘션 감지용
✅ message.channels - 채널의 모든 메시지
✅ message.groups - 비공개 채널 메시지
✅ message.im - DM 메시지
✅ message.mpim - 그룹 DM 메시지
```

### 2. 이벤트 발생 패턴
- **멘션 포함 메시지**: `app_mention` + `message.channels` 동시 발생
- **일반 메시지**: `message.channels`만 발생
- **DM**: `message.im`만 발생
- **쓰레드**: `message` 이벤트에 `thread_ts` 포함

### 3. 현재 처리 로직 문제
```python
# slack_handler.py:212
if event_type == "app_mention" or (event_type == "message" and is_dm) or is_thread_message:
    # 모든 조건에서 처리 → 중복 발생
```

## 슬래시 명령어 문제

### 1. Slack 기본 명령어 충돌
- `/search`: Slack 내장 검색 기능과 충돌
- `/help`: Slack 도움말과 충돌
- 사용자가 `/search` 입력 시 Slack이 가로챔

### 2. 현재 상황별 처리
```
채널:
- @robeing 필수 (app_mention만 처리)
- /search 단독 사용 불가

DM:
- 멘션 불필요 (message.im 처리)
- /search 사용 가능

쓰레드:
- 멘션 불필요 (thread_ts 있으면 처리)
- /search 사용 가능
```

## 해결 방안

### 1. 중복 방지 (즉시 적용 가능)
```python
# slack_handler.py에 추가
processed_messages = set()  # 또는 Redis 캐시

async def handle_slack_events(request: Request):
    # ...
    client_msg_id = event.get("client_msg_id")

    # 중복 체크
    if client_msg_id and client_msg_id in processed_messages:
        return JSONResponse({"status": "ok"})

    if client_msg_id:
        processed_messages.add(client_msg_id)
        # 5분 후 제거 (메모리 관리)
        asyncio.create_task(remove_after_delay(client_msg_id, 300))
```

### 2. 이벤트 우선순위 정리
```python
# 개선된 로직
is_mention = event_type == "app_mention"
is_dm = event.get("channel_type") == "im"
is_thread = event.get("thread_ts") is not None

# 우선순위: app_mention > thread > dm
if is_mention:
    # 멘션은 항상 처리, 단 client_msg_id 중복 체크
    if not is_duplicate(event):
        process_message()
elif is_thread and event_type == "message":
    # 쓰레드 메시지 처리
    process_message()
elif is_dm and event_type == "message":
    # DM 처리
    process_message()
```

### 3. 자연어 명령어 지원
- IntentAnalyzer 활성화로 "검색해줘" → `/search` 변환
- 슬래시 명령어 대신 자연어 사용 유도

## 교훈
1. **Event Subscriptions 이해**: 하나의 메시지가 여러 이벤트 생성 가능
2. **중복 처리 필수**: client_msg_id 또는 timestamp로 중복 방지
3. **Slack 기본 명령어 회피**: 커스텀 명령어는 `/rb-*` 형식 권장