Files
telegram-bot-workers/CLAUDE.md
kappa 2bd9bc4c2b feat: complete agent refactoring integration
- Add deposit session routing to openai-service.ts
- Convert deposit-tool to agent trigger (delegate to deposit-agent)
- Update CLAUDE.md with new agent architecture

Changes:
- openai-service.ts: Import and check hasDepositSession, route to processDepositConsultation
- deposit-tool.ts: Convert action → natural language → delegate to Deposit Agent
- CLAUDE.md: Update Core Services, Function Calling Tools, Data Layer, Deposit System sections

All tests passing (192/195), dev server starts successfully.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 12:47:34 +09:00

866 lines
32 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CLAUDE.md
> 🔧 **개발자용 문서**: 기술 상세, 코드 패턴, 트러블슈팅
> 📖 **[README.md](./README.md)**: 기능 소개, 배포 가이드, 사용법
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
---
## 1. Quick Start
### Auto-Read on Start
**세션 시작 시 반드시 수행:**
1. `README.md`를 Read 도구로 읽어 프로젝트 전체 구조 파악
2. 작업 대상 파일의 기존 코드 먼저 확인
```
필수 읽기: README.md → 작업 대상 파일
```
### Agent Usage Policy
**🎯 목표: 컨텍스트 절약 - 대부분의 작업을 에이전트에 위임**
**프로젝트 특성:**
- 언어: TypeScript (strict mode)
- 런타임: Cloudflare Workers
- 프레임워크: Wrangler, Workers AI, D1
- 주요 디렉토리: `src/tools/`, `src/routes/`, `src/services/`
**사용 가능한 에이전트 타입:**
- `coder`: 코드 작성/수정 (TypeScript/Workers 전문, 프로덕션 품질)
- `explorer`: 코드베이스 탐색/분석 (thorough 레벨)
- `planner`: 설계/계획 수립 전문가
- `reviewer`: 코드 리뷰 (qa/security/performance 페르소나 조합)
- `Bash`: 빌드/배포/테스트 실행 (긴 로그 출력 분리)
**CRITICAL: 다음 작업은 반드시 Task tool (agent)를 사용하여 메인 세션 컨텍스트 절약:**
| 작업 유형 | 조건 | 에이전트 타입 | 이유 |
|-----------|------|---------------|------|
| **코드 작성/수정** | 모든 코드 변경 | `coder` | TS/Workers 전문, 타입 안정성, 프로덕션 품질 |
| **리팩토링** | 파일 수 무관 | `coder` (병렬) | 일관성, 컨텍스트 분리, TS 최적화 |
| **Function Calling 도구** | 추가/수정 | `coder` (병렬) | tools/ + openai-service.ts 동시 처리 |
| **스키마 작업** | D1 마이그레이션 | `coder` | 백업→마이그레이션→검증 전체 위임 |
| **프로젝트 분석** | 구조 파악 | `explorer` (thorough) | 대량 파일 읽기 분리 |
| **설계/계획** | 아키텍처 설계 | `planner` | 시스템 분석 및 개선 방향 제시 |
| **코드 리뷰** | 보안/성능 | `reviewer``coder` | 분석 후 개선 제안 (reviewer는 읽기 전용) |
| **빌드/배포** | npm run, wrangler | `Bash` | 긴 로그 출력 분리 |
| **테스트** | 로컬 테스트 실행 | `Bash` | 테스트 출력 분리 |
**에이전트 위임의 이점:**
- ✅ 각 에이전트가 독립 컨텍스트 사용 (메인 세션 부담 0)
- ✅ 요약만 메인 세션에 반환 (토큰 대폭 절약)
- ✅ 병렬 처리 가능 (시간 단축)
- ✅ 메인 세션은 조율/지시만 담당
**병렬 처리 필수:**
- 독립적인 파일 여러 개 → 병렬 `coder` 에이전트
- 다른 디렉토리 동시 작업 → 병렬 `coder` 에이전트
- Function Calling 도구 추가 → tools/{new}.ts + openai-service.ts 병렬
**직접 처리 (최소화):**
- 간단한 문서 읽기 (README.md 확인)
- 사용자와의 대화/질문
- 에이전트 작업 조율/검토
### Critical Rules
**절대 지켜야 할 규칙:**
| 규칙 | 이유 |
|------|------|
| 배포 전 `npm run dev` 로컬 테스트 | 프로덕션 장애 방지 |
| D1 스키마 변경 시 마이그레이션 SQL 별도 작성 | 기존 데이터 보존 |
| Secrets(BOT_TOKEN, API_KEY 등) 코드에 하드코딩 금지 | 보안 |
| `wrangler.toml`의 ID 값 변경 금지 | 리소스 연결 유지 |
| Function Calling 도구 추가 시 `tools` 배열 + `executeFunctionCall()` 동시 수정 | 불일치 방지 |
**위험한 작업:**
- `wrangler d1 execute` 직접 실행 (production) → 반드시 확인 요청
- `user_deposits`, `deposit_transactions` 테이블 직접 수정 → 금전 관련, 주의
### Documentation Rules
**작업 완료 후 문서 자동 업데이트:**
| 변경 유형 | 업데이트 대상 |
|-----------|---------------|
| `src/*.ts` 파일 수정 | CLAUDE.md (Architecture, Key Patterns) |
| 새 Function Calling 도구 추가 | 양쪽 (README: 지원 기능 테이블, CLAUDE: tools 목록) |
| `schema.sql` 변경 | 양쪽 (Data Layer 섹션) |
| `wrangler.toml` 환경변수 추가 | 양쪽 (Configuration 섹션) |
| 외부 API 연동 추가/변경 | 양쪽 (External Integrations) |
| 봇 명령어 추가 | 양쪽 (Commands 섹션) |
---
## 2. Commands & Setup
### NPM Scripts
```bash
npm run dev # 로컬 개발 (wrangler dev)
npm run deploy # Cloudflare Workers 배포
npm run db:init # D1 스키마 초기화 (production) ⚠️ 주의
npm run db:init:local # D1 스키마 초기화 (local)
npm run tail # Workers 로그 스트리밍
npm test # 단위 테스트 실행 (Vitest)
npm run test:watch # Watch 모드
npm run test:coverage # 커버리지 리포트
```
### KV Namespace 생성
```bash
# Rate Limiting용 (필수)
wrangler kv:namespace create RATE_LIMIT_KV
# 서버 상담 세션용 (서버 추천 기능 사용 시 필수)
wrangler kv:namespace create SESSION_KV
# 출력된 id를 wrangler.toml의 [[kv_namespaces]] 섹션에 입력
```
### Secrets 설정
```bash
wrangler secret put BOT_TOKEN # Telegram Bot Token
wrangler secret put WEBHOOK_SECRET # Webhook 검증용
wrangler secret put OPENAI_API_KEY # OpenAI API 키
wrangler secret put NAMECHEAP_API_KEY # namecheap-api 래퍼 인증 키
wrangler secret put NAMECHEAP_API_KEY_INTERNAL # Namecheap API 키 (내부용)
wrangler secret put BRAVE_API_KEY # Brave Search API 키
wrangler secret put DEPOSIT_API_SECRET # Deposit API 인증 키
```
### Webhook 설정
```bash
# Webhook 설정
curl "https://telegram-summary-bot.kappa-d8e.workers.dev/setup-webhook?token=${BOT_TOKEN}&secret=${WEBHOOK_SECRET}"
# Webhook 정보 조회
curl "https://telegram-summary-bot.kappa-d8e.workers.dev/webhook-info?token=${BOT_TOKEN}&secret=${WEBHOOK_SECRET}"
```
### Database Migrations
**마이그레이션 목록:**
| 파일 | 설명 |
|------|------|
| `001_optimize_prefix_indexes.sql` | 입금자명 prefix 인덱스 최적화 (99% 성능 향상) |
| `002_add_version_columns.sql` | Optimistic Locking (user_deposits.version) |
| `003_add_server_tables.sql` | server_orders, server_specs 테이블 추가 |
| `004_add_terminated_at.sql` | server_orders.terminated_at 컬럼 추가 |
| `005_add_stopped_status.sql` | server_orders 테이블에 'stopped' 상태 추가 |
**실행:**
```bash
# 로컬 테스트
wrangler d1 execute telegram-conversations --local --file=migrations/001_optimize_prefix_indexes.sql
# 프로덕션 적용 ⚠️ 주의: 데이터 백업 권장
wrangler d1 execute telegram-conversations --file=migrations/001_optimize_prefix_indexes.sql
```
---
## 3. Architecture
### Message Flow
```
Telegram Webhook → Security Validation → Command/Message Router
┌──────────────────────────┴──────────────────────────┐
↓ ↓
Command Handler AI Response Generator
(commands.ts) (openai-service.ts)
Function Calling (9개)
(weather, search, time, calc, docs,
domain, suggest_domains, deposit, server)
Profile System
(summary-service.ts)
```
### Core Services
| 파일 | 역할 | 주요 함수 |
|------|------|----------|
| `index.ts` | Worker 진입점, Email Handler | `fetch()`, `email()` |
| `openai-service.ts` | AI 응답 + Function Calling + 세션 라우팅 | `generateResponse()`, `executeFunctionCall()` |
| `summary-service.ts` | 프로필 시스템 | `updateSummary()`, `getConversationContext()` |
| `security.ts` | Webhook 보안, Rate Limiting (KV) | `validateWebhook()`, `checkRateLimit()` |
| `services/notification.ts` | 관리자 알림 | `notifyAdmin()` |
| `commands.ts` | 봇 명령어 | `handleCommand()` |
| `telegram.ts` | Telegram API | `sendMessage()`, `sendTypingAction()` |
**Agent System (세션 기반 전문가 AI):**
| 파일 | 역할 | 상태 관리 |
|------|------|----------|
| `agents/server-agent.ts` | 서버 추천 상담 (30년 경력 아키텍트) | KV (1시간) |
| `agents/troubleshoot-agent.ts` | 트러블슈팅 상담 | KV (1시간) |
| `agents/domain-agent.ts` | 도메인 추천 상담 (10년 경력 컨설턴트) | D1 (1시간) |
| `agents/deposit-agent.ts` | 예치금 입금 신고 상담 (금융 상담사) | D1 (30분) |
**Logging & Monitoring:**
| 파일 | 역할 |
|------|------|
| `utils/logger.ts` | 구조화된 로깅 (JSON 기반, 환경별 전환) |
| `utils/metrics.ts` | 성능 메트릭 수집 (API 호출 시간, 에러율) |
| `utils/circuit-breaker.ts` | Circuit Breaker (OpenAI API 보호) |
| `utils/retry.ts` | 재시도 로직 (지수 백오프, 15개 API 지원) |
### Function Calling Tools (9개)
| 도구 | 함수명 | 처리 방식 | 트리거 키워드 |
|------|--------|----------|---------------|
| 날씨 | `get_weather` | wttr.in API | 날씨 |
| 검색 | `search_web` | Brave Search API (한글→영문 자동 번역) | ~란, ~뭐야 |
| 시간 | `get_current_time` | 내장 | 몇 시, 시간 |
| 계산 | `calculate` | 내장 | 계산, +, -, *, / |
| 문서 | `lookup_docs` | Context7 API | 문서, 사용법, API |
| 도메인 | `manage_domain` | **Domain Agent 위임** (세션 기반) | 도메인, 네임서버, WHOIS |
| 도메인 추천 | `suggest_domains` | GPT + Namecheap API | 도메인 추천, 도메인 제안 |
| 예치금 | `manage_deposit` | **Deposit Agent 위임** (세션 기반) | 입금, 충전, 잔액, 계좌 |
| 서버 | `manage_server` | **Server Agent 위임** (세션 기반) | 서버, VPS, 클라우드, 호스팅 |
### Data Layer (D1 SQLite)
| 테이블 | 용도 | 주요 컬럼 |
|--------|------|----------|
| `users` | 사용자 | telegram_id, username |
| `message_buffer` | 대화 기록 | user_id, role, content |
| `summaries` | 프로필 | user_id, generation, summary |
| `user_deposits` | 예치금 계정 | user_id, balance, version |
| `deposit_transactions` | 거래 내역 | user_id, amount, status |
| `bank_notifications` | SMS 파싱 | depositor_name, amount, bank |
| `user_domains` | 도메인 소유권 | user_id, domain, verified |
| `server_orders` | 서버 주문 | user_id, spec_id, status |
| `server_specs` | 서버 스펙 | name, cpu, ram, disk, price |
| `domain_sessions` | 도메인 상담 세션 | user_id, status, collected_info, messages |
| `deposit_sessions` | 예치금 상담 세션 | user_id, status, collected_info, messages |
**AI Fallback:** OpenAI 미설정 시 Workers AI (Llama 3.1 8B) 자동 전환
### 동적 도구 로딩
**목적:** 토큰 절약 + AI 선택 정확도 향상
```
사용자 메시지 → 키워드 패턴 매칭 → 관련 도구만 선택 → AI 호출
```
**카테고리 분류:**
| 카테고리 | 도구 | 감지 패턴 |
|----------|------|-----------|
| domain | manage_domain, suggest_domains | 도메인, 네임서버, whois, .com |
| deposit | manage_deposit | 입금, 충전, 잔액, 계좌 |
| server | manage_server | 서버, VPS, 클라우드, 호스팅 |
| weather | get_weather | 날씨, 기온, 비, 눈 |
| search | search_web, lookup_docs | 검색, 찾아, 뭐야, 가격 |
| utility | get_current_time, calculate | (항상 포함) |
**폴백:** 패턴 매칭 없으면 전체 도구 사용
---
## 4. Feature Systems
### 4.1 Deposit System
**아키텍처 변경 (2026-02-05):**
- **이전**: manage_deposit 도구 → 직접 코드 실행
- **현재**: manage_deposit 도구 → **Deposit Agent 위임** (세션 기반 상담)
**흐름:**
```
사용자: "잔액 확인해줘"
메인 AI → manage_deposit(action="balance") 호출
deposit-tool.ts: action → 자연어 변환 ("잔액 확인해줘")
Deposit Agent (금융 상담사 페르소나)
- 세션 생성/조회 (D1, TTL 30분)
- OpenAI Function Calling (get_balance, get_account_info, request_deposit)
- 도구 실행 → executeDepositFunction()
응답 반환 + 세션 저장
```
**Deposit Agent Function Calling:**
| 함수 | 설명 | 권한 |
|------|------|------|
| `get_balance` | 잔액 조회 | 모든 사용자 |
| `get_account_info` | 입금 계좌 안내 | 모든 사용자 |
| `request_deposit` | 입금 신고 (금액+입금자명 필수) | 모든 사용자 |
| `get_transactions` | 거래 내역 | 모든 사용자 |
| `cancel_transaction` | 입금 취소 | 모든 사용자 |
| `get_pending_list` | 대기 목록 | 관리자 |
| `confirm_deposit` | 입금 확인 | 관리자 |
| `reject_deposit` | 입금 거절 | 관리자 |
**스마트 파싱:**
- "홍길동 5만원 입금" → 금액(50000) + 입금자명(홍길동) 즉시 추출 → confirming 상태
- "3만원 입금" → 금액만 추출 → collecting_name 상태 (입금자명 요청)
- Agent가 세션 컨텍스트 유지, 대화형 정보 수집
**자동 매칭 흐름:**
```
[시나리오 1: 사용자 먼저]
"홍길동 50000원 입금" → bank_notifications 검색
매칭 O → confirmed + 잔액↑ | 매칭 X → pending
[시나리오 2: SMS 먼저 - Email Routing]
은행 SMS → Cloudflare Email Routing → Worker (email handler)
파싱 → bank_notifications 저장
deposit_transactions 검색 (pending)
매칭 O → confirmed + 잔액↑ + 알림
매칭 X → 저장만 + 관리자 알림
```
**매칭 로직 (7글자 제한):**
- 은행 SMS는 입금자명을 7글자까지만 표시
- 매칭 시 SUBSTR(depositor_name, 1, 7) 비교
- `deposit-agent.ts:72`, `index.ts:908` 구현
**Optimistic Locking:**
- `user_deposits.version` 컬럼으로 동시성 제어
- 잔액 변경 시 version 자동 증가
- 충돌 시 자동 재시도 (최대 3회, 지수 백오프)
- Double-spending 방지 (도메인 등록 결제 적용)
**Cron 자동 취소:**
- UTC 15:00 (KST 00:00) 매일 실행
- 24시간 이상 대기 중인 입금 요청 자동 취소
- 사용자에게 Telegram 알림 전송
**입금 계좌:** 하나은행 427-910018-27104 (주식회사 아이언클래드)
### 4.2 Domain System
**manage_domain 도구 파라미터:**
```typescript
{
action: 'register' | 'check' | 'whois' | 'list' | 'info' | 'get_ns' | 'set_ns' | 'price' | 'cheapest',
domain?: string,
nameservers?: string[],
tld?: string
}
```
**action별 처리:**
| action | 설명 | 권한 |
|--------|------|------|
| `list` | 내 도메인 목록 | 소유자 |
| `info` | 도메인 상세정보 | 소유자 |
| `get_ns` | 네임서버 조회 | 공개 |
| `set_ns` | 네임서버 변경 | 소유자 |
| `check` | 가용성 확인 + 가격 | 공개 |
| `whois` | WHOIS 조회 | 공개 |
| `price` | TLD 가격 | 공개 |
| `cheapest` | 가장 저렴한 TLD 목록 (TOP 15) | 공개 |
| `register` | 등록 확인 페이지 | 사용자 |
**등록 흐름 (인라인 버튼):**
```
사용자: "example.com 등록해줘"
executeDomainAction():
1. 가용성 확인 + 가격 조회
2. 잔액 확인
3. __KEYBOARD__ 마커 포함 응답 생성
telegram.ts: inline_keyboard 생성 → "✅ 등록 확인 / ❌ 취소" 버튼 표시
index.ts: callback_query 핸들러 → domain-register.ts 호출
domain-register.ts:
- 잔액 재확인
- Optimistic Locking으로 잔액 차감
- Namecheap API 호출
- user_domains 테이블에 등록
```
**도메인 추천 (`suggest_domains`):**
```
1. GPT-4o-mini: 키워드 기반 도메인 15개 생성
2. Namecheap API: 가용성 일괄 확인
3. 등록 가능 도메인 < 10개? → 재시도 (최대 3회)
4. TLD별 가격 조회 (병렬 처리)
5. 결과 포맷팅 (등록 가능한 것만 표시)
```
**Namecheap API:**
- 엔드포인트: `namecheap-api.anvil.it.com`
- 가격 정책: Namecheap 원가 + 13%, 매일 환율 업데이트
- WHOIS Guard 자동 적용 (개인정보 비공개)
### 4.3 Server System
**manage_server 도구 파라미터:**
```typescript
{
action: 'recommend' | 'order' | 'start' | 'stop' | 'delete' | 'list',
tech_stack?: string[], // recommend용
expected_users?: number, // recommend용
use_case?: string, // recommend용
traffic_pattern?: 'steady' | 'spiky' | 'growing',
region_preference?: string[],
budget_limit?: number,
lang?: 'ko' | 'ja' | 'zh' | 'en', // 자동 감지
server_id?: string, // order/start/stop/delete용
region_code?: string, // order용
label?: string // order용
}
```
**action별 상태:**
| action | 설명 | 상태 |
|--------|------|------|
| `recommend` | 서버 추천 | ✅ 구현 완료 |
| `order` | 서버 신청 | 🚧 준비 중 |
| `start` | 서버 시작 | 🚧 준비 중 |
| `stop` | 서버 중지 | 🚧 준비 중 |
| `delete` | 서버 해지 | 🚧 준비 중 |
| `list` | 내 서버 목록 | 🚧 준비 중 |
**Server Expert AI Flow (상담 기반 추천):**
```
사용자: "서버 추천해줘"
메인 AI → manage_server(action="start_consultation")
KV 세션 생성 (server_session:{userId}, TTL 1h)
Server Expert AI (gpt-4o-mini + Function Calling)
- 페르소나: 30년 경력 클라우드 아키텍트
- 용도/규모 파악 (최대 2번 질문)
- [선택] search_trends (Brave Search)
- [선택] lookup_framework_docs (Context7)
action="question" → 추가 정보 수집 (세션 유지)
action="recommend" → 자동 스펙 추론 → Cloud Orchestrator API 호출 → 세션 삭제
서버 추천 결과 반환
```
**자동 추론 (30년 경험 기반):**
| 용도 | 추론된 tech_stack | 추론된 expected_users |
|------|-------------------|---------------------|
| 블로그 / WordPress | `['wordpress']` | 100명 |
| 쇼핑몰 / 이커머스 | `['ecommerce']` | 500명 |
| 커뮤니티 / 게시판 | `['php', 'mysql']` | - |
| API / 백엔드 | `['nodejs', 'express']` | - |
| 기본값 | `['web']` | 100명 |
**추천 결과 포맷:**
```
🖥️ 서버 추천 결과
1⃣ Standard 8GB (Anvil)
• 스펙: 4vCPU / 8GB / 160GB SSD
• 리전: Tokyo 3 (JP)
• 가격: ₩69,719/월 (대역폭 5TB)
• 예상 트래픽: 1.7TB (포함 범위 내)
• 점수: 95점 / 최대 7,500명
```
**서버 주문 상태 전이:**
| 상태 | 설정 주체 | UI 표시 |
|------|----------|---------|
| `pending` | telegram-bot | ❌ 표시 안 함 |
| `provisioning` | cloud-orchestrator | ✅ 🔄 생성 중... |
| `active` | cloud-orchestrator | ✅ 🟢 가동 중 |
| `stopped` | cloud-orchestrator | ✅ ⛔ 중지됨 |
| `failed` | cloud-orchestrator | ❌ 표시 안 함 |
| `terminated` | telegram-bot | ❌ 표시 안 함 |
**Service Binding:** `CLOUD_ORCHESTRATOR``cloud-orchestrator` (wrangler.toml)
---
## 5. API & Security
### Endpoints
**공개 엔드포인트:**
| 엔드포인트 | 메서드 | 인증 | 용도 |
|-----------|--------|------|------|
| `/health` | GET | None | Health check (최소 정보만) |
| `/webhook-info` | GET | Query Param | Telegram Webhook 상태 조회 |
| `/setup-webhook` | GET | Query Param | Telegram Webhook 설정 |
**인증 필요 엔드포인트:**
| 엔드포인트 | 메서드 | 인증 방식 | 권한 |
|-----------|--------|----------|------|
| `/webhook` | POST | Telegram Secret Token | Telegram만 호출 가능 |
| `/api/deposit/balance` | GET | X-API-Key 헤더 | namecheap-api 전용 |
| `/api/deposit/deduct` | POST | X-API-Key 헤더 | namecheap-api 전용 |
| `/api/contact` | POST | CORS | hosting.anvil.it.com만 |
| `/api/metrics` | GET | Bearer Token | 관리자 전용 |
| `/api/test` | POST | WEBHOOK_SECRET | 테스트 전용 |
**인증 방식:**
- **API Key**: `X-API-Key: {DEPOSIT_API_SECRET}`
- **Bearer**: `Authorization: Bearer {WEBHOOK_SECRET}`
- **Query Param**: `?token={BOT_TOKEN}&secret={WEBHOOK_SECRET}`
- **CORS**: `hosting.anvil.it.com`만 허용
**External Consumers:**
- **namecheap-api**: `/api/deposit/*` 호출 (도메인 등록 시 잔액 조회/차감)
- **hosting.anvil.it.com**: `/api/contact` 호출 (웹사이트 문의 폼)
- **Monitoring Tools**: `/api/metrics` 조회 (Circuit Breaker 상태)
### Rate Limiting
**Cloudflare KV 기반:**
- 사용자별 메시지 제한: 30 requests / 60초
- KV Namespace: `RATE_LIMIT_KV`
- 인스턴스 간 공유, 재시작 후 유지
- 자동 만료 (TTL), 분산 환경 일관성 보장
- 과도한 요청 시 경고 메시지 + 차단
**관리자 알림 Rate Limiting:**
- 같은 유형의 알림은 1시간에 1회만 전송
- 키: `notification:{type}:{service}`
- TTL: 3600초
### Admin Notification
**알림 유형:**
| 유형 | 트리거 조건 | 심각도 |
|------|------------|--------|
| `circuit_breaker` | Circuit Breaker OPEN 상태 전환 | 🚨 HIGH |
| `retry_exhausted` | 모든 재시도 실패 (3회) | ⚠️ MEDIUM |
| `api_error` | 치명적 API 에러 (5xx, Rate Limit) | 🔴 CRITICAL |
**통합 지점:**
- `utils/circuit-breaker.ts`: Circuit 차단 시
- `utils/retry.ts`: 재시도 실패 시
- `openai-service.ts`: OpenAI API 에러 시
- `tools/*.ts`: 외부 API 에러 시
---
## 6. Development
### Code Style
**TypeScript:**
- Strict mode 활성화 (`tsconfig.json`)
- 타입 정의: `types.ts`에 인터페이스 집중 관리
- any 사용 금지 (불가피한 경우 주석으로 이유 명시)
**네이밍:**
- 파일: `kebab-case.ts` (예: `openai-service.ts`)
- 함수: `camelCase` (예: `executeFunctionCall`)
- 상수: `UPPER_SNAKE_CASE` (예: `SUMMARY_THRESHOLD`)
- 타입/인터페이스: `PascalCase` (예: `TelegramUpdate`)
**에러 핸들링:**
```typescript
import { createLogger } from './utils/logger';
const logger = createLogger('service-name');
try {
// 작업
} catch (error) {
logger.error('작업 실패', error as Error, { context: 'data' });
return '죄송합니다. 일시적인 오류가 발생했습니다.';
}
```
**로깅:**
```typescript
import { createLogger } from './utils/logger';
const logger = createLogger('service-name');
logger.info('동작 설명', { key: 'value' });
logger.error('에러 설명', error as Error);
logger.warn('경고 메시지', { context: 'data' });
const end = logger.startTimer('작업 완료');
await doWork();
end(); // duration 자동 기록
```
### Testing
**자동화된 단위 테스트 (Vitest):**
**실행 명령어:**
```bash
npm test # 모든 테스트 실행
npm run test:watch # Watch 모드
npm run test:coverage # 커버리지 리포트
```
**테스트 범위:**
| 기능 | 테스트 케이스 | 상태 |
|------|--------------|------|
| **음수 금액 거부** | 음수/0원 입금 시도 | ✅ |
| **동시성 처리** | 동일 사용자 동시 입금, Race condition | ✅ |
| **Batch 실패 처리** | db.batch() 부분 실패 시뮬레이션 | ✅ |
| **7글자 매칭** | "홍길동아버지님" → "홍길동아버지" 자동 매칭 | ✅ |
| **관리자 권한** | 비관리자 confirm/reject/pending 차단 | ✅ |
| **거래 상태** | confirmed 거래 취소 차단 | ✅ |
| **Edge Cases** | 999,999,999원, 특수문자, 1글자 이름 | ✅ |
**Mock 전략:**
- D1 Database: Miniflare in-memory SQLite
- Environment Variables: `vitest.config.ts`에서 바인딩
- KV Namespace: Rate Limiting 모킹
**헬퍼 함수 (`tests/setup.ts`):**
```typescript
createTestUser(telegramId, username)
createBankNotification(depositorName, amount)
createDepositTransaction(userId, amount, status)
getTestDB()
```
**수동 테스트 (Webhook):**
```bash
# 1. 로컬 D1 초기화 (최초 1회)
npm run db:init:local
# 2. 로컬 서버 실행
npm run dev
# 3. 테스트 요청
curl -X POST http://localhost:8787/webhook \
-H "Content-Type: application/json" \
-H "X-Telegram-Bot-Api-Secret-Token: test-secret" \
-d '{"message":{"chat":{"id":123},"text":"테스트"}}'
```
**Web Chat Testing:** [telegram-cli/README.md](../telegram-cli/README.md) - 봇 테스트용 별도 Worker
---
## 7. Configuration
### Environment Variables (wrangler.toml)
**기본 설정:**
| 변수 | 기본값 | 설명 |
|------|--------|------|
| `SUMMARY_THRESHOLD` | 20 | 프로필 업데이트 주기 (메시지 수) |
| `MAX_SUMMARIES_PER_USER` | 3 | 유지할 프로필 버전 수 |
| `DOMAIN_OWNER_ID` | - | 도메인 관리 권한 Telegram ID |
| `DEPOSIT_ADMIN_ID` | - | 예치금 관리 권한 Telegram ID |
**외부 API 엔드포인트 (커스터마이징 가능):**
| 변수 | 기본값 |
|------|--------|
| `OPENAI_API_BASE` | `https://gateway.ai.cloudflare.com/v1/.../openai` |
| `NAMECHEAP_API_URL` | `https://namecheap-api.anvil.it.com` |
| `WHOIS_API_URL` | `https://whois-api-...vercel.app` |
| `CONTEXT7_API_BASE` | `https://context7.com/api/v2` |
| `BRAVE_API_BASE` | `https://api.search.brave.com/res/v1` |
| `WTTR_IN_URL` | `https://wttr.in` |
| `HOSTING_SITE_URL` | `https://hosting.anvil.it.com` |
### Secrets
| 변수 | 설명 | 저장 위치 |
|------|------|----------|
| `BOT_TOKEN` | Telegram Bot Token | Vault: telegram-bot |
| `WEBHOOK_SECRET` | Telegram Webhook 인증 | Vault: telegram-bot |
| `OPENAI_API_KEY` | OpenAI API 키 | - |
| `NAMECHEAP_API_KEY` | namecheap-api 래퍼 인증 | - |
| `NAMECHEAP_API_KEY_INTERNAL` | Namecheap API 키 (내부) | - |
| `BRAVE_API_KEY` | Brave Search API 키 | - |
| `DEPOSIT_API_SECRET` | Deposit API 인증 | - |
### Bindings
**KV Namespaces:**
| Binding | 설명 |
|---------|------|
| `RATE_LIMIT_KV` | Rate Limiting 저장소 |
| `SESSION_KV` | 서버 상담 세션 저장소 |
**Other Bindings:**
| Binding | 타입 | 용도 |
|---------|------|------|
| `DB` | D1 Database | 사용자/메시지/예치금 데이터 |
| `AI` | Workers AI | OpenAI 폴백용 (Llama 3.1 8B) |
| `CLOUD_ORCHESTRATOR` | Service Binding | 서버 관리 Worker |
### External Integrations
| 서비스 | 용도 | 엔드포인트 | 주의사항 |
|--------|------|-----------|----------|
| **AI Gateway** | OpenAI 프록시 | gateway.ai.cloudflare.com | 지역 제한 우회, 로그/캐시 |
| Context7 | 문서 조회 | context7.com API | - |
| Namecheap API | 도메인 백엔드 | namecheap-api.anvil.it.com | 날짜: MM/DD/YYYY → ISO 변환 |
| WHOIS API | WHOIS 조회 | whois-api-eight.vercel.app | ccSLD 미지원 |
| wttr.in | 날씨 | wttr.in | - |
| Brave Search | 검색 | api.search.brave.com | Free AI 플랜 (2,000/월) |
| Email Routing | 입금 SMS 수신 | Cloudflare Email Routing | Worker email handler로 직접 처리 |
**Cloudflare AI Gateway:**
```
Gateway ID: telegram-bot
Account ID: d8e5997eb4040f8b489f09095c0f623c
URL: gateway.ai.cloudflare.com/v1/{account_id}/telegram-bot/openai/...
```
**적용 범위:**
- ✅ Chat Completions - AI Gateway 경유
- ✅ 예치금 관리 - 코드 직접 처리 (Assistants API 제거)
- ✅ 도메인 관리 - 코드 직접 처리
---
## 8. Troubleshooting
### 자주 발생하는 에러
| 증상 | 원인 | 해결 |
|------|------|------|
| `D1_ERROR: no such table` | 스키마 미적용 | `npm run db:init` 실행 |
| `401 Unauthorized` (OpenAI) | API 키 만료/잘못됨 | `wrangler secret put OPENAI_API_KEY` |
| Webhook 응답 없음 | Secret Token 불일치 | `WEBHOOK_SECRET` 재설정 후 `/setup-webhook` |
| Function Calling 무한 루프 | tool_choice 설정 오류 | `tool_choice: "auto"` 확인 |
| 프로필 업데이트 안됨 | 메시지 20개 미만 | `/context`로 버퍼 수 확인 |
| Email Worker 파싱 실패 | SMS 형식 변경 | `index.ts`의 정규식 패턴 확인 |
| AI가 도구 호출 안 함 | 키워드 미인식 | 시스템 프롬프트 + 도구 description에 키워드 추가 |
| CORS 오류 (웹사이트 문의) | 허용된 Origin 아님 | `hosting.anvil.it.com`만 허용됨 |
### 디버깅 명령어
```bash
# D1 데이터 직접 조회 (로컬)
wrangler d1 execute telegram-conversations --local --command "SELECT * FROM users LIMIT 5"
# D1 데이터 직접 조회 (production) ⚠️ 주의
wrangler d1 execute telegram-conversations --command "SELECT * FROM users LIMIT 5"
```
---
## 9. Key Patterns
### Function Calling 추가 방법
```typescript
// 1. openai-service.ts의 tools 배열에 추가
const tools = [
{
type: "function",
function: {
name: "new_tool",
description: "도구 설명 (트리거 키워드 포함)",
parameters: { /* JSON Schema */ }
}
}
];
// 2. executeFunctionCall()에 케이스 추가
case 'new_tool':
return await executeNewTool(args, env);
```
### 프로필 시스템 (3개 요약 통합)
```
메시지 수신 → message_buffer 저장 (최대 19개)
↓ 20개 도달
┌──────────────┴──────────────┐
↓ ↓
기존 요약 3개 조회 사용자 발언만 추출
↓ ↓
└──────────→ OpenAI 통합 분석 ←┘
summaries 테이블 저장 (generation++)
구버전 삭제 (최근 3개만 유지)
```
**Context Enrichment:**
```typescript
// getConversationContext() 반환값
{
previousSummary: Summary | null, // 최신 요약 (호환성)
summaries: Summary[], // 전체 요약 (최대 3개, 최신순)
recentMessages: BufferedMessage[],
totalMessages: number,
}
```
### AI 시스템 프롬프트
**핵심 규칙 (`summary-service.ts`):**
```
- 날씨, 시간, 계산 요청은 제공된 도구를 사용하세요.
- 최신 정보, 실시간 데이터, 현재 가격, 뉴스 등은 search_web 도구로 검색하세요.
- 예치금, 입금, 충전, 잔액, 계좌 관련 요청은 반드시 manage_deposit 도구를 사용하세요.
- 도메인 추천, 도메인 제안, 도메인 아이디어 요청은 반드시 suggest_domains 도구를 사용하세요.
- 기타 도메인 관련 요청(조회, 등록, 네임서버 등)은 manage_domain 도구를 사용하세요.
- 서버, VPS, 클라우드, 호스팅 추천 요청은 반드시 manage_server 도구를 사용하세요.
- manage_deposit, manage_domain, suggest_domains, manage_server 도구 결과는 그대로 전달하세요.
```
**중요:** 메인 AI가 도구를 호출하지 않고 직접 답변하는 경우:
1. 시스템 프롬프트에 해당 키워드 추가 (`summary-service.ts`)
2. 도구 description에 키워드 명시 (`openai-service.ts` tools 배열)
### 검색 한글→영문 자동 번역
```
"판골린 VPN" → GPT-4o-mini 번역 → "Pangolin VPN" → Brave Search
```
- 한글 포함 검색어 감지 (`/[가-힣]/`)
- GPT-4o-mini로 영문 번역 (외래어/기술용어 원어 복원)
- 번역된 쿼리로 검색
- 결과에 원본+번역 표시
### 에러 핸들링 구조 (index.ts:handleMessage)
```
Webhook 수신
보안 검증 실패 → 401 반환 (로그 기록)
Rate Limit 초과 → 경고 메시지 전송 + return
사용자 DB 조회/생성 (try-catch)
↓ 실패 시 → "일시적인 오류" 메시지 전송 + return
메시지 처리 (전체 try-catch)
├── 명령어 처리 (handleCommand)
└── AI 응답 생성 (generateAIResponse)
↓ 실패 시 → "메시지 처리 오류" 메시지 전송
응답 전송 (sendMessage)
```
**중요:** 모든 DB 작업과 AI 호출은 try-catch로 감싸서 오류 시에도 사용자에게 메시지 전송
---
## OpenAPI Documentation
**OpenAPI Specification**: `openapi.yaml`
**문서 보기:**
```bash
npx swagger-ui-watcher openapi.yaml # Swagger UI
npx redoc-cli bundle openapi.yaml -o docs/api.html # Redoc HTML
npx @apidevtools/swagger-cli validate openapi.yaml # 스펙 검증
```