docs: 콜드메일 자동 감지 시스템 구현 완료 상태로 업데이트

- 상태: 계획 → 구현 완료
- skill-email: 메일 상세 조회, 첨부파일 다운로드 구현 사실 기록
- rb8001: 6개 서비스 + 스케줄러 구현 사실 기록 (커밋 해시 포함)
- 환경변수: COLDMAIL_BRIEFING_ENABLED, COLDMAIL_CHANNEL_ID, SLACK_LIST_ID, NAVERWORKS_COMPANY_EMAIL 설정 완료
- 구현된 처리 흐름 10단계 기록
- 테스트 실행 방법 추가
- 의사코드, 예측, 민감정보 제거

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
happybell80 2025-10-01 00:07:14 +09:00
parent d533219b4d
commit 3d87ef8c28

View File

@ -2,7 +2,7 @@
## 날짜: 2025-09-30 ## 날짜: 2025-09-30
## 작성자: Claude (로컬 개발자) ## 작성자: Claude (로컬 개발자)
## 상태: 계획 ## 상태: 구현 완료
## 목표 ## 목표
NAVER WORKS 메일 중 투자 제안(콜드메일) 수신 시: NAVER WORKS 메일 중 투자 제안(콜드메일) 수신 시:
@ -13,20 +13,26 @@ NAVER WORKS 메일 중 투자 제안(콜드메일) 수신 시:
--- ---
## 현재 상태 (2025-09-30 코드 확인) ## 구현 완료 (2025-09-30)
### 구현 완료 ### skill-email (커밋: a535732)
- skill-email: `list_messages` (naverworks_provider.py:152), `get_message` (naverworks_provider.py:288), 토큰 갱신 (naverworks_provider.py:356) - GET /messages/{message_id}: routers/mail_detail_router.py 생성, main.py:311-312 등록
- skill-rag-file: POST /api/upload (upload.py:29), 포트 8508, PDF/DOCX/DOC/TXT/MD 지원 (config.py:33) - GET /messages/{message_id}/attachments/{attachment_id}: routers/mail_detail_router.py
- rb8001: Slack 파일 → skill-rag-file 전송 (slack_handler.py:52-147, 비동기 병렬) - download_attachment 메서드: services/naverworks_provider.py:357-388
- rb8001: NAVER WORKS 일일 브리핑 (naverworks_briefing.py:36-256, 긴급/계약/결제 키워드) - attachments 필드 추가: services/naverworks_provider.py:326
### 미구현 (코드 확인) ### rb8001 (커밋: 19304ea, 1980a4e, d88615e)
- ~~skill-email: `download_attachment` 메서드 없음~~ → 구현 완료 - app/services/coldmail_filter.py: Incremental Naive Bayes 필터, initialize_seed_data(), is_coldmail(), update_classifier()
- rb8001: 콜드메일(투자/IR) 필터 로직 없음 (현재는 일반 중요 키워드만) → 구현 완료 - app/services/naverworks_file_processor.py: download_naverworks_attachment(), upload_to_rag_file(), process_naverworks_attachments()
- ~~rb8001: NAVER WORKS 첨부파일 다운로드→rag-file 경로 없음~~ → 구현 완료 - app/services/ir_analyzer.py: extract_ir_metrics(), query_rag(), call_llm()
- skill-slack: Slack 메시지 전송 API 존재 (POST /api/v1/send, messages.py:19), rb8001에서 HTTP로 호출 - app/services/startup_valuation.py: valuate_startup(), get_prior_by_stage(), calculate_posterior(), save_valuation()
- **Slack Lists API**: lists:write, lists:read 스코프 설정 완료, 구현 필요 - app/services/slack_lists_client.py: create_list_item(), update_list_item(), create_coldmail_list_item(), update_ir_feedback()
- app/scheduler/jobs/coldmail_briefing.py: _run_coldmail_briefing(), register() (cron: 5 9 * * mon-fri)
- main.py:197-198: coldmail_briefing.register(scheduler)
- app/skills/naverworks_briefing.py:17: NAVERWORKS_COMPANY_EMAIL 환경변수 사용, 하드코딩 제거
- app/state/database.py:118-147: get_naverworks_user_uuid() 함수 (이미 존재)
- tests/test_coldmail_briefing.py: 9개 테스트 함수
- Dockerfile:30: COPY ./tests /code/tests 추가
### API 스펙 확인 완료 (2025-09-30) ### API 스펙 확인 완료 (2025-09-30)
@ -52,63 +58,51 @@ NAVER WORKS 메일 중 투자 제안(콜드메일) 수신 시:
**구현 가능성**: 100% (API 스펙 및 실제 응답 구조 검증 완료) **구현 가능성**: 100% (API 스펙 및 실제 응답 구조 검증 완료)
### 환경 설정 확인 (2025-09-30) ### 환경 설정 완료 (2025-09-30, 51124 서버)
- **Slack 워크스페이스**: 유료 플랜 (Lists API 제약 없음) - **DB 테이블**: coldmail_classifier, startup_valuation (51123 서버)
- **DB 테이블 생성 완료** (51123 서버): - **환경변수** (rb8001 .env):
- `coldmail_classifier`: word VARCHAR, coldmail_count INT, normal_count INT - COLDMAIL_BRIEFING_ENABLED=true
- `startup_valuation`: team_id UUID FK, startup_name VARCHAR, valuation_median NUMERIC, valuation_lower NUMERIC, valuation_upper NUMERIC, confidence FLOAT, metadata JSONB - COLDMAIL_BRIEFING_SCHEDULE=5 9 * * mon-fri
- **환경변수**: `COLDMAIL_CHANNEL_ID` (51124 서버 rb8001 .env) - COLDMAIL_CHANNEL_ID=C09HR9BMT51
- **구현 범위**: 전체 13단계 구현 - SLACK_LIST_ID=F09J1HPPQJG
- NAVERWORKS_COMPANY_EMAIL (하드코딩 제거됨)
- **Slack 앱 스코프**: lists:write, lists:read, files:read
- **배포**: docker-compose.yml env_file: .env (line 6-7), Dockerfile COPY ./tests (line 30)
--- ---
## 구현 계획 ## 구현된 처리 흐름
### 콜드메일 필터링 (Incremental Naive Bayes) ### 스케줄러 실행
1. **초기 Prior**: DB `coldmail_classifier` 테이블 (word, coldmail_count, normal_count), 도메인(`*.vc`: 0.9), 키워드(`투자`: 0.8) 시드 - 평일 9시 5분 (월요일: 72시간, 화~금: 24시간 조회)
2. **특징 추출**: 제목+발신자 도메인 → 토큰화 - coldmail_briefing.py:75-189
3. **확률 계산**: P(콜드메일|단어) = P(단어|콜드메일) × P(콜드메일) / P(단어), 임계값 > 0.7
4. **Slack 피드백**: "IR 맞음 ✅" / "아님 ❌" 버튼, 클릭 시 DB 카운터 업데이트
5. **Prior 갱신**: 평일 9시 5분 스케줄러, 피드백 반영 후 재분류
6. **첨부파일 조건**: PDF 우선 처리
### 처리 흐름 ### 처리 단계
1. 평일 9시 5분 rb8001 스케줄러 (cron: `5 9 * * mon-fri`) → skill-email list_messages (월요일 72시간, 화~금 24시간) 1. NAVERWORKS_COMPANY_EMAIL → get_naverworks_user_uuid() → user_id 조회
2. 콜드메일 필터링 (rb8001, Naive Bayes), 첨부파일 있는 것만 2. skill-email GET /messages (startSearchDate, endSearchDate)
3. 첨부파일 다운로드 (NAVER WORKS API) → skill-rag-file 업로드 3. is_coldmail() 필터링 (Naive Bayes, coldmail_classifier 테이블)
4. **IR 파일 파싱** (skill-rag-file): PDF/DOCX → 텍스트 추출 → semantic chunking → 임베딩 → ChromaDB 저장 4. 첨부파일 있는 메일만 선택
5. **핵심 지표 추출** (rb8001, LLM + RAG): 사업 분야, 투자 단계, 매출, 성장률, 팀 구성, 기술 우위 5. skill-email GET /messages/{message_id} → attachments 정보
6. **가치 평가** (rb8001, Bayesian VC Method): 6. process_naverworks_attachments() → PDF만 선택 → skill-rag-file POST /api/upload
- Prior: 동일 업종/단계 평균 밸류에이션 (DB 조회) 7. extract_ir_metrics() → skill-rag-file RAG 쿼리 6회 → LLM 요약
- Likelihood: IR 지표 반영 (성장률, 특허, 시장점유율) 8. valuate_startup() → Bayesian VC Method (Prior × Likelihood = Posterior) → startup_valuation 테이블 저장
- Posterior: 밸류에이션 분포 계산 (중간값, 신뢰구간, 불확실성) 9. create_coldmail_list_item() → Slack Lists API (lists.items.create)
- DB 저장: `startup_valuation` 테이블 10. skill-slack POST /api/v1/send → 처리 완료 요약 메시지
7. **Slack Lists 생성/업데이트** (slackLists.items.create):
- 컬럼: 회사명, 담당자, 제안내용, 첨부파일, 밸류에이션, IR여부(피드백) ### Naive Bayes 학습 루프
- 피드백: slackLists.items.update로 업데이트 - initialize_seed_data(): *.vc 도메인, 투자/IR 키워드 시드
8. **학습 루프**: 피드백 수집 → Prior 업데이트 → 모델 개선 - update_classifier(): Slack 피드백 시 DB 카운터 업데이트 (현재 수동 호출)
--- ---
## 다음 단계 ## 테스트
### FastAPI 구조 원칙 ### 테스트 파일
- **main.py**: 앱 생성, 라우터 등록만 - tests/test_coldmail_briefing.py (9개 함수)
- **routers/**: 엔드포인트별 분리
- **services/**: 비즈니스 로직
- **settings.py**: 환경변수, URL 생성
### 구현 순서 ### 실행 방법
1. ~~**메일 상세 조회 API 테스트**~~: attachments 필드 확인 완료 - 51124 서버: docker exec -it rb8001 python tests/test_coldmail_briefing.py --test [db|filter|email|attachment|ir|valuation|lists|scheduler]
2. **Slack 앱 매니페스트 수정**: lists:write, lists:read, files:read 스코프 추가 → 앱 재설치 - 로컬: python tests/test_coldmail_briefing.py
3. skill-email: GET /messages/{message_id} 엔드포인트 추가 (main.py 라우팅)
4. skill-email: `download_attachment` 메서드 추가 (services/naverworks_provider.py, Base64 디코딩) ### 필수 환경변수
5. ~~PostgreSQL 테이블~~: `coldmail_classifier`, `startup_valuation` 생성 완료 (51123 서버) - COLDMAIL_BRIEFING_ENABLED, COLDMAIL_CHANNEL_ID, SLACK_LIST_ID, NAVERWORKS_COMPANY_EMAIL, SLACK_BOT_TOKEN, DATABASE_URL, SKILL_EMAIL_URL, SKILL_SLACK_URL, SKILL_RAG_FILE_URL
6. rb8001: Naive Bayes 필터 구현 (services/coldmail_filter.py, 도메인/키워드 시드)
7. rb8001: NAVER WORKS 첨부파일 처리 (services/naverworks_file_processor.py, slack_handler.py:52-147 참고)
8. rb8001: IR 지표 추출 (services/ir_analyzer.py, LLM + RAG)
9. rb8001: Bayesian 가치 평가 (services/startup_valuation.py, scipy.stats)
10. rb8001: Slack Lists 클라이언트 (services/slack_lists_client.py, slackLists API)
11. rb8001: 스케줄러 작업 등록 (scheduler/jobs/coldmail_briefing.py, cron: `5 9 * * mon-fri`)
12. rb8001: main.py에 스케줄러 작업만 등록
13. rb8001: .env에 `COLDMAIL_CHANNEL_ID` 사용