docs: NaverWorks-Slack 연동 구현 완료 문서 업데이트

- 코드 분석 결과 반영 (51124 서버 확인)
- 구현 결정 사항 정리 (6가지 핵심 결정)
- 우선순위별 구현 체크리스트 (P0, P1, P2)
- 실제 데이터 흐름 15단계 상세 기록

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
happybell80 2025-09-20 00:18:26 +09:00
parent d01e35452e
commit 6bd22f0a3f

View File

@ -1,9 +1,9 @@
# NAVER WORKS → Slack 연동 [1/3] 기본 구성 # NAVER WORKS → Slack 연동 [1/3] 기본 구성
## 날짜: 2025-09-19 ## 날짜: 2025-09-19 (수정: 2025-01-09)
## 작성자: Claude (51123 서버 관리자) ## 작성자: Claude (51123 서버 관리자) / happybell80
## 관련 서비스: rb8001, skill-email, auth-server ## 관련 서비스: rb8001, skill-email, skill-slack, auth-server
## 상태: 기본 구조 구현 필요 ## 상태: 기본 구조 부분 구현
## 관련 문서 ## 관련 문서
- [2/3 일일 브리핑](./250919_naverworks_slack_02_daily_briefing.md) - [2/3 일일 브리핑](./250919_naverworks_slack_02_daily_briefing.md)
@ -11,8 +11,7 @@
--- ---
## 1. 현재 구현 상태 (2025-01-09 확인)
## 1. 현재 구현 상태 (코드 분석 기준)
### 구현 완료 ### 구현 완료
- **auth-server**: - **auth-server**:
@ -24,16 +23,19 @@
- GET `/messages` 엔드포인트 (provider 파라미터 지원) - GET `/messages` 엔드포인트 (provider 파라미터 지원)
- POST `/send` 엔드포인트 - POST `/send` 엔드포인트
- registry.register("naverworks", NaverWorksProvider()) 등록됨 - registry.register("naverworks", NaverWorksProvider()) 등록됨
- **skill-slack (포트 8502)**:
- POST `/api/v1/send` 토큰 파라미터 지원 (2025-01-09)
- 멀티 워크스페이스 지원 가능
- **NAVER WORKS Mail API**: - **NAVER WORKS Mail API**:
- ✅ 올바른 엔드포인트 확인: `/mail/mailfolders/{folderId}/children` - ✅ 올바른 엔드포인트 확인: `/mail/mailfolders/{folderId}/children`
- ✅ mailAddress null 문제 해결 (API 사용에 영향 없음) - ✅ mailAddress null 문제 해결 (API 사용에 영향 없음)
- ✅ 9,192개 메일 정상 조회 확인 - ✅ 9,192개 메일 정상 조회 확인
### 미구현/불일치 ### 미구현/문제점
- **rb8001**: provider=naverworks 미지정 → 기본 Gmail만 사용 - **rb8001**: provider 파라미터 없음, UUID 변환 누락 (list 경로)
- **skill-email**: `/mail-summary` 엔드포인트 없음 (문서에만 제안) - **skill-slack**: rb8001과 미연동 (직접 WebClient 사용)
- **식별자**: Slack ID → UUID 변환이 send에만 부분 적용 - **24시간 필터**: 어디에도 구현 안 됨
- **보안 위험**: NaverWorksProvider.DEFAULT_USER_ID 하드코딩 존재 - **토큰 갱신**: 자동 호출 없음 (수동 함수만 존재)
### 잘못된 전제 정정 ### 잘못된 전제 정정
- ❌ "skill-naverworks(8511) 구현 완료" → ✅ skill-email(8501) 멀티 프로바이더로 통합 - ❌ "skill-naverworks(8511) 구현 완료" → ✅ skill-email(8501) 멀티 프로바이더로 통합
@ -64,186 +66,149 @@
--- ---
## 3. 오케스트레이션 구조와 skill-slack 통합 ## 3. 정확한 구현 경로
### 3.1 rb8001 오케스트레이션 흐름 ### 3.1 전체 데이터 흐름 (토큰 갱신 포함)
```
Slack 요청 → rb8001 (중앙 오케스트레이터) **시나리오**: 슬랙에서 "네이버웍스 메일 확인" 메시지를 보내면 최근 24시간 이내 받은 메일 전체가 슬랙 채널에 표시
├→ skill-email (메일 데이터 조회)
├→ 필터링/분석 (rb8001 내부) **상세 흐름**:
├→ skill-slack (Slack 포맷팅) 1. 슬랙 "네이버웍스 메일 확인" → Gateway
└→ Slack 응답 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": "네이버웍스 메일 확인"
}
}
``` ```
**rb8001의 역할:** **프론트엔드 요청 경로**:
- 사용자 의도 파악
- 스킬 조합 결정
- 데이터 가공 및 필터링
- 최종 응답 전송
### 3.2 skill-slack 현재 구조 및 추가 역할
**실제 파일 구조 (포트 8502):**
``` ```
skill-slack/ Frontend → Gateway → rb8001 → skill-email → rb8001 → skill-slack → Slack
├── app/
│ ├── main.py # FastAPI 앱, API 버전 설정
│ ├── api/
│ │ └── endpoints/
│ │ ├── messages.py # /messages/send, /messages/update
│ │ ├── summarize.py # /summarize
│ │ └── digest.py # /digest
│ ├── services/
│ │ ├── slack_service.py # SlackService 클래스
│ │ ├── message_formatter.py # 메시지 포맷 헬퍼
│ │ └── summarize_service.py # 요약 서비스
│ ├── models/
│ │ └── slack_models.py # BaseSkillRequest 등 Pydantic 모델
│ └── core/
│ └── config.py # Settings 설정
``` ```
**기존 엔드포인트 (모두 `/api/v1` prefix):** Gateway → rb8001 전달 정보:
| 엔드포인트 | 역할 | 현재 상태 | Request Body | - Headers: `X-User-Id`, `X-Source`: "frontend"
|-----------|------|-----------|--------------| - Body: `{"text": "메시지", "user_id": "UUID", "context": {}}`
| POST `/api/v1/messages/send` | Slack 메시지 전송 | ✅ 구현됨 | BaseSkillRequest + message |
| POST `/api/v1/messages/update` | 메시지 업데이트 | ✅ 구현됨 | BaseSkillRequest + ts + message |
| POST `/api/v1/summarize` | 대화 요약 | ✅ 구현됨 | BaseSkillRequest + messages |
| POST `/api/v1/digest` | 스레드 다이제스트 | ✅ 구현됨 | BaseSkillRequest + thread_ts |
**BaseSkillRequest 구조:** ### 3.2 현재 사용 가능한 엔드포인트
```python
class BaseSkillRequest(BaseModel):
team_id: str
user_id: str
channel_id: str
thread_ts: Optional[str] = None
```
**추가 필요 엔드포인트:** **skill-email (포트 8501)**:
| 엔드포인트 | 역할 | 입력 | 출력 | - GET `/messages?provider=naverworks&user_id={uuid}` - 메일 목록 조회
|-----------|------|------|------| - POST `/send` - 메일 발송 (provider 필드 포함)
| POST `/api/v1/format/mail-list` | 메일 목록을 Slack 블록으로 변환 | BaseSkillRequest + mails | Block Kit JSON |
| POST `/api/v1/format/cold-mail` | 콜드메일 테이블 포맷 생성 | BaseSkillRequest + cold_mails | Table Block |
| POST `/api/v1/format/briefing` | 일일 브리핑 포맷 생성 | BaseSkillRequest + briefing_data | Briefing Block |
### 3.3 skill-email 파일별 역할 (최소 변경 원칙) **skill-slack (포트 8502)**:
| 파일 경로 | 역할 | 구현 내용 | 예상 코드 줄 수 | - POST `/api/v1/send` - Slack 메시지 전송
|-----------|------|-----------|----------------| - 필수: channel, text
| `main.py` | 앱 실행, 라우터 등록 | 기존 엔드포인트 유지, 새 라우터만 추가 | +5줄 추가 | - 선택: token, thread_ts, blocks
| `routers/naverworks_mail.py` (신규) | HTTP 요청 처리 | `/cold-mail-list`, `/daily-briefing` 엔드포인트 | 30-40줄 |
| `services/naverworks_mail_service.py` (신규) | 비즈니스 로직 | 콜드메일 필터링, 브리핑 생성 로직 | 100-150줄 |
| `services/naverworks_provider.py` | NAVER WORKS API 연동 | 기존 파일 활용, 메서드만 추가 | +50줄 추가 |
| `repositories/mail_cache_repository.py` (신규) | DB CRUD 작업 | 메일 캐시 저장/조회 SQL | 50-60줄 |
| `models/mail_cache.py` (신규) | DB 테이블 정의 | SQLAlchemy ORM 모델 (mail_cache 테이블) | 15-20줄 |
| `schemas/naverworks_schemas.py` (신규) | API 입출력 형식 | Pydantic 모델 (Request/Response) | 30-40줄 |
| `core/slack_formatter.py` (신규) | Slack 포맷터 | 메일→Slack 블록 변환 | 50-70줄 |
### 3.4 데이터 계층 구분 ### 3.3 수정 필요 위치
| 계층 | 파일 종류 | 역할 | 비유 |
|------|-----------|------|------|
| **Model** | `models/*.py` | DB 테이블 구조 정의 (SQLAlchemy ORM) | 창고 선반 설계도 (내부용) |
| **Schema** | `schemas/*.py` | API 요청/응답 형식 (Pydantic) | 손님 주문서 양식 (외부용) |
| **Repository** | `repositories/*.py` | DB 접근 로직 (CRUD) | 창고 관리 직원 |
| **Database** | `db/session.py` | DB 연결 관리 | 창고 출입문 열쇠 |
#### 데이터 흐름 예시 **rb8001/app/skills/email_integration.py**:
``` - 262행: GET `/messages` 호출 시 provider 파라미터 누락
1. API 요청 → Schema (검증) - 현재 코드: `params={"user_id": user_id, "limit": 5}` (Gmail만 조회)
2. Service → Repository (DB 작업 요청) - 필요한 수정: provider=naverworks 파라미터 추가
3. Repository → Model (ORM으로 DB 테이블 접근)
4. Model → Database (실제 SQL 실행)
5. 결과 → Schema (응답 포맷) → API 응답
```
### 3.5 rb8001 파일별 역할 **rb8001/app/router/slack_handler.py**:
| 파일 경로 | 역할 | 구현 내용 | - 274행: `local_client.chat_postMessage()` 직접 호출
|-----------|------|-----------| - 311행: `WebClient(token=custom_token)` 직접 생성
| `app/main.py` | 메시지 라우팅 | Slack 메시지 수신 및 처리 | - skill-slack 사용 안 함
| `app/skills/email_integration.py` | 이메일 스킬 통합 | NaverWorks 지원 추가 |
| `app/services/scheduler.py` | 스케줄러 | 일일 브리핑 자동 실행 | **robeing-gateway/app/main.py**:
| `app/schemas/skill_schemas.py` | 스킬 요청/응답 형식 | SkillRequest, SkillResponse | - 553, 560, 611, 615행: X-User-Id, X-Slack-Bot-Token 헤더 설정
- X-Source 헤더 없음 (요청 출처 구분 불가)
### 3.6 auth-server 파일별 역할
| 파일 경로 | 역할 | 현재 상태 |
|-----------|------|-----------|
| `app/providers/naverworks.py` | OAuth 로그인 | ✅ 구현됨 |
| `app/providers/naverworks_passport.py` | Passport 시스템 | ✅ 구현됨 |
--- ---
## 4. 기본 연동 테스트 시나리오 ## 4. 확인된 사실과 구현 체크리스트
### 4.1 자동 Provider 감지 테스트 (skill-slack 포함) ### 코드 분석 결과 (2025-01-09)
- Slack: "@로빙 메일 확인" - **skill-slack**: 8502 포트 엔드포인트 구현됨, rb8001은 직접 WebClient 사용 중 (미연동)
- rb8001 흐름: - **provider 구분**: 미구현, 기본 Gmail만 동작 (rb8001/app/skills/email_integration.py:260-266)
1. DB 조회 (gmail_token, naverworks_token) - **24시간 필터**: 미구현, orderBy만 있음 (skill-email/services/naverworks_provider.py:167)
2. provider 자동 결정 - NaverWorks API는 searchDateType, startSearchDate, endSearchDate 파라미터 지원
3. skill-email 호출 → 메일 데이터 획득 - **토큰 갱신**: NaverWorks는 auth-server 위임, 자동 호출 없음
4. skill-slack `/format-mail-list` → Slack 블록 생성 - **UUID 변환**: list 경로에서 변환 없음 (263행 user_id는 입력 그대로 전달)
5. Slack 응답
### 4.2 명시적 Provider 지정 ### 필수 수정 사항 (우선순위별)
- Slack: "@로빙 네이버웍스 메일 확인" **P0 (즉시)**:
- DB 조회 없이 바로 provider=naverworks 사용 - [ ] skill-slack thread_ts 버그 수정 (messages.py:29-33)
- 오버라이드로 특정 provider 강제 지정 - [ ] skill-slack API Key 인증 추가 (messages 엔드포인트)
**P1 (1주)**:
- [ ] Gateway UUID 변환 완전 처리
- [ ] rb8001 provider 로직: 키워드→DB조회→질문
- [ ] skill-email 24시간 필터 (API 파라미터)
- [ ] skill-email DEFAULT_USER_ID 제거 (31행)
- [ ] skill-email 401 에러 시 토큰 갱신
**P2 (점진적)**:
- [ ] 새 기능만 skill-slack 사용
- [ ] 기존 코드 부분 전환
### 4.3 DB 조회 로직 구현
- rb8001/app/skills/email_integration.py에 detect_email_provider 메서드 추가
- gmail_token 테이블에서 is_equipped=true인 계정 확인
- naverworks_token 테이블에서 사용자 계정 확인
- 둘 다 있으면 "both", 하나만 있으면 해당 provider, 없으면 "none" 반환
--- ---
## 5. 기본 구성 구현 체크리스트 ## 5. 주요 파일 위치와 역할
### 5.1 rb8001 수정 ### rb8001 (포트 8001)
- [ ] `app/skills/email_integration.py` 수정 - **app/skills/email_integration.py**: Gmail 스킬 통합 (네이버웍스 추가 필요)
- [ ] `detect_email_provider()` 함수 추가 - DB 기반 자동 감지 - **app/router/slack_handler.py**: Slack 이벤트 처리 (현재 직접 호출)
- [ ] get_messages()에 자동 provider 선택 로직
- [ ] send_email()에 자동 provider 선택 로직
- [ ] 둘 다 있을 때 선택 UI 구현
- [ ] DB 조회 로직 구현
- [ ] gmail_token 테이블 조회
- [ ] naverworks_token 테이블 조회
- [ ] 결과 기반 provider 자동 결정
- [ ] Slack ID → UUID 변환 일관성 확보
- [ ] get_uuid_from_slack() 활용 확대
- [ ] 모든 skill-email 호출에 UUID 사용
### 5.2 skill-slack 구현 ### skill-email (포트 8501)
- [ ] 새 엔드포인트 추가 (`/api/v1` prefix 필수) - **services/naverworks_provider.py**: 네이버웍스 Provider 구현
- [ ] POST `/api/v1/format/mail-list` - 기본 메일 목록 포맷 - 270행: refresh_token() 함수 존재 (auth-server의 `/auth/naverworks/passport/refresh` 호출)
- [ ] POST `/api/v1/format/cold-mail` - 콜드메일 테이블 포맷 - 150행: list_messages() - 토큰 만료 체크 없이 바로 사용
- [ ] POST `/api/v1/format/briefing` - 일일 브리핑 포맷 - 31행: DEFAULT_USER_ID 하드코딩 문제
- [ ] BaseSkillRequest 상속 모델 구현 - **main.py**: 엔드포인트 정의
- [ ] MailListRequest(BaseSkillRequest) - 210행: GET `/messages` - provider 파라미터로 gmail/naverworks 분기
- [ ] ColdMailRequest(BaseSkillRequest) - POST `/send`
- [ ] BriefingRequest(BaseSkillRequest) - **services/gmail_service.py**
- [ ] Slack Block Kit Builder 구현 - 60-72행: 토큰 자동 갱신 구현 (creds.expired 체크 후 refresh)
- [ ] Section blocks
- [ ] Divider blocks ### skill-slack (포트 8502)
- [ ] Context blocks - **app/api/endpoints/messages.py**: 메시지 전송 엔드포인트
- **app/models/requests.py**: SlackMessageRequest 모델 (token 필드 포함)
### 5.3 skill-email 수정
- [ ] `services/naverworks_provider.py` 수정
- [ ] DEFAULT_USER_ID 하드코딩 제거
- [ ] account_id 없을 시 명확한 에러 처리
- [ ] 에러 응답 표준화
- [ ] 400: 잘못된 요청
- [ ] 422: 필수 정보 누락
--- ---
## 6. 환경 설정 및 주의사항 ## 6. 결정 사항 (2025-01-09)
### 6.1 환경 설정 확인 ### 구현 결정
- skill-email .env 파일에 NAVER WORKS 관련 설정 확인 1. **Provider 선택**: 키워드 우선 → DB 조회 → 둘 다 있으면 질문
- rb8001에서 skill-email 호출 시 포트 8501 사용 2. **24시간 필터**: skill-email에서 API 파라미터 처리 (startSearchDate, endSearchDate)
- auth-server의 NAVER WORKS OAuth 설정 확인 3. **토큰 갱신**: 401 에러 후 재시도 (1회)
4. **UUID 변환**: Gateway에서 모두 변환
5. **skill-slack 전환**: 단계적 (새 기능부터)
6. **메일 표시**: 5개 요약 + "더보기" 버튼
### 6.2 보안 주의사항
- **계정 오매핑 방지**: DEFAULT_USER_ID 제거로 잘못된 계정 접근 차단
- **UUID 검증**: 모든 사용자 식별자를 UUID로 표준화
- **에러 처리**: 명확한 HTTP 상태 코드로 문제 진단 용이