# CLAUDE.md - 작업 규칙

> **Claude Code 작업 시작 시**: 이 파일을 읽은 직후 `current_status.md`를 읽고, [다음 단계] 1번부터 진행한다. PRD.md는 요구사항 확인이 필요할 때만 참조한다. 작업 종료 시 반드시 `current_status.md`를 업데이트한 뒤 세션을 마친다.

이 문서는 **Claude(개발 파트너)와 Teddy가 G2B Bid Scout 프로젝트를 함께 개발할 때 지켜야 할 규칙**을 정의한다. 새 세션을 시작할 때마다 이 파일을 먼저 읽고 작업한다.

---

## 1. 프로젝트 정체성

- **이름**: G2B Bid Scout
- **한 줄 설명**: 나라장터 입찰공고를 자동 수집·큐레이션해 강사에게 주 1회 메일로 보내는 봇
- **사용자**: 기업교육 강사 (1차: Teddy, 2차: Fork해서 쓰는 다른 강사들)
- **상위 문서**: `PRD.md` (왜/무엇), 이 문서는 **어떻게/어디를** 다룸

> PRD와 이 문서가 충돌하면 **PRD가 우선**. CLAUDE.md는 실행 규칙.

---

## 2. 작업 시작 전 체크리스트

새 세션을 시작할 때 Claude는 다음 순서로 파일을 읽는다:

```
1. CLAUDE.md (이 파일)         → 작업 규칙 숙지
2. current_status.md           → 마지막 세션에서 어디까지 했는지 확인
3. PRD.md                      → 요구사항 재확인 (필요할 때만)
4. README.md                   → 사용자 관점 재확인 (필요할 때만)
```

작업 시작 전에 항상 묻는다:
- "지난 세션 마지막에 [X]까지 완료했어. 이번 세션 목표는 무엇으로 잡을까?"

---

## 3. 역할 구조 (Manager / Worker / Evaluator)

복잡한 작업은 3역할로 분리해서 수행한다.

### Manager (목표 점검)
- 작업 시작 전: "오늘 목표는 무엇인가? PRD의 어느 섹션과 연결되는가?"
- 작업 중: 범위 이탈 감시 ("요청 안 한 분석·제안·확장 금지")
- 작업 끝: "다음 세션이 어디서 시작해야 하는가?"

### Worker (실행)
- 코드 작성, 파일 편집, 명령 실행
- 한 번에 한 모듈만. `fetcher.js` 끝내고 `filter.js` 시작.
- 기존 코드 생략·삭제 없이 이어서 작성

### Evaluator (품질 평가)
- 매 모듈 완성 후 10점 만점 자체 평가
  - 적합성 (PRD에 부합하는가)
  - 신뢰도 (에지 케이스 처리되는가)
  - 활용 가능성 (다른 강사가 .env만 바꿔 쓸 수 있는가)
- **9.0 미만이면 자동으로 개선 버전 제시**
- 오류 발견 시: 즉시 인정 → 수정 → 수정 이유 1줄

---

## 4. 코딩 컨벤션

### 4.1 파일 구조 원칙

```
src/
├── index.js          # 진입점 only. 비즈니스 로직 금지.
├── fetcher.js        # 공공데이터 API(PPSSrch)만. 키워드별 병렬 호출.
├── filter.js         # 키워드 매칭 + 태깅. AI 호출 금지.
├── evaluator.js      # Claude API만. 메일·필터 금지.
├── mailer.js         # Nodemailer + HTML 빌드. 데이터 로직 금지.
└── utils.js          # 순수 함수만. 부수효과 금지.
```

**원칙**: 한 파일 = 한 책임. 책임 경계를 넘는 코드를 발견하면 즉시 분리.

### 4.2 코딩 스타일

- **언어**: Node.js 18+ (ES Modules 사용, `type: "module"`)
- **주석**: 모든 함수 위에 한글 주석 필수. JSDoc 형식 권장.
  ```js
  /**
   * 공공데이터포털에서 용역 공고 전체를 페이징으로 수집한다.
   * @param {string} apiKey - 디코딩된 API 키
   * @returns {Promise<Array>} 공고 객체 배열
   */
  async function fetchAllServiceBids(apiKey) { ... }
  ```
- **변수명**: camelCase. 한글 변수명 사용 금지(주석으로만).
- **상수**: SCREAMING_SNAKE_CASE. 매직 넘버 금지.
- **에러**: try/catch로 잡고, console.error로 로깅 후 throw. 침묵 금지.

### 4.3 환경변수 사용 규칙

- 모든 외부 설정은 `.env`에서 읽는다. 코드에 하드코딩 금지.
- `.env.example`는 `.env` 변경 시 **반드시 함께** 업데이트.
- 환경변수 누락 시 시작 즉시 명확한 에러 메시지로 종료:
  ```js
  if (!process.env.G2B_API_KEY) {
    throw new Error('G2B_API_KEY가 .env에 설정되지 않았습니다.');
  }
  ```

### 4.4 외부 의존성

승인된 패키지만 사용:
- `@anthropic-ai/sdk` (Claude API)
- `nodemailer` (메일 발송)
- `dotenv` (환경변수)
- `axios` 또는 native `fetch` (HTTP)

새 패키지 도입 시 Teddy에게 사전 확인.

---

## 5. AI 호출 규칙

### 5.1 Claude API 사용 원칙

- **모델**: 환경변수 `CLAUDE_MODEL` (기본 `claude-haiku-4-5`)
- **호출 횟수**: 주당 최대 2회 (메인 평가 1회 + 30건 초과 시 분할 1회)
- **프롬프트**: 별도 상수로 분리 (`PROMPTS.ELIGIBILITY` 같은 형태)
- **응답 파싱**: JSON 모드 강제 + 실패 시 1회 재시도
- **타임아웃**: 60초

### 5.2 프롬프트 구조 (적합도 평가용)

```
[시스템 메시지]
당신은 기업교육 강사의 입찰공고 적합도를 평가하는 어시스턴트입니다.

강사 프로필:
{INSTRUCTOR_PROFILE}

각 공고에 대해 강사 프로필 대비 적합도를 상/중/하로 평가하고
한 줄 이유를 제시하세요. 키워드 매칭은 이미 완료되었습니다.
의미적 적합성만 판단하세요.

[유저 메시지]
다음은 평가할 공고 목록입니다.
각 공고를 {bidNtceNo, score: "상|중|하", reason: "..."} 형태로 평가하세요.

응답은 JSON 배열만 출력하세요. 다른 설명 금지.

공고 목록:
{공고 배열 JSON}
```

---

## 6. 메일 빌드 규칙

### 6.1 HTML 템플릿 원칙

- 인라인 CSS만 사용 (Gmail은 `<style>` 태그 제한적)
- 폰트: `Pretendard, -apple-system, BlinkMacSystemFont, sans-serif`
- 본문 14px 기본 / 최소 10px
- 컬러: WOWD.LAB 브랜드 가이드 따름
  - Primary: `#50676A`
  - Accent: `#F29B2F` (CTA 버튼)
  - Dark: `#231F20` (본문)
- 모바일 우선: max-width 600px, 단일 컬럼

### 6.2 CTA 버튼

```html
<a href="{원문URL}"
   style="display:inline-block; padding:10px 20px; background:#F29B2F;
          color:#fff; text-decoration:none; border-radius:4px;">
  원문 보러 가기 →
</a>
```

### 6.3 발신자 / 제목 규칙

- From: `{GMAIL_USER}` (별칭 사용 금지)
- Subject: `🎯 이번 주 입찰공고 N건 (마감 임박 X건) | YYYY-MM-DD`
- 0건 시: `📭 이번 주 적합 공고 없음 | YYYY-MM-DD`

---

## 7. Git / 커밋 규칙

### 7.1 브랜치
- `main`: 운영 (GitHub Actions 실행 기준)
- 개발 시 main에 직접 푸시 가능 (1인 프로젝트)

### 7.2 커밋 메시지

```
타입: 한 줄 요약 (50자 이내)

상세 설명 (필요 시)
```

타입:
- `feat`: 새 기능
- `fix`: 버그 수정
- `refactor`: 리팩터링
- `docs`: 문서 변경
- `chore`: 빌드/설정 변경

예시:
```
feat: 1차 필터에 마감 D-14 윈도우 추가
fix: presmptPrce가 null일 때 NaN 발생 버그 수정
docs: README에 cron 표현식 예시 추가
```

### 7.3 절대 커밋 금지
- `.env` (실제 키 포함)
- `node_modules/`
- 개인 메일 발송 로그

`.gitignore` 필수:
```
.env
node_modules/
*.log
.DS_Store
```

---

## 8. 디버깅 / 테스트 규칙

### 8.1 로컬 테스트
- `npm run test:fetch` → API 호출만 검증 (Claude 호출 없음)
- `npm run test:filter` → 더미 데이터로 필터 로직 검증
- `npm run test:mail` → 더미 데이터로 메일 발송 검증 (실제 발송)
- `npm start` → 전체 흐름 1회 실행

### 8.2 운영 디버깅
- GitHub Actions 실행 로그를 통해 단계별 통계 확인
- 메일 발송 실패 시 GitHub Actions에서 에러 알림 (workflow에 fail 알림 설정)

### 8.3 에지 케이스 체크리스트

매 모듈 완성 후 반드시 검증:

- [ ] API 응답이 빈 배열일 때
- [ ] API가 5xx 에러 반환할 때 (3회 재시도)
- [ ] `presmptPrce`가 null/0/문자열일 때
- [ ] 한국어 키워드에 특수문자/공백 포함될 때
- [ ] Claude API가 JSON이 아닌 응답을 줄 때 (1회 재시도 후 폴백)
- [ ] 메일 후보가 30건 초과일 때 (분할 호출)
- [ ] 메일 후보가 0건일 때 (안내 메일 분기)

---

## 9. 단축키 / 운영 표현

### 9.1 작업 상태 보고 포맷

복잡한 작업이 끝나면 항상 이 포맷으로 요약:

```
[완료된 작업]
- ...

[진행 중 작업]
- ...

[다음 단계]
- ...

[미결정 이슈]
- ...
```

### 9.2 `/meta` 또는 `/메타`

Teddy가 이 단축키를 입력하면 현재 작업을 다음 구조로 자동 재작성:
- 역할 / 목표 / 작업 범위 / 출력 형식 / 평가 기준

---

## 10. 절대 규칙 (Never)

다음은 어떤 경우에도 위반 금지:

1. **PRD 범위를 벗어난 기능 임의 추가 금지**
   - "이것도 있으면 좋을 것 같아서..." → 즉시 중단. Teddy에게 확인.
2. **테스트 없이 운영 푸시 금지**
   - 최소 `npm run test:fetch` + `npm run test:mail`은 통과해야 main에 푸시
3. **API 키·비밀번호 하드코딩 금지**
   - 모든 비밀은 `.env`와 GitHub Secrets로만
4. **다른 강사의 사용성을 깨뜨리는 변경 금지**
   - Teddy 전용 분기 로직 작성 금지. 모두 환경변수로.
5. **불확실한 정보를 확실한 것처럼 답변 금지**
   - "확실하지 않은 사실" 또는 "추론 의견"으로 명시
6. **에러 침묵 금지**
   - try/catch로 잡으면 반드시 로깅 + 재처리 또는 throw

---

## 11. 세션 종료 시 체크리스트

> ⚠️ **`current_status.md` 업데이트는 선택이 아닌 필수다.** 이걸 빼먹으면 다음 세션이 처음부터 다시 파악해야 한다. 작업이 끝났으면 코드 커밋 전에 반드시 이 파일부터 갱신한다.

작업을 마무리하기 전에:

- [ ] **`current_status.md` 업데이트** (다음 세션이 바로 이어갈 수 있도록) ← 최우선
- [ ] 새로 추가한 환경변수가 있으면 `.env.example`에도 반영
- [ ] PRD에 영향 주는 결정이 있었으면 PRD 버전 갱신 검토
- [ ] 커밋 메시지에 변경 의도 명확히 기재
- [ ] 미해결 이슈를 `current_status.md`의 [미결정 이슈]에 적기

---

## 12. 변경 이력

| 버전 | 일자 | 변경 |
|------|------|------|
| v0.1 | 2026-05-17 | 초안 작성 |
| v0.2 | 2026-05-17 | Claude Code 작업 시작 시 인용구 추가 / 섹션 11(세션 종료 체크리스트)에 current_status.md 우선순위 강조 |
| v0.3 | 2026-05-17 | 파일 구조에 병렬 페이징·키워드 태깅 반영. API Base URL `/ad/` 경로 확정. 필터 정책 변경: 키워드 매칭 공고 전부 AI 평가 대상 |
| v0.4 | 2026-05-17 | fetcher.js를 PPSSrch 엔드포인트(키워드별 부분 매칭 병렬 호출)로 전환 |
