# CLAUDE.md

> Claude Code가 본 프로젝트에서 작업할 때 따라야 할 규칙.
> 프로젝트의 "왜/무엇"은 `PRD.md`를, "사용법"은 `README.md`를 참고한다.
> 이 문서는 "어떻게/어디를"에만 집중한다.

---

## 0. 작업 시작·종료 프로토콜 (가장 중요)

### 🔴 작업 시작 전 — 반드시 수행
1. **`current_status.md`를 가장 먼저 읽는다.**
2. "진행 중 작업" 섹션을 확인해 이전 세션이 어디서 멈췄는지 파악한다.
3. "미결정 이슈"가 있으면 사용자에게 먼저 묻고 시작한다.
4. 파악한 내용을 1~3줄로 요약해 사용자에게 보고한 뒤 작업을 시작한다.

### 🟢 작업 종료 후 — 반드시 수행
작업이 끝나면(파일 생성/수정/삭제 등 의미 있는 변경이 있을 때) `current_status.md`를 다음 형식으로 **업데이트한다.**

```
## [날짜 YYYY-MM-DD HH:mm]
### 완료된 작업
- 무엇을 했는가 (구체적 파일명·함수명 포함)

### 진행 중 작업
- 지금 어디까지 됐고 어디서 멈췄는가

### 다음 단계
- 다음 세션에서 가장 먼저 할 일 1~3개

### 미결정 이슈
- 사용자 결정이 필요한 항목
```

**원칙**:
- 이전 기록을 지우지 않고 **누적 추가**한다 (위에 새 기록 쌓기).
- "대충 했음" 같은 모호한 표현 금지. 파일명·함수명·줄 번호까지 구체적으로.
- 사용자가 다른 PC에서 열어도 맥락을 5분 안에 복원할 수 있어야 한다.

---

## 1. 프로젝트 개요 (3줄)

- **무엇**: 기업교육 강사를 위한 데일리 뉴스 자동 큐레이션 봇
- **핵심 흐름**: Google News RSS → 자카드 중복 제거 → Claude API 평가 → Claude API 요약 → HTML 카드 메일 발송
- **실행 환경**: Node.js + GitHub Actions cron (매일 KST 07:00)

---

## 2. 핵심 아키텍처

```
src/index.js (엔트리)
   │
   ├─→ fetcher.js          (RSS 수집)
   ├─→ deduplicator.js     (자카드 유사도 중복 제거, 외부 API 없음)
   ├─→ evaluator.js        (Claude API 호출 #1: 적합도 평가)
   │       │
   │       ├─ 적합 0개 → templates/empty.js → mailer.js → 종료
   │       │
   │       └─ 적합 1개+ ↓
   │
   ├─→ selector.js         (키워드 균등 배분 Top N)
   ├─→ summarizer.js       (Claude API 호출 #2: 요약 + 활용 코멘트)
   ├─→ templates/daily.js  (HTML 렌더링)
   └─→ mailer.js           (Nodemailer 발송)
```

---

## 3. 파일별 역할

| 파일 | 단일 책임 | 외부 의존 |
|---|---|---|
| `src/index.js` | 파이프라인 조립 + 분기 | 모든 모듈 |
| `src/config.js` | 환경변수 로드 + 검증 | `dotenv` |
| `src/fetcher.js` | RSS 호출 + 파싱 + 24h 필터 | `rss-parser` |
| `src/deduplicator.js` | 자카드 유사도 계산 + 그룹화 | 없음 (순수 JS) |
| `src/evaluator.js` | Claude API로 상/중/하 판정 | `lib/claude.js` |
| `src/selector.js` | 키워드 균등 배분 + Top N | 없음 |
| `src/summarizer.js` | Claude API로 요약 + 코멘트 | `lib/claude.js` |
| `src/templates/daily.js` | 일반 모드 HTML | 없음 |
| `src/templates/empty.js` | 안내 모드 HTML | 없음 |
| `src/mailer.js` | Gmail SMTP 발송 | `nodemailer` |
| `src/lib/claude.js` | Claude API 호출 통합 래퍼 | `@anthropic-ai/sdk` |
| `src/lib/logger.js` | 콘솔 로그 통합 (타임스탬프) | 없음 |

---

## 4. 절대 규칙 (Must)

1. **모든 환경변수는 `src/config.js`만 통과한다.**
   - `process.env.XXX`를 다른 파일에서 직접 읽지 않는다.
   - `config.js`에서 검증·기본값·타입변환을 한 번에 처리한다.
   - **필수 환경변수 누락 시**: "어떤 변수가 빠졌는지 + 어디서 설정해야 하는지(GitHub Secrets 경로)"를 콘솔에 명확히 출력 후 즉시 종료.

2. **Claude API 호출은 `src/lib/claude.js`만 사용한다.**
   - `evaluator.js`, `summarizer.js`는 이 래퍼만 호출한다.
   - 모델명·토큰·재시도 로직이 한 곳에서 관리된다.

3. **로그는 `src/lib/logger.js`만 사용한다.**
   - `console.log` 직접 사용 금지.
   - 모든 로그는 `[YYYY-MM-DD HH:mm:ss] [모듈명] 메시지` 형식.

4. **한 파일 = 한 책임.**
   - 새 기능 추가 시 기존 파일에 우겨넣지 말고 새 파일을 만든다.

5. **코드 내 주석은 한국어로 작성한다.**
   - 변수/함수명은 영어, 주석은 한국어.

6. **기존 코드를 생략·축약하지 않는다.**
   - `// ... 기존 코드 동일` 같은 표현 금지.
   - 수정 시에도 전체 코드를 그대로 이어 쓴다.

---

## 5. 절대 금지 (Must Not)

- ❌ `.env` 파일을 git에 커밋
- ❌ API 키·비밀번호 하드코딩
- ❌ 한국어 주석을 영문으로 자동 변환
- ❌ 기존 코드를 임의로 생략·축약
- ❌ Claude API 호출 시 `max_tokens`·`temperature`를 호출부에서 직접 지정 (`lib/claude.js`가 기본값 관리)
- ❌ HTML 템플릿에 외부 CSS·JS·이미지 링크 사용 (Gmail 호환성 깨짐, 모두 인라인 처리)
- ❌ `current_status.md`를 git에 커밋 (gitignore 처리)

---

## 6. 자주 하는 작업 가이드

| 원하는 변경 | 만져야 할 곳 |
|---|---|
| 키워드 추가/제거 | `.env`의 `KEYWORDS`만 |
| 강사 프로필 변경 | `.env`의 `INSTRUCTOR_PROFILE`만 |
| Claude 모델 교체 | `.env`의 `CLAUDE_MODEL`만 |
| 메일 디자인 변경 | `src/templates/daily.js` 또는 `empty.js`만 |
| 적합도 평가 기준 수정 | `src/evaluator.js`의 프롬프트 |
| 중복 임계값 조정 | `.env`의 `SIMILARITY_THRESHOLD`만 |
| 발송 시각 변경 | `.github/workflows/daily.yml`의 cron |
| RSS 소스 추가 (네이버 등) | `src/fetcher.js`에 새 함수 추가 + index에서 합치기 |

---

## 7. Claude API 사용 규칙

### 7.1 호출 횟수
- 하루 최대 **2회** (평가 1회 + 요약 1회)
- 적합도 '상' 0개일 땐 **1회만** (요약 호출 스킵)
- 배치 처리: 여러 기사를 한 번의 호출로 묶는다. 기사당 1회 호출 금지.

### 7.2 응답 파싱
- 모든 응답은 JSON 형식으로 강제한다.
- 프롬프트 끝에 `"JSON only, no markdown fences"` 명시.
- 파싱 실패 시 1회 재시도, 그래도 실패하면 에러 로그 + 메일 발송 스킵.

### 7.3 모델 선택
- 기본값: `claude-haiku-4-5`
- `.env`의 `CLAUDE_MODEL`로 변경 가능 (Haiku/Sonnet/Opus)
- 코드에서 모델명을 if 분기로 다르게 처리하지 않는다 (모델은 블랙박스로 취급).

---

## 8. 에러 처리 원칙

| 상황 | 동작 |
|---|---|
| 필수 환경변수 누락 | 누락 변수명 + 등록 위치 출력 후 즉시 종료 |
| RSS 호출 실패 | 해당 키워드만 스킵, 나머지로 계속 진행 |
| 적합도 '상' 0개 | `empty.js` 템플릿으로 안내 메일 발송 (정상 흐름) |
| Claude API 파싱 실패 | 1회 재시도 → 실패 시 에러 메일 발송 |
| Gmail SMTP 실패 | GitHub Actions 로그에 에러 출력, 실행 실패 처리 |
| 전체 기사 수집 0개 | "오늘 수집 기사 없음" 메일 발송 |

**원칙**: 봇이 침묵하지 않는다. 어떤 상황이든 사용자에게 결과를 알린다.

---

## 9. 테스트 / 디버깅

### 9.1 로컬 실행
```bash
node src/index.js
```
- `.env`를 로컬에 두고 실행
- 실제 메일 발송됨 (테스트용 별도 메일 주소 권장)

### 9.2 GitHub Actions 수동 실행
- Actions 탭 → "Daily News Curator" → "Run workflow"
- cron 안 기다리고 즉시 테스트 가능

### 9.3 0개 분기 강제 테스트
- `src/evaluator.js`에서 임시로 모든 결과를 "하"로 리턴하도록 변경
- `empty.js` 템플릿 정상 동작 확인 후 원복

---

## 10. 버전 관리

- 본 프로젝트는 SemVer 따른다 (v1.0.0 → v1.1.0 → ...)
- 주요 변경 시 `README.md`에 변경 이력 1줄 추가
- 작업 기록은 로컬 `current_status.md`에만 (gitignore 처리)

---

## 11. 외부 라이브러리 화이트리스트

본 프로젝트는 **최소 의존성**을 원칙으로 한다. 아래 목록 외 추가 시 사유 명시.

| 패키지 | 용도 |
|---|---|
| `@anthropic-ai/sdk` | Claude API |
| `rss-parser` | RSS 파싱 |
| `nodemailer` | Gmail SMTP 발송 |
| `dotenv` | 환경변수 로드 |

이게 전부. 다른 강사가 fork할 때 `npm install` 한 번에 끝나야 한다.

---

## 12. 만든 사람 / 라이선스

- 만든 사람: Teddy (WOWD.LAB)
- 라이선스: MIT (예정)
- 문의: support@wowdlab.com
