Plan: 뉴스브리핑 LangGraph 전환 계획 추가

- 260202_뉴스브리핑_LangGraph_전환.md 생성 (311 원칙 준수)
- 260202_동남아_뉴스_수집_및_로그_개선.md → archive 이동 (완료)

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Claude-51124 2026-02-02 10:30:29 +09:00
parent 5a1fab4297
commit 23e43aa993
3 changed files with 478 additions and 345 deletions

View File

@ -0,0 +1,88 @@
# 뉴스 브리핑 LangGraph 워크플로우 전환
**날짜**: 2026-02-02
**작성자**: Claude
**관련 파일**: `rb8001/app/services/skills/startup_news_skill.py`, `skill_news/app/services/sea_news_collector.py`
**원칙 참조**: `311_백엔드_구조_원칙.md` (섹션 5: LangGraph 워크플로우)
---
## 1. 현재 문제
- **원칙 위반**: 뉴스 브리핑은 수집→필터→번역→포맷→전송 다단계 처리인데, 일반 함수로 구현되어 있음. 311 원칙 "복잡한 다단계 처리는 LangGraph 적극 활용" 위반.
- **추적성 부족**: 각 단계별 실패 지점, 중간 상태, 실행 시간 등이 로그에 체계적으로 남지 않음.
- **복구 불가**: 중간 단계 실패 시 처음부터 재실행해야 함 (체크포인트 없음).
---
## 2. LangGraph 전환 설계
### 2.1 상태 모델 (HeadlinesState)
```python
class HeadlinesState(TypedDict):
channel_id: str
naver_items: List[Dict] # 깡프로 헤드라인
sea_items: List[Dict] # 동남아 뉴스
terms: Optional[List[str]] # 추출된 용어
formatted_text: str # 최종 Slack 텍스트
message_ts: Optional[str] # 전송된 메시지 ts
errors: List[str] # 각 단계 에러
```
### 2.2 노드 구성
1. **fetch_naver_node**: skill-news API 호출 → `naver_items` 반환
2. **fetch_sea_node**: skill-news SEA API 호출 → `sea_items` 반환 (실패 시 빈 리스트, 에러 기록)
3. **extract_terms_node**: Gemini로 용어 추출 → `terms` 반환 (환경변수 체크)
4. **format_node**: 깡프로 + 동남아 + 용어 섹션 조합 → `formatted_text` 반환
5. **send_node**: Slack 전송 → `message_ts` 반환 및 로그 기록
### 2.3 라우팅
```
START → fetch_naver → fetch_sea → extract_terms → format → send → END
```
- `fetch_sea` 실패 시에도 계속 진행 (graceful degradation)
- `extract_terms` 환경변수 false면 skip
- 각 노드 실패는 `errors` 리스트에 기록
### 2.4 체크포인터
- **AsyncSqliteSaver** 사용 (경량 워크플로우, 서버 재시작 시 재개 불필요)
- DB 경로: `/code/checkpoints/headlines_workflow.db`
- thread_id: `f"headlines_{channel_id}_{date}"`
---
## 3. Phase별 작업
### Phase 1: 워크플로우 파일 생성
- **파일**: `rb8001/app/services/workflows/headlines_workflow.py` (신규)
- **내용**: HeadlinesState, 5개 노드, StateGraph 정의
### Phase 2: startup_news_skill.py 리팩토링
- **기존**: `run_headlines_job()` 함수 → **변경**: LangGraph 워크플로우 호출
- **로그**: 각 노드별 실행 로그 + 최종 message_ts 로그
### Phase 3: TDD 테스트
- **파일**: `rb8001/tests/test_headlines_workflow.py` (신규)
- **시나리오**:
- 정상 플로우 (깡프로 + 동남아 + 용어)
- 동남아 실패 시 graceful degradation
- 용어 추출 skip
- message_ts 로그 확인
### Phase 4: 배포 및 검증
- **배포**: `git push origin main` (rb8001) → Gitea Actions 자동 배포
- **검증**: 내일 아침 09:10 스케줄 실행 시 로그에 노드별 실행 + message_ts 확인
---
## 4. 남은 작업
- [ ] `headlines_workflow.py` 생성 (LangGraph StateGraph)
- [ ] `startup_news_skill.py` 리팩토링 (워크플로우 호출)
- [ ] `test_headlines_workflow.py` 작성 (TDD)
- [ ] 배포 및 스케줄 실행 검증

View File

@ -0,0 +1,45 @@
# 동남아 뉴스 수집 복구 및 메시지 로그 개선 계획
**날짜**: 2026-02-02
**작성자**: Claude
**관련 파일**: `rb8001/app/services/skills/startup_news_skill.py`, `skill_news/app/services/sea_news_collector.py`
---
## 1. 문제 상황
- **수집 실패**: Google News HTML 구조 변경으로 인해 동남아 뉴스 수집량이 0건으로 떨어짐.
- **추적 불가**: 뉴스 브리핑 송출 시 Slack 메시지의 타임스탬프(ts)를 로그에 남기지 않아, 잘못된 메시지 삭제 등 사후 처리가 어려움.
## 2. 해결 단계 (Phase)
### Phase 1: 송출 로그 개선 (로그에 ts 포함)
- **목표**: 뉴스 브리핑 전송 성공 시 Slack이 반환하는 `ts`를 반드시 로그에 기록.
- **작업**: `startup_news_skill.py``slack_client.chat_postMessage` 호출 결과에서 `ts`를 추출하여 `logger.info`로 출력.
- **기대효과**: 문제 발생 시 로그만 보고도 해당 메시지를 식별하여 삭제 가능.
### Phase 2: 수집기 셀렉터 복구
- **목표**: 변경된 Google News 구조에 맞춰 뉴스 제목과 링크를 다시 수집.
- **작업**: `sea_news_collector.py`의 셀렉터를 `article`에서 `a[class*="JtKRv"]` 기반으로 업데이트.
- **기대효과**: 24시간 이내의 정확한 동남아 스타트업 뉴스 수집 재개.
### Phase 2.5: 동남아 뉴스 형식 검증
- **목표**: 수집된 뉴스가 Slack 표시 형식에 맞는지 확인.
- **형식**: `01. <url|제목>`, `02. <url|제목>`, `03. <url|제목>` (한국어 번역된 제목, 링크 포함).
- **검증**: `sea_news_service.py``format_sea_news_for_slack` 결과에 URL·제목이 정상 포함되는지 확인.
### Phase 3: 수집 안정성 강화 (RSS 폴백)
- **목표**: Google News 스크래핑 실패 시에도 최소한의 뉴스를 보장.
- **작업**: `ASEAN UP` 등 RSS 피드를 보조 수집원으로 추가. 0건일 경우 RSS에서 가져와 LLM 필터링 후 제공.
- **기대효과**: 스크래핑 엔진이 깨져도 브리핑 섹션이 비어 나가는 현상 방지.
## 3. 삭제 및 재전송 절차
- **대상 메시지**: ts=`1769991030.415619`, 채널=`C09C98KK2TT` (Slack URL: `.../C09C98KK2TT/p1769991030415619`).
- **삭제**: `chat.delete` API 호출 (`channel=C09C98KK2TT`, `ts=1769991030.415619`). **토큰**: `COMPANYX_SLACK_BOT_TOKEN` 사용 (startup_news_skill과 동일, 참조: `troubleshooting/250915_happybell80_Slack_메시징_운영_런북.md`).
- **재전송**: `run_headlines_job("C09C98KK2TT")` 수동 호출 또는 스케줄러 엔드포인트 `POST /api/schedule/run/daily_headlines` 실행.
- **순서**: Phase 1~2 완료 후 → 삭제 → 재전송.
## 4. 남은 작업
- [ ] `startup_news_skill.py` 수정 (로그 추가)
- [ ] `sea_news_collector.py` 수정 (셀렉터 업데이트)
- [ ] 동남아 뉴스 형식 검증 (`format_sea_news_for_slack`)
- [ ] 기존 메시지 삭제 후 재전송