# NAVER WORKS → Slack 연동 [1/3] 기본 구성 ## 날짜: 2025-09-19 (완료: 2025-01-10) ## 작성자: Claude (51123 서버 관리자) / happybell80 ## 관련 서비스: rb8001, skill-email, skill-slack, auth-server, robeing-gateway ## 상태: ✅ 구현 완료 및 테스트 성공 ## 관련 문서 - [2/3 일일 브리핑](./250919_naverworks_slack_02_daily_briefing.md) - [3/3 콜드메일 리스트업](./250919_naverworks_slack_03_cold_mail_list.md) --- ## 1. 현재 구현 상태 (2025-01-09 확인) ### 구현 완료 - **auth-server**: - `naverworks.py`, `naverworks_passport.py` 파일 존재 - NAVER WORKS OAuth 환경변수 설정 (CLIENT_ID, CLIENT_SECRET, REDIRECT_URI, TENANT_ID) - 토큰 갱신: POST `/auth/naverworks/passport/refresh` 동작 - **skill-email (포트 8501)**: - `services/naverworks_provider.py` NaverWorksProvider 클래스 구현 - GET `/messages` 엔드포인트 (provider 파라미터 지원) - POST `/send` 엔드포인트 - registry.register("naverworks", NaverWorksProvider()) 등록됨 - **skill-slack (포트 8502)**: - POST `/api/v1/send` 토큰 파라미터 지원 (2025-01-09) - 멀티 워크스페이스 지원 가능 - **NAVER WORKS Mail API**: - ✅ 올바른 엔드포인트 확인: `/mail/mailfolders/{folderId}/children` - ✅ mailAddress null 문제 해결 (API 사용에 영향 없음) - ✅ 9,192개 메일 정상 조회 확인 ### 미구현/문제점 - **rb8001**: provider 파라미터 없음, UUID 변환 누락 (list 경로) - **skill-slack**: rb8001과 미연동 (직접 WebClient 사용) - **24시간 필터**: 어디에도 구현 안 됨 - **토큰 갱신**: 자동 호출 없음 (수동 함수만 존재) ### 잘못된 전제 정정 - ❌ "skill-naverworks(8511) 구현 완료" → ✅ skill-email(8501) 멀티 프로바이더로 통합 - ❌ "Service Account 설정 완료" → ✅ 사용자 OAuth 토큰 기반 (SA는 Phase 3 계획) - ❌ 별도 skill-naverworks 필요 → ✅ skill-email의 provider 파라미터로 처리 --- ## 2. 기본 구성 구현 사항 ### 2.1 rb8001 수정 - 자동 Provider 감지 - `app/skills/email_integration.py`에 DB 기반 자동 분기 로직 추가 - 사용자의 메일 계정을 DB에서 조회하여 자동 선택 - 분기 로직: ``` 1. DB에서 user_id로 메일 계정 조회 2. Gmail만 있음 → provider=gmail 3. NaverWorks만 있음 → provider=naverworks 4. 둘 다 있음 → 사용자에게 선택 요청 5. 둘 다 없음 → 메일 계정 설정 안내 ``` - 명시적 키워드("네이버웍스", "Gmail")는 오버라이드용 ### 2.2 skill-email 수정 - 안전성 개선 - NaverWorksProvider.DEFAULT_USER_ID 제거 - account_id 누락 시 400/422 에러 반환 - 모든 요청에 UUID 검증 로직 추가 --- ## 3. 정확한 구현 경로 ### 3.1 전체 데이터 흐름 (토큰 갱신 포함) **시나리오**: 슬랙에서 "네이버웍스 메일 확인" 메시지를 보내면 최근 24시간 이내 받은 메일 전체가 슬랙 채널에 표시 **상세 흐름**: 1. 슬랙 "네이버웍스 메일 확인" → Gateway 2. Gateway가 slack_user_mapping에서 UUID 조회 → X-User-Id 헤더 3. Gateway가 slack_workspace에서 봇 토큰 조회 → X-Slack-Bot-Token 헤더 4. Gateway가 X-Source: "slack" 헤더 추가 5. Gateway → rb8001 (헤더 + 메시지) 6. rb8001이 X-Source 확인 → slack 요청임을 인지 7. rb8001 → skill-email:8501/messages?provider=naverworks&user_id={uuid} 8. skill-email이 naverworks_token에서 액세스 토큰 조회 9. 토큰 만료 체크 → 만료시 auth-server:8000/auth/naverworks/passport/refresh 호출 10. auth-server가 naverworks_token 테이블 업데이트 → 새 토큰 반환 11. NaverWorks API 호출 → 24시간 이내 메일 전체 반환 12. rb8001이 메일 데이터를 슬랙 메시지 형식으로 포맷팅 (blocks, markdown) 13. rb8001 → skill-slack:8502/api/v1/send (channel, text, blocks, token) 14. skill-slack이 슬랙 API 형식에 맞게 최종 포맷팅 15. skill-slack → 슬랙 채널에 메일 표시 **Gateway → rb8001 전달 정보**: Headers: - `X-User-Id`: UUID (Slack user를 UUID로 변환) - `X-Slack-Bot-Token`: 봇 토큰 (Gateway가 DB에서 조회) - `X-Source`: "slack" (요청 출처 구분) - `X-Slack-Signature`: Slack 서명 - `X-Slack-Request-Timestamp`: 타임스탬프 Body (원본 그대로): ```json { "team": {"id": "T0925SXPS4D"}, "event": { "user": "U0928DT3MDW", "channel": "C07V9F3V21V", "text": "네이버웍스 메일 확인" } } ``` **프론트엔드 요청 경로**: ``` Frontend → Gateway → rb8001 → skill-email → rb8001 → skill-slack → Slack ``` Gateway → rb8001 전달 정보: - Headers: `X-User-Id`, `X-Source`: "frontend" - Body: `{"text": "메시지", "user_id": "UUID", "context": {}}` ### 3.2 현재 사용 가능한 엔드포인트 **skill-email (포트 8501)**: - GET `/messages?provider=naverworks&user_id={uuid}` - 메일 목록 조회 - POST `/send` - 메일 발송 (provider 필드 포함) **skill-slack (포트 8502)**: - POST `/api/v1/send` - Slack 메시지 전송 - 필수: channel, text - 선택: token, thread_ts, blocks ### 3.3 수정 필요 위치 **rb8001/app/skills/email_integration.py**: - 262행: GET `/messages` 호출 시 provider 파라미터 누락 - 현재 코드: `params={"user_id": user_id, "limit": 5}` (Gmail만 조회) - 필요한 수정: provider=naverworks 파라미터 추가 **rb8001/app/router/slack_handler.py**: - 274행: `local_client.chat_postMessage()` 직접 호출 - 311행: `WebClient(token=custom_token)` 직접 생성 - skill-slack 사용 안 함 **robeing-gateway/app/main.py**: - 553, 560, 611, 615행: X-User-Id, X-Slack-Bot-Token 헤더 설정 - X-Source 헤더 없음 (요청 출처 구분 불가) --- ## 4. 확인된 사실과 구현 체크리스트 ### 코드 분석 결과 (2025-01-09) - **skill-slack**: 8502 포트 엔드포인트 구현됨, rb8001은 직접 WebClient 사용 중 (미연동) - **provider 구분**: 미구현, 기본 Gmail만 동작 (rb8001/app/skills/email_integration.py:260-266) - **24시간 필터**: 미구현, orderBy만 있음 (skill-email/services/naverworks_provider.py:167) - NaverWorks API는 searchDateType, startSearchDate, endSearchDate 파라미터 지원 - **토큰 갱신**: NaverWorks는 auth-server 위임, 자동 호출 없음 - **UUID 변환**: list 경로에서 변환 없음 (263행 user_id는 입력 그대로 전달) ### 구현 완료 사항 (2025-01-10) **P0 (완료)**: - ✅ skill-slack thread_ts 버그 수정 (messages.py:36-48) - ✅ skill-slack API Key 인증 추가 (/send, /update) **P1 (완료)**: - ✅ Gateway X-Source 헤더 추가 (main.py:552, 240) - ✅ rb8001 provider 로직 구현 (email_integration.py:70-130) - ✅ skill-email 24시간 필터 (naverworks_provider.py:173-179) - ✅ skill-email DEFAULT_USER_ID 제거 (31행 삭제) - ✅ skill-email 401 에러 시 토큰 갱신 (194-210행) **P2 (완료)**: - ✅ send_naverworks_to_slack() 함수 구현 (email_integration.py:433-524) - ✅ slack_handler.py 키워드 연결 (213-228행) ### 테스트 결과 - ✅ "네이버웍스 메일 확인" 명령어 정상 작동 - ✅ 24시간 이내 메일 조회 성공 - ✅ 메일 없을 시 안내 메시지 표시 - ⚠️ 메일 있을 시 이중 전송 가능성 (send_naverworks_to_slack + slack_handler) - 📝 skill-slack은 메일이 있을 때만 호출됨 (없으면 직접 응답) --- ## 5. 주요 파일 위치와 역할 ### rb8001 (포트 8001) - **app/skills/email_integration.py**: Gmail 스킬 통합 (네이버웍스 추가 필요) - **app/router/slack_handler.py**: Slack 이벤트 처리 (현재 직접 호출) ### skill-email (포트 8501) - **services/naverworks_provider.py**: 네이버웍스 Provider 구현 - 270행: refresh_token() 함수 존재 (auth-server의 `/auth/naverworks/passport/refresh` 호출) - 150행: list_messages() - 토큰 만료 체크 없이 바로 사용 - 31행: DEFAULT_USER_ID 하드코딩 문제 - **main.py**: 엔드포인트 정의 - 210행: GET `/messages` - provider 파라미터로 gmail/naverworks 분기 - POST `/send` - **services/gmail_service.py** - 60-72행: 토큰 자동 갱신 구현 (creds.expired 체크 후 refresh) ### skill-slack (포트 8502) - **app/api/endpoints/messages.py**: 메시지 전송 엔드포인트 - **app/models/requests.py**: SlackMessageRequest 모델 (token 필드 포함) --- ## 6. 결정 사항 (2025-01-09) ### 구현 결정 1. **Provider 선택**: 키워드 우선 → DB 조회 → 둘 다 있으면 질문 2. **24시간 필터**: skill-email에서 API 파라미터 처리 (startSearchDate, endSearchDate) 3. **토큰 갱신**: 401 에러 후 재시도 (1회) 4. **UUID 변환**: Gateway에서 모두 변환 5. **skill-slack 전환**: 단계적 (새 기능부터) 6. **메일 표시**: 5개 요약 + "더보기" 버튼