--- type: workflow tags: [workflow, coldmail, langgraph, scheduler, ir-deck] last_updated: 2026-04-06 --- # coldmail_ir_notification_sync 워크플로우 ## 목적 콜드메일을 자동 감지하여 IR 자료 포함 여부를 판별하고, Slack에 요약 알림을 게시한다. 신뢰도에 따라 자동 등록 또는 사용자 확인을 거친다. ## 현행 아키텍처 - **스케줄러**: APScheduler DB 기반 cron (`coldmail_briefing` 잡) - **워크플로우 엔진**: LangGraph StateGraph + AsyncSqliteSaver 체크포인트 - **Slack 전송**: `skill-slack` 서비스 HTTP 호출 (`SKILL_SLACK_URL` 환경변수) n8n은 사용하지 않는다. ## 흐름 ``` APScheduler cron (평일 09:05) → coldmail_briefing.py._run_coldmail_briefing() → briefing_window 계산 (월요일 72h, 화~금 24h) → LangGraph 워크플로우 실행: fetch → filter → process → wait_confirmation (interrupt) → confirm → send → END ``` ## 단계별 상세 ### 1. 스케줄러 트리거 | 항목 | 내용 | |------|------| | 코드 | `app/scheduler/jobs/coldmail_briefing.py` | | 설정 | `settings.COLDMAIL_BRIEFING_ENABLED`, `settings.COLDMAIL_BRIEFING_SCHEDULE` | | 스케줄 | cron 표현식 → APScheduler 형식으로 변환 | | 사용자 | `settings.NAVERWORKS_COMPANY_EMAIL` → UUID 조회 | ### 2. LangGraph 워크플로우 | 항목 | 내용 | |------|------| | 코드 | `app/services/workflows/coldmail_workflow.py` | | 상태 | `ColdmailState` TypedDict (emails, coldmail_candidates, processed_results, waiting_confirmation 등) | | 체크포인트 | `AsyncSqliteSaver` (`settings.LANGGRAPH_STATE_DIR` / `settings.LANGGRAPH_SQLITE_FILE`) | | thread_id | `coldmail:{user_id}:{date}` | ### 3. 노드 ��명 | 노드 | 함수 | 역할 | |------|------|------| | fetch | `fetch_node` | `coldmail_email_fetcher.fetch_emails()` 호출. 사전 주입 이메일이 있으면 그대로 사용 | | filter | `filter_node` | `coldmail_hybrid_filter.hybrid_coldmail_filter()` — 하이브리드 필터(첨부파일+본문) 적용 | | process | `process_node` | 신뢰도 95% 이상 자동 처리, 미만은 `waiting_confirmation`에 추가 | | wait_confirmation | `wait_confirmation_node` | `interrupt()` 호출하여 워크플로우 일시정지. 사용자 확인/거부 대기 | | confirm | `confirm_node` | 확인된 이메일을 리스트에 등록하고 로딩 메시지 업데이트 | | send | `send_node` | Slack 채널에 처리 결과 요약 전송 | ### 4. 조건부 라우팅 | 분기점 | 조건 | 다음 노드 | |--------|------|-----------| | filter 후 | coldmail_candidates 있음 | process | | filter 후 | coldmail_candidates 없음 | END | | wait_confirmation 후 | confirmed_email_id 있음 | confirm | | wait_confirmation 후 | waiting_confirmation 남음 | wait_confirmation (루프) | | wait_confirmation 후 | 둘 다 없음 | send | | confirm 후 | waiting_confirmation 남음 | wait_confirmation | | confirm 후 | 없음 | send | ## 엔드포인트 - **인바운드**: 없음 (스케줄러가 내부 직접 호출) - **아웃바운드**: `POST {SKILL_SLACK_URL}/api/v1/send` — Slack 요약 전송 - **아웃바운드**: `POST {SKILL_SLACK_URL}/api/v1/update` — 로딩 메시지 업데이트 ## 환경변수 | 변수 | 용도 | |------|------| | `COLDMAIL_CHANNEL_ID` | Slack 알림 채널 | | `SKILL_SLACK_URL` | skill-slack 서비스 URL | | `SKILL_SLACK_API_KEY` / `SERVICE_API_KEY` | skill-slack 인증 | | `NAVERWORKS_COMPANY_EMAIL` | 이메일 조회 대상 사용자 | | `LANGGRAPH_STATE_DIR` | 체크포인트 DB 디렉터리 | | `LANGGRAPH_SQLITE_FILE` | 체크포인트 DB 파일명 | ## 관련 문서 - [message_flow_v2.md](./message_flow_v2.md) — 대화 처리 흐름 (v2) - [skill-slack SKILL.md](/home/admin/robeing/DOCS/skills/skill-slack/SKILL.md) — Slack 스킬 계약