# 강사를 위한 데일리 뉴스 큐레이션 봇 PRD

**프로젝트명**: `daily-news-curator-for-instructors` (가칭)
**작성일**: 2026-05-16
**작성자**: Teddy (WOWD.LAB)
**버전**: **v1.0 (확정)**

---

## 변경 이력

| 버전 | 일자 | 변경 내용 |
|---|---|---|
| v0.1 | 2026-05-16 | 초안 작성 |
| v1.0 | 2026-05-16 | 미결정 이슈 확정: ①적합 기사 0개 시에도 메일 발송 ②모델 환경변수화 / `INSTRUCTOR_PROFILE` 변수 신설 / 폴더 구조 단순화(PRD를 루트에) |

---

## 1. 프로젝트 개요

### 1.1 목적
기업교육 강사가 매일 아침 강의 분야 뉴스를 수동 검색하는 시간을 0분으로 만든다. 매일 오전 7시, AI가 강사 관점에서 선별·요약·활용 코멘트까지 붙인 메일이 수신함에 도착한다.

### 1.2 한 줄 정의
> "키워드만 바꾸면 누구나 자기 강의 분야의 큐레이션 비서를 갖는다."

### 1.3 핵심 가치
- **시간 절약**: 매일 30분 → 5분 (메일 훑기만)
- **관점 강화**: 단순 뉴스가 아닌 "강의 활용 포인트"까지 포함
- **재사용성**: 다른 강사도 Fork → .env만 수정해서 그대로 사용

---

## 2. 사용자 시나리오

### 2.1 1차 사용자 (Teddy)
- 키워드: `기업교육`, `생성형AI`, `AX`, `바이브코딩`
- 강사 프로필: "기업교육 강사, 디자인씽킹·AI 활용 워크숍 진행, 사례 중심 강의 선호"
- 사용 패턴: 오전 7시 메일 수신 → 출근 준비하며 모바일로 훑음 → 강의/콘텐츠 아이디어 발굴

### 2.2 2차 사용자 (다른 강사들)
- GitHub Repo Fork → Secrets 등록 → `.env`의 키워드와 프로필만 변경 → 끝
- 예시:
  - 리더십 강사: 키워드 `리더십,조직문화,MZ세대,코칭` + 프로필 `리더십 전문 강사, 팀빌딩·코칭 워크숍 진행`
  - 마케팅 강사: 키워드 `퍼포먼스마케팅,GA4,그로스해킹,브랜딩` + 프로필 `디지털 마케팅 강사, 실무 케이스 중심`

---

## 3. 핵심 요구사항

### 3.1 기능 요구사항

| 번호 | 기능 | 설명 |
|---|---|---|
| F1 | 키워드별 RSS 수집 | 각 키워드별로 Google News RSS를 따로 호출, 풀(pool) 구성 |
| F2 | 사전 중복 제거 | 자카드 유사도 기반(어절 단위, 임계값 0.65)으로 유사 제목 묶기 |
| F3 | 키워드 균등 배분 | 최종 5개 중 키워드별 1~2개씩 배분 (다양성 보장) |
| F4 | AI 적합도 평가 | Claude API로 강사 관점 적합도(상/중/하) 판정, '상'만 통과 |
| F5 | 3줄 요약 + 활용 코멘트 | 각 기사에 3줄 요약 + "강의에 이렇게 써먹을 수 있다" 1줄 |
| F6 | HTML 메일 발송 | Nodemailer + Gmail SMTP로 카드형 HTML 메일 발송 |
| F7 | 적은 날엔 적게 | 적합도 '상' 기사가 5개 미만이면 그만큼만 발송 |
| F7-1 | 0개일 땐 안내 메일 | 적합도 '상' 기사가 0개인 날에도 "오늘은 적합 기사 없음" 안내 메일 발송 (봇 생존 신호) |
| F8 | 매일 7시 자동 실행 | GitHub Actions cron으로 KST 오전 7시 자동 실행 |
| F9 | 모델 선택 가능 | `CLAUDE_MODEL` 환경변수로 모델 자유 선택 (Haiku/Sonnet/Opus) |
| F10 | 강사 프로필 주입 | `INSTRUCTOR_PROFILE` 환경변수로 평가 프롬프트에 강사 컨텍스트 주입 |

### 3.2 비기능 요구사항

| 항목 | 기준 |
|---|---|
| 비용 | Haiku 기준 월 500원 이하 / Sonnet 기준 월 5,000원 이하 |
| 실행 시간 | 5분 이내 (GitHub Actions 무료 한도 내) |
| 가독성 | 모바일에서 5분 안에 훑을 수 있는 카드형 UI |
| 재사용성 | `.env` 수정만으로 다른 강사 사용 가능 |
| 신뢰성 | 실패 시 GitHub Actions 로그로 원인 파악 가능 |

---

## 4. 시스템 아키텍처

```
[GitHub Actions Cron: KST 07:00]
          ↓
[1. RSS 수집]
  - 키워드별 Google News RSS 호출 (4개 키워드 = 4개 피드)
  - 각 피드에서 최근 24시간 기사만 추출
          ↓
[2. 사전 중복 제거]
  - URL 완전 일치 제거
  - 제목 자카드 유사도 0.65 이상 → 1개만 남김
  - 출처: 어느 키워드에서 왔는지 태깅 유지
          ↓
[3. AI 적합도 평가 (Claude API 호출 #1)]
  - INSTRUCTOR_PROFILE 컨텍스트 주입
  - 사례/케이스형(1순위) > 인사이트/관점형(2순위) 가중치
  - 적합도 '상'만 통과
          ↓
       ┌──분기──┐
   '상' 0개         '상' 1개 이상
       ↓                ↓
[안내 메일 발송]  [4. 키워드 균등 배분 + Top 5 선정]
   "오늘은 적합              ↓
    기사 없음"      [5. 요약 + 활용 코멘트 (Claude API 호출 #2)]
       ↓                    ↓
      종료          [6. HTML 카드 메일 발송]
                            ↓
                          종료
```

---

## 5. 상세 설계

### 5.1 RSS 수집 (F1)
- Google News RSS URL 형식: `https://news.google.com/rss/search?q={키워드}&hl=ko&gl=KR&ceid=KR:ko`
- 키워드별로 1회씩 호출, 각 피드에서 상위 15~20개 수집 (총 60~80개 풀)
- 24시간 이내 기사만 필터링(`pubDate` 기준)

### 5.2 중복 제거 (F2) — 자카드 유사도 방식

```
function similarity(titleA, titleB):
  1) 정규화: 소문자화, 특수문자 제거, 매체명 꼬리표 제거 (" - 매체명")
  2) 어절 단위 split (공백 기준)
  3) 불용어 제거 ("및", "등", "에서" 등)
  4) Jaccard = |A ∩ B| / |A ∪ B|
  5) SIMILARITY_THRESHOLD 이상이면 동일 기사로 간주

→ 그룹화 후, 그룹당 1개만 남김 (대표: pubDate 가장 최신)
```

비용: 0원 (순수 문자열 비교)

### 5.3 AI 적합도 평가 (F4) — Claude API 호출 #1

**Claude에게 전달할 프롬프트 골자:**

```
당신은 기업교육 강사를 위한 뉴스 큐레이터입니다.
다음 기사들을 강사 관점에서 평가해주세요.

[강사 프로필]
{INSTRUCTOR_PROFILE}
- 강의 분야: {KEYWORDS}

[평가 기준 - 우선순위 순]
1순위: 사례/케이스 스터디형 (기업이 실제로 시도한 사례)
2순위: 인사이트/관점형 (전문가 칼럼, 새로운 프레임)
제외: 단순 신제품 광고, 인사 발표, 주가 변동, 정치성 기사

[평가 라벨]
- "상": 강의에 바로 인용 가능한 사례/인사이트
- "중": 흥미롭지만 강의 활용도는 낮음
- "하": 강의 활용 불가

[기사 목록]
1. [{키워드}] {제목} - {요약 첫 200자}
2. ...

[출력 형식 - JSON only]
{
  "evaluations": [
    {"index": 1, "rating": "상", "type": "사례", "reason": "..."},
    ...
  ]
}
```

- 모델: `CLAUDE_MODEL` 환경변수로 지정 (기본값 `claude-haiku-4-5`)
- 한 번의 호출로 모든 기사를 배치 평가

### 5.4 키워드 균등 배분 (F3, F7)
- 통과 기사들을 키워드별로 그룹화
- 라운드 로빈 방식으로 1개씩 뽑아 `MAX_ARTICLES`까지 채움
- 한 키워드가 비면 다른 키워드에서 보충

### 5.5 적합 기사 0개 분기 처리 (F7-1)

**조건**: `evaluator.js` 결과 중 `rating === "상"`인 기사가 0개

**동작**:
- 요약 + 코멘트 생성(API 호출 #2) 스킵 → 비용/시간 절약
- 안내용 HTML 메일 발송:
  - 제목: `[데일리 뉴스] {날짜} - 오늘은 적합 기사 없음`
  - 본문 카드:
    ```
    오늘은 강의 활용도 '상' 등급 기사가 없습니다.

    [수집 통계]
    - 수집 기사: N건
    - 중복 제거 후: M건
    - 적합도 '중': X건 / '하': Y건

    💡 다음 후보(중 등급 Top 1):
    - 제목
    - 링크
    ```

**의도**: 봇 생존 확인 + 평가 통계로 신뢰감 확보 + 가장 가까운 차선 1건은 살짝 보여주기

### 5.6 요약 + 활용 코멘트 (F5) — Claude API 호출 #2

```
다음 {N}개의 기사에 대해 각각 3줄 요약과 강의 활용 코멘트를 작성해주세요.

[강사 프로필]
{INSTRUCTOR_PROFILE}

[원칙]
- 3줄 요약: 사실 중심, 핵심 숫자/사례 포함
- 활용 코멘트: "이 기사는 ___ 강의에서 ___로 써먹을 수 있다" 형식
- 톤: 강사가 5초 안에 가치를 판단할 수 있도록 뾰족하게

[기사 목록]
...

[출력 형식 - JSON]
{
  "articles": [
    {
      "index": 1,
      "summary": ["1줄", "2줄", "3줄"],
      "usage_comment": "..."
    }
  ]
}
```

- 모델: `CLAUDE_MODEL` 환경변수 사용

### 5.7 HTML 메일 템플릿 (F6) — 카드형, 모바일 우선

**일반 모드 구조:**
- 헤더: 날짜 + "오늘의 강의 인사이트 N건"
- 카드 N개 (기사당 1카드):
  - 키워드 뱃지 (예: `[생성형AI]`)
  - 제목 (링크)
  - 출처 · 발행시각
  - 3줄 요약
  - 💡 활용 코멘트 (강조 박스)
- 푸터: 키워드 목록 + "WOWD.LAB 데일리 뉴스 봇"

**안내 모드 구조 (F7-1):**
- 헤더: 날짜 + "오늘은 적합 기사 없음"
- 통계 카드 1개 (수집·중복제거·등급 분포)
- 차선 후보 1개 (중 등급 Top 1)
- 푸터: 동일

**디자인 가이드:**
- 폰트: 시스템 폰트 스택(Apple SD Gothic Neo, Pretendard, 맑은 고딕)
- 컬러: 본문 `#0D0D0D`, 포인트 `#F6862A`, 카드 배경 `#F8F8F8`
- 카드 간격 넉넉히, 모바일에서 한 화면에 1.5개 카드 보이는 정도
- 인라인 CSS (Gmail HTML 호환성)

### 5.8 GitHub Actions 워크플로우 (F8)

```yaml
name: Daily News Curator
on:
  schedule:
    - cron: '0 22 * * *'   # UTC 22:00 = KST 07:00
  workflow_dispatch:        # 수동 실행 가능
jobs:
  curate:
    runs-on: ubuntu-latest
    steps:
      - checkout
      - setup-node@v4
      - npm ci
      - run: node src/index.js
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
          CLAUDE_MODEL: ${{ secrets.CLAUDE_MODEL }}
          GMAIL_USER: ${{ secrets.GMAIL_USER }}
          GMAIL_APP_PASSWORD: ${{ secrets.GMAIL_APP_PASSWORD }}
          MAIL_TO: ${{ secrets.MAIL_TO }}
          KEYWORDS: ${{ secrets.KEYWORDS }}
          INSTRUCTOR_PROFILE: ${{ secrets.INSTRUCTOR_PROFILE }}
          MAX_ARTICLES: ${{ secrets.MAX_ARTICLES }}
          SIMILARITY_THRESHOLD: ${{ secrets.SIMILARITY_THRESHOLD }}
```

---

## 6. 파일/폴더 구조

```
daily-news-curator/
├── .github/
│   └── workflows/
│       └── daily.yml              # GitHub Actions cron
├── src/
│   ├── index.js                   # 메인 엔트리 (분기 로직 포함)
│   ├── config.js                  # 환경변수 통합 (모든 변수의 단일 출입구)
│   ├── fetcher.js                 # RSS 수집
│   ├── deduplicator.js            # 자카드 유사도 중복 제거
│   ├── evaluator.js               # Claude API 적합도 평가
│   ├── summarizer.js              # Claude API 요약 + 활용 코멘트
│   ├── selector.js                # 키워드 균등 배분 Top N
│   ├── mailer.js                  # Nodemailer 발송
│   ├── templates/
│   │   ├── daily.js               # 일반 모드 HTML
│   │   └── empty.js               # 안내 모드 HTML (F7-1)
│   └── lib/
│       ├── claude.js              # Claude API 호출 통합 래퍼
│       └── logger.js              # 콘솔 로그 통합
├── .env.example                   # 환경변수 예시
├── .gitignore                     # current_status.md, .env 제외
├── package.json
├── package-lock.json
├── PRD.md                         # 이 문서
├── CLAUDE.md                      # Claude Code 작업 규칙
├── README.md                      # 사용자 가이드
└── current_status.md              # 작업 로그 (gitignore, 로컬 전용)
```

---

## 7. 환경 변수 (.env / GitHub Secrets)

| 변수명 | 필수 | 기본값 | 설명 | 예시 |
|---|---|---|---|---|
| `ANTHROPIC_API_KEY` | ✅ | — | Claude API 키 | `sk-ant-...` |
| `CLAUDE_MODEL` | ⬜ | `claude-haiku-4-5` | Claude 모델명 | `claude-sonnet-4-6` |
| `GMAIL_USER` | ✅ | — | 발신 Gmail 주소 | `you@gmail.com` |
| `GMAIL_APP_PASSWORD` | ✅ | — | Gmail 앱 비밀번호 (16자) | `xxxx xxxx xxxx xxxx` |
| `MAIL_TO` | ✅ | — | 수신 메일 주소 | `you@gmail.com` |
| `KEYWORDS` | ✅ | — | 쉼표 구분 키워드 | `기업교육,생성형AI,AX,바이브코딩` |
| `INSTRUCTOR_PROFILE` | ✅ | — | 강사 한 줄 프로필 | `기업교육 강사, 디자인씽킹·AI 워크숍, 사례 중심 선호` |
| `MAX_ARTICLES` | ⬜ | `5` | 최대 기사 수 | `5` |
| `SIMILARITY_THRESHOLD` | ⬜ | `0.65` | 중복 임계값 | `0.65` |

**모델 선택 가이드 (README에 명시)**:
- `claude-haiku-4-5`: 빠르고 저렴 (월 ~500원), 일반 큐레이션 충분 — **기본 권장**
- `claude-sonnet-4-6`: 균형형 (월 ~3,000원), 평가 품질 더 깐깐
- `claude-opus-4-7`: 최고 품질 (월 ~15,000원), 평가 정확도가 진짜 중요할 때

---

## 8. 문서 구조

본 프로젝트는 다음 4종의 마크다운 문서를 둔다.

| 문서 | 독자 | 역할 | git 커밋 |
|---|---|---|---|
| `PRD.md` | 본인 + fork 받은 강사 | 왜/무엇을 만드는가 | ✅ |
| `README.md` | fork 받은 강사 | 어떻게 사용하는가 | ✅ |
| `CLAUDE.md` | Claude Code | 어떻게 코드를 만지는가 | ✅ |
| `current_status.md` | 본인(+Claude Code) | 지금 어디까지 했는가 | ❌ (gitignore) |

---

## 9. 단계별 개발 순서

| 단계 | 작업 | 검증 방법 |
|---|---|---|
| 0 | 공통 유틸: `config.js`, `lib/logger.js`, `lib/claude.js` | 환경변수 누락 시 친절 메시지 출력 확인 |
| 1 | RSS 수집기 단독 구현 (`fetcher.js`) | 콘솔에 키워드별 기사 출력 |
| 2 | 자카드 중복 제거기 (`deduplicator.js`) | 의도적 유사 제목 → 1개만 남는지 |
| 3 | Claude API 평가기 (`evaluator.js`) | JSON 응답 파싱 정상 작동 |
| 4 | 0개 분기 로직 (`index.js`) | 적합 기사 0개 케이스 강제 테스트 |
| 5 | 요약 + 코멘트 생성기 (`summarizer.js`) | 실제 기사로 출력 품질 확인 |
| 6 | HTML 템플릿 2종 (`templates/daily.js`, `empty.js`) | 브라우저로 양쪽 다 확인 |
| 7 | Nodemailer 발송 (`mailer.js`) | 본인에게 테스트 메일 |
| 8 | 전체 파이프라인 연결 (`index.js`) | 로컬에서 1회 풀 실행 |
| 9 | GitHub Actions 등록 (`daily.yml`) | `workflow_dispatch` 수동 실행 |
| 10 | README 검증 | 다른 사람에게 시켜보고 막히는 지점 점검 |

---

## 10. 예상 비용

| 모델 | API 호출 비용 (월) | 총 운영비 |
|---|---|---|
| `claude-haiku-4-5` | ~$0.30 | **월 500원 이하** |
| `claude-sonnet-4-6` | ~$2 | 월 3,000원 |
| `claude-opus-4-7` | ~$10 | 월 15,000원 |

※ Google News RSS, Gmail SMTP, GitHub Actions는 모두 0원

---

## 11. 성공 지표

- **정량**: 메일 수신 7일 연속 정상 도착 / 적합도 '상' 정확도 80% 이상(주관 평가)
- **정성**: "이거 없으면 안 되겠다"는 본인 만족 / 다른 강사 3명 fork 시도

---

## 12. 향후 확장 아이디어 (v2 후보)

- Slack/카카오톡 발송 옵션
- 주간 다이제스트(일요일 통합본)
- 영문 매체(HBR 등) 추가
- 강의별 키워드 세트 다중화
- 평가 기록 누적 → 본인 클릭 패턴 학습

---

## 13. 미결정 이슈 — 모두 해결 ✅

- [x] 적합도 '상' 0개 시: **안내 메일 발송 (F7-1)**
- [x] Claude 모델 선택: **`CLAUDE_MODEL` 환경변수로 자유 선택 (F9)**
- [x] PRD 위치: **루트 디렉토리 (docs/ 폴더 없음)**
- [x] 작업 맥락 관리: **`current_status.md` 로컬 전용, Claude Code가 작업 전후 읽기/쓰기**
