142 lines
4.2 KiB
Markdown
142 lines
4.2 KiB
Markdown
# Slack User ID → 이름 매핑 문제 해결
|
|
|
|
## 문제점
|
|
rb8001에서 Slack 사용자 ID (예: U0925SXQFDK)를 실제 이름으로 변환하지 못함
|
|
|
|
## 현재 상태
|
|
1. **메모리 검색**: ✅ 정상 작동
|
|
- ChromaDB에 22개 메모리 저장됨
|
|
- search_memories() 함수 정상 작동
|
|
- 과거 대화 검색 가능
|
|
|
|
2. **사용자 이름 매핑**: ❌ 미구현 (ID 매핑은 slack_user_mapping 의존 제거, 2025-09-11)
|
|
- slack_user_mapping 테이블 없음
|
|
- Slack API를 통한 사용자 정보 조회 미구현
|
|
|
|
## 해결 방안
|
|
|
|
### 1. slack_user_mapping 테이블 생성
|
|
```sql
|
|
CREATE TABLE slack_user_mapping (
|
|
id SERIAL PRIMARY KEY,
|
|
slack_user_id VARCHAR(50) UNIQUE NOT NULL,
|
|
user_name VARCHAR(100),
|
|
display_name VARCHAR(100),
|
|
real_name VARCHAR(100),
|
|
email VARCHAR(100),
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
```
|
|
|
|
### 2. Slack API로 사용자 정보 가져오기
|
|
```python
|
|
from slack_sdk import WebClient
|
|
|
|
class SlackUserService:
|
|
def __init__(self, slack_token):
|
|
self.client = WebClient(token=slack_token)
|
|
|
|
async def get_user_info(self, user_id: str):
|
|
"""Slack API로 사용자 정보 조회"""
|
|
try:
|
|
response = self.client.users_info(user=user_id)
|
|
if response["ok"]:
|
|
user = response["user"]
|
|
return {
|
|
"slack_user_id": user_id,
|
|
"user_name": user.get("name"),
|
|
"display_name": user["profile"].get("display_name"),
|
|
"real_name": user["profile"].get("real_name"),
|
|
"email": user["profile"].get("email")
|
|
}
|
|
except Exception as e:
|
|
logger.error(f"Failed to get user info: {e}")
|
|
return None
|
|
```
|
|
|
|
### 3. 캐싱 전략
|
|
```python
|
|
class UserNameCache:
|
|
def __init__(self):
|
|
self.cache = {} # {user_id: user_info}
|
|
self.db = StateServiceClient()
|
|
|
|
async def get_user_name(self, user_id: str) -> str:
|
|
# 1. 캐시 확인
|
|
if user_id in self.cache:
|
|
return self.cache[user_id]["display_name"]
|
|
|
|
# 2. DB 확인
|
|
user_info = await self.db.get_user_mapping(user_id)
|
|
if user_info:
|
|
self.cache[user_id] = user_info
|
|
return user_info["display_name"]
|
|
|
|
# 3. Slack API 호출
|
|
slack_service = SlackUserService(settings.SLACK_BOT_TOKEN)
|
|
user_info = await slack_service.get_user_info(user_id)
|
|
|
|
if user_info:
|
|
# DB에 저장
|
|
await self.db.save_user_mapping(user_info)
|
|
self.cache[user_id] = user_info
|
|
return user_info["display_name"]
|
|
|
|
return user_id # 실패 시 ID 반환
|
|
```
|
|
|
|
### 4. 메시지 처리 시 이름 변환
|
|
```python
|
|
# slack_handler.py
|
|
async def handle_message(event):
|
|
user_id = event.get("user")
|
|
|
|
# 사용자 이름 가져오기
|
|
user_name = await user_name_cache.get_user_name(user_id)
|
|
|
|
# 메시지 처리
|
|
message = event.get("text")
|
|
logger.info(f"Message from {user_name} ({user_id}): {message}")
|
|
|
|
# 메모리 저장 시 이름 포함
|
|
await memory_manager.add_memory(
|
|
content=f"{user_name}: {message}",
|
|
metadata={
|
|
"user_id": user_id,
|
|
"user_name": user_name,
|
|
"channel_id": channel_id
|
|
}
|
|
)
|
|
```
|
|
|
|
## 구현 우선순위
|
|
1. **Phase 1**: 인메모리 캐시만 구현
|
|
- Slack API로 실시간 조회
|
|
- 메모리에 캐싱
|
|
|
|
2. **Phase 2**: DB 저장 추가
|
|
- PostgreSQL에 slack_user_mapping 테이블 생성
|
|
- 조회한 정보 영구 저장
|
|
|
|
3. **Phase 3**: 배치 업데이트
|
|
- 주기적으로 사용자 정보 갱신
|
|
- 변경사항 감지
|
|
|
|
## 테스트 시나리오
|
|
```python
|
|
# 1. 새로운 사용자 메시지
|
|
assert get_user_name("U0925SXQFDK") == "희재"
|
|
|
|
# 2. 캐시된 사용자
|
|
assert get_user_name("U0925SXQFDK") == "희재" # API 호출 없음
|
|
|
|
# 3. 알 수 없는 사용자
|
|
assert get_user_name("UNKNOWN") == "UNKNOWN"
|
|
```
|
|
|
|
## 참고 사항
|
|
- Slack API rate limit: 1분당 50회
|
|
- users.info API는 user:read 스코프 필요
|
|
- 사용자 정보는 변경될 수 있으므로 주기적 갱신 필요
|