DOCS/workflow/04_scheduler/scheduled_daily_briefing.md
happybell80 f078b28ced docs: 03_rag + 04_scheduler + 05_admin 워크플로우 현행화
03_rag:
- companyx_grounding_pipeline.md: 코드 SSOT 섹션 추가, 진입 조건 3단계(IC→마커 폴백) 정확히 기술, 환경변수 참조로 IP 하드코딩 제거
- companyx_incremental_indexing_workflow.md: frontmatter 표준 적용 (type, last_updated)
- rag_upload_indexing_pipeline.md: 코드 SSOT·재인덱싱·업로드 경로별 진입점 테이블 추가, 환경변수 참조

04_scheduler:
- scheduled_daily_briefing.md: n8n cron 전제 제거, APScheduler DB 기반 + LangGraph 워크플로우 기준 재작성
- scheduled_healthcheck_alert.md: n8n cron 전제 제거, /health 엔드포인트 + SKILL.md registry 기반 재작성
- scheduled_rag_reindex_retry.md: 현행 코드에 해당 잡 없음 → _archive 이동

05_admin:
- diary_reflection_pipeline.md: n8n 전제 제거, APScheduler + diary_generator.py 기준 재작성, /api/diary/generate(존재하지 않는 엔드포인트) 제거

Refs: DOCS#8

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 07:52:29 +09:00

63 lines
2.9 KiB
Markdown

---
tags: [workflow, scheduler, news, headlines, slack]
type: workflow
last_updated: 2026-04-06
---
# scheduled_daily_briefing 워크플로우
## 목적
DB에 등록된 스케줄에 따라 네이버 + 동남아 스타트업 헤드라인을 수집하여 Slack 채널에 자동 게시한다.
## 아키텍처
- **스케줄러**: APScheduler (DB 기반). `db_loader.py``scheduler_jobs` 테이블에서 `job_type=daily_headlines` 잡을 로드하여 등록.
- **실행 래퍼**: `app/scheduler/jobs/daily_headlines.py``_run_headlines_with_logging(channel_id)`.
- **실제 워크플로우**: `app/services/workflows/headlines_workflow.py` — LangGraph StateGraph로 구성.
- **n8n 미사용**. systemd로 rb8001이 직접 실행.
## 코드 SSOT
- `rb8001/app/scheduler/jobs/daily_headlines.py` — 스케줄러 잡 래퍼
- `rb8001/app/services/skills/startup_news_skill.py``run_headlines_job()` 진입점
- `rb8001/app/services/workflows/headlines_workflow.py` — LangGraph 워크플로우 본체
- `rb8001/app/scheduler/db_loader.py` — DB 잡 로더 (`JOB_TYPE_MAP["daily_headlines"]`)
## 흐름
```
APScheduler cron trigger
→ db_loader가 등록한 guarded_job (schedule_policy 평가)
→ _run_headlines_with_logging(channel_id)
→ run_headlines_job(channel_id)
→ run_headlines_workflow(channel_id) [LangGraph]
→ fetch_naver_node (SkillCommands.fetch_naver_headlines, fmt=slack)
→ fetch_sea_node (SkillCommands.fetch_sea_headlines, fmt=json)
→ format_node (네이버 텍스트에 동남아 섹션 삽입)
→ send_node (Slack chat.postMessage)
```
## 스케줄 정책
- cron 표현식은 `scheduler_jobs` DB 테이블에서 관리한다 (예: `10 9 * * 1-5`).
- `schedule_policy` 필드에 `workday` 정책이 설정되어 있으면 공휴일/주말을 건너뛴다 (`evaluate_schedule_policy()`).
- `channel_id``config.channel_id` DB 필드에서 전달받는다.
## 주요 노드 (LangGraph)
| 노드 | 함수 | 설명 |
|------|------|------|
| fetch_naver | `fetch_naver_node()` | `SkillCommands.fetch_naver_headlines(fmt="slack")` 호출 |
| fetch_sea | `fetch_sea_node()` | `SkillCommands.fetch_sea_headlines(fmt="json")` 호출 |
| format | `format_node()` | 네이버 헤드라인 텍스트 끝에 동남아 섹션 삽입 |
| send | `send_node()` | Slack `chat.postMessage` 전송 |
## Slack 봇 토큰 해소
- `_get_slack_bot_token_for_channel(channel_id)` → DB에서 채널별 workspace bot_token 조회.
- 실패 시 `settings.COMPANYX_SLACK_BOT_TOKEN``settings.SLACK_BOT_TOKEN` 순서로 폴백.
## 실패 분기
- 네이버 또는 동남아 API 호출 실패 시 `errors` 리스트에 기록하고 빈 텍스트로 진행.
- 보낼 텍스트가 비어 있으면 Slack 전송을 스킵하고 `message_ts=None`으로 종료.
- Slack 전송 실패 시 `errors`에 기록.
## 관련 문서
- [skill_news_briefing_request](../02_skills/skill_news_briefing_request.md)