refactor: migrate server provisioning to Cloud Orchestrator service
- Remove Queue-based server provisioning (moved to cloud-orchestrator) - Add manage_server tool with Service Binding to Cloud Orchestrator - Add CDN cache hit rate estimation based on tech_stack - Always display bandwidth info (show "포함 범위 내" when no overage) - Add language auto-detection (ko, ja, zh, en) - Update system prompt to always call tools fresh - Add Server System documentation to CLAUDE.md BREAKING: Server provisioning now requires cloud-orchestrator service Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
366
CLAUDE.md
366
CLAUDE.md
@@ -190,24 +190,11 @@ npm run deploy # Cloudflare Workers 배포
|
||||
npm run db:init # D1 스키마 초기화 (production) ⚠️ 주의
|
||||
npm run db:init:local # D1 스키마 초기화 (local)
|
||||
npm run tail # Workers 로그 스트리밍
|
||||
npm run chat # CLI 테스트 클라이언트
|
||||
npm test # 단위 테스트 실행 (Vitest)
|
||||
npm run test:watch # Watch 모드
|
||||
npm run test:coverage # 커버리지 리포트
|
||||
```
|
||||
|
||||
**CLI 테스트 클라이언트:**
|
||||
```bash
|
||||
# .env 파일 생성 (최초 1회)
|
||||
echo 'WEBHOOK_SECRET=...' > .env # Vault: secret/data/telegram-bot
|
||||
|
||||
# 대화형 모드
|
||||
npm run chat
|
||||
|
||||
# 단일 메시지 모드
|
||||
npm run chat "날씨 알려줘"
|
||||
```
|
||||
|
||||
**KV Namespace 생성 (최초 1회):**
|
||||
```bash
|
||||
# Rate Limiting용 KV Namespace 생성
|
||||
@@ -215,17 +202,6 @@ wrangler kv:namespace create RATE_LIMIT_KV
|
||||
# 출력된 id를 wrangler.toml의 [[kv_namespaces]] 섹션에 입력
|
||||
```
|
||||
|
||||
**Queue 생성 (최초 1회):**
|
||||
```bash
|
||||
# 서버 프로비저닝용 Queue 생성
|
||||
wrangler queues create server-provision-queue
|
||||
wrangler queues create provision-dlq
|
||||
|
||||
# Queue 상태 확인
|
||||
wrangler queues list
|
||||
wrangler queues describe server-provision-queue
|
||||
```
|
||||
|
||||
**Secrets 설정:**
|
||||
```bash
|
||||
wrangler secret put BOT_TOKEN # Telegram Bot Token
|
||||
@@ -235,9 +211,6 @@ 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 인증 키
|
||||
wrangler secret put LINODE_API_KEY # Linode API 키
|
||||
wrangler secret put VULTR_API_KEY # Vultr API 키
|
||||
wrangler secret put SERVER_ADMIN_ID # 서버 관리 알림 Telegram ID
|
||||
```
|
||||
|
||||
**Webhook 설정:**
|
||||
@@ -266,8 +239,6 @@ wrangler d1 execute telegram-conversations --file=migrations/001_rollback.sql
|
||||
|------|------|--------|
|
||||
| `001_optimize_prefix_indexes.sql` | 입금자명 prefix 인덱스 최적화 (99% 성능 향상) | 2026-01-19 |
|
||||
| `002_add_version_columns.sql` | Optimistic Locking (user_deposits.version) | 2026-01-20 |
|
||||
| `003_add_server_tables.sql` | 서버 관리 시스템 테이블 추가 | 2026-01-23 |
|
||||
| `004_seed_server_data.sql` | 서버 제공자/사양 초기 데이터 | 2026-01-23 |
|
||||
|
||||
**마이그레이션 작업 내용 (001):**
|
||||
- `deposit_transactions.depositor_name_prefix` 컬럼 추가
|
||||
@@ -422,6 +393,107 @@ curl "https://telegram-summary-bot.kappa-d8e.workers.dev/webhook-info?token=${BO
|
||||
|
||||
---
|
||||
|
||||
## Web Chat Testing (telegram-cli)
|
||||
|
||||
**목적:** Claude Code가 봇과 대화하여 기능을 테스트할 때 사용
|
||||
|
||||
### API 엔드포인트
|
||||
|
||||
```bash
|
||||
# 봇과 대화
|
||||
curl -s -X POST 'https://telegram-cli-web.kappa-d8e.workers.dev/api/chat' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"message": "안녕"}'
|
||||
```
|
||||
|
||||
**응답 형식:**
|
||||
```json
|
||||
{
|
||||
"response": "봇 응답 텍스트...",
|
||||
"time_ms": 1234
|
||||
}
|
||||
```
|
||||
|
||||
### Claude가 사용하는 경우
|
||||
|
||||
**테스트 시나리오:**
|
||||
```bash
|
||||
# 1. 기본 대화
|
||||
curl -X POST 'https://telegram-cli-web.kappa-d8e.workers.dev/api/chat' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"message": "안녕하세요"}'
|
||||
|
||||
# 2. 예치금 기능
|
||||
curl -X POST 'https://telegram-cli-web.kappa-d8e.workers.dev/api/chat' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"message": "잔액 조회"}'
|
||||
|
||||
# 3. 도메인 기능
|
||||
curl -X POST 'https://telegram-cli-web.kappa-d8e.workers.dev/api/chat' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"message": "example.com 조회"}'
|
||||
|
||||
# 4. Function Calling 도구
|
||||
curl -X POST 'https://telegram-cli-web.kappa-d8e.workers.dev/api/chat' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"message": "서울 날씨"}'
|
||||
```
|
||||
|
||||
### 다른 엔드포인트
|
||||
|
||||
| 엔드포인트 | 메서드 | 설명 |
|
||||
|-----------|--------|------|
|
||||
| `/` | GET | 웹 채팅 UI (브라우저) |
|
||||
| `/health` | GET | Health check |
|
||||
|
||||
### 배포 정보
|
||||
|
||||
**Worker URL**: https://telegram-cli-web.kappa-d8e.workers.dev
|
||||
**별도 Worker**: 메인 봇과 독립적으로 배포됨
|
||||
**상세 문서**: [telegram-cli/README.md](../telegram-cli/README.md)
|
||||
|
||||
**Secrets 필요:**
|
||||
- `BOT_TOKEN`: Telegram Bot Token (Vault: telegram-bot)
|
||||
- `WEBHOOK_SECRET`: Bot Worker /api/test 인증용 (Vault: telegram-bot)
|
||||
|
||||
**배포 명령:**
|
||||
```bash
|
||||
cd telegram-cli
|
||||
npm install
|
||||
wrangler secret put BOT_TOKEN
|
||||
wrangler secret put WEBHOOK_SECRET
|
||||
npm run deploy
|
||||
```
|
||||
|
||||
### 아키텍처
|
||||
|
||||
```
|
||||
Claude Code (또는 브라우저)
|
||||
↓
|
||||
POST /api/chat → telegram-cli Worker
|
||||
↓
|
||||
Bot Worker (/api/test)
|
||||
- 메인 봇과 동일한 로직
|
||||
- DB 저장/조회
|
||||
- AI 응답 생성
|
||||
- Function Calling
|
||||
↓
|
||||
응답 반환 { response, time_ms }
|
||||
```
|
||||
|
||||
**특징:**
|
||||
- 별도 Worker로 분리되어 메인 봇에 영향 없음
|
||||
- 동일한 Bot Worker의 /api/test 엔드포인트 호출
|
||||
- 응답 시간 측정 자동 포함
|
||||
- username: 'web-tester'로 자동 설정
|
||||
|
||||
**사용 사례:**
|
||||
- Claude Code가 봇 기능 테스트
|
||||
- 개발자가 브라우저에서 빠른 테스트
|
||||
- CI/CD 파이프라인에서 자동 테스트
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### 자주 발생하는 에러
|
||||
@@ -614,7 +686,7 @@ Telegram Webhook → Security Validation → Command/Message Router
|
||||
**Core Services:**
|
||||
| 파일 | 역할 | 주요 함수 |
|
||||
|------|------|----------|
|
||||
| `index.ts` | Worker 진입점, Email Handler, Queue Handler | `fetch()`, `email()`, `queue()` |
|
||||
| `index.ts` | Worker 진입점, Email Handler | `fetch()`, `email()` |
|
||||
| `openai-service.ts` | AI 응답 + Function Calling | `generateResponse()`, `executeFunctionCall()` |
|
||||
| `summary-service.ts` | 프로필 시스템 | `updateSummary()`, `getConversationContext()` |
|
||||
| `deposit-agent.ts` | 예치금 함수 (코드 직접 처리) | `executeDepositFunction()` |
|
||||
@@ -622,9 +694,6 @@ Telegram Webhook → Security Validation → Command/Message Router
|
||||
| `services/notification.ts` | 관리자 알림 (Circuit Breaker, Retry 실패) | `notifyAdmin()` |
|
||||
| `commands.ts` | 봇 명령어 | `handleCommand()` |
|
||||
| `telegram.ts` | Telegram API | `sendMessage()`, `sendTypingAction()` |
|
||||
| `queue/provision-consumer.ts` | 서버 생성 Queue Consumer | `handleProvisionQueue()` |
|
||||
| `queue/provision-dlq.ts` | Dead Letter Queue 핸들러 (환불 처리) | `handleProvisionDLQ()` |
|
||||
| `server-provision.ts` | 서버 프로비저닝 로직 | `executeServerProvision()` |
|
||||
|
||||
**Logging & Monitoring (Phase 5-3):**
|
||||
| 파일 | 역할 | 주요 기능 |
|
||||
@@ -658,7 +727,7 @@ end(); // duration 자동 기록
|
||||
| 도메인 | `manage_domain` | 코드 직접 처리 → Namecheap | 도메인, 네임서버, WHOIS |
|
||||
| 도메인 추천 | `suggest_domains` | GPT + Namecheap | **도메인 추천, 도메인 제안, 도메인 아이디어** |
|
||||
| 예치금 | `manage_deposit` | 코드 직접 처리 | **입금, 충전, 잔액, 계좌, 송금** |
|
||||
| 서버 | `manage_server` | Linode/Vultr API | **서버, VPS, 클라우드, 인스턴스** |
|
||||
| 서버 | `manage_server` | Cloud Orchestrator (Service Binding) | **서버, VPS, 클라우드, 호스팅** |
|
||||
|
||||
**Data Layer (D1 SQLite):**
|
||||
| 테이블 | 용도 | 주요 컬럼 |
|
||||
@@ -670,16 +739,6 @@ end(); // duration 자동 기록
|
||||
| `deposit_transactions` | 거래 내역 | user_id, amount, status |
|
||||
| `bank_notifications` | SMS 파싱 | depositor_name, amount, bank |
|
||||
| `user_domains` | 도메인 소유권 | user_id, domain, verified (등록 시 자동 추가) |
|
||||
| `cloud_providers` | 클라우드 제공자 | name, api_base_url, enabled |
|
||||
| `instance_specs` | 서버 사양표 | plan_id, vcpus, memory_mb, price_krw, regions |
|
||||
| `server_orders` | 서버 주문 내역 | user_id, provider_id, status, ip_address |
|
||||
| `user_servers` | 서버 소유권 | user_id, provider_instance_id, verified |
|
||||
|
||||
**Queue System (Server Provisioning):**
|
||||
| Queue | 역할 | Consumer |
|
||||
|-------|------|----------|
|
||||
| `server-provision-queue` | 서버 생성 요청 큐 | provision-consumer.ts |
|
||||
| `provision-dlq` | 실패한 요청 (환불 처리) | provision-dlq.ts |
|
||||
|
||||
**AI Fallback:** OpenAI 미설정 시 Workers AI (Llama 3.1 8B) 자동 전환
|
||||
|
||||
@@ -831,7 +890,6 @@ case 'new_tool':
|
||||
| `MAX_SUMMARIES_PER_USER` | 3 | 유지할 프로필 버전 수 |
|
||||
| `DOMAIN_OWNER_ID` | - | 도메인 관리 권한 Telegram ID |
|
||||
| `DEPOSIT_ADMIN_ID` | - | 예치금 관리 권한 Telegram ID |
|
||||
| `SERVER_ADMIN_ID` | - | 서버 관리 권한 Telegram ID |
|
||||
|
||||
**외부 API 엔드포인트 (커스터마이징 가능):**
|
||||
| 변수 | 기본값 | 설명 |
|
||||
@@ -858,9 +916,6 @@ case 'new_tool':
|
||||
| `NAMECHEAP_API_KEY_INTERNAL` | Namecheap API 키 (내부) | - |
|
||||
| `BRAVE_API_KEY` | Brave Search API 키 | - |
|
||||
| `DEPOSIT_API_SECRET` | Deposit API 인증 | - |
|
||||
| `LINODE_API_KEY` | Linode API 키 | - |
|
||||
| `VULTR_API_KEY` | Vultr API 키 | - |
|
||||
| `SERVER_ADMIN_ID` | 서버 관리 알림 Telegram ID | - |
|
||||
|
||||
**KV Namespaces:**
|
||||
| Binding | 설명 | 생성 명령 |
|
||||
@@ -1159,6 +1214,71 @@ wrangler d1 execute telegram-conversations --command "SELECT user_id, balance, v
|
||||
|
||||
---
|
||||
|
||||
## Server System
|
||||
|
||||
**목적:** 클라우드 서버 추천 및 관리 (Cloud Orchestrator 연동)
|
||||
|
||||
**연결 방식:** Cloudflare Service Binding (Worker-to-Worker 직접 통신)
|
||||
|
||||
**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` | 내 서버 목록 | 🚧 준비 중 |
|
||||
|
||||
**추천 결과 포맷:**
|
||||
```
|
||||
🖥️ 서버 추천 결과
|
||||
|
||||
1️⃣ Standard 8GB (Anvil)
|
||||
• 스펙: 4vCPU / 8GB / 160GB SSD
|
||||
• 리전: Tokyo 3 (JP)
|
||||
• 가격: ₩69,719/월 (대역폭 5TB)
|
||||
• 예상 트래픽: 1.7TB (포함 범위 내) ← 항상 표시
|
||||
• 점수: 95점 / 최대 7,500명
|
||||
```
|
||||
|
||||
**대역폭 정보 표시 규칙:**
|
||||
- 초과 없음: `예상 트래픽: X.XTB (포함 범위 내)`
|
||||
- 초과 있음: `예상 트래픽: X.XTB → 초과 X.XTB (₩X,XXX)`
|
||||
|
||||
**CDN 캐시 히트율 추정:**
|
||||
- tech_stack에 `cloudflare`, `cdn` 등 포함 시 자동 적용
|
||||
- 비디오 스트리밍: 92%, 정적 사이트: 95%, API: 30%, 이커머스: 70%
|
||||
|
||||
**언어 자동 감지:**
|
||||
- 한글 → `ko`, 히라가나/가타카나 → `ja`, 한자 → `zh`, 기본값 → `en`
|
||||
|
||||
**Service Binding 설정 (wrangler.toml):**
|
||||
```toml
|
||||
[[services]]
|
||||
binding = "CLOUD_ORCHESTRATOR"
|
||||
service = "cloud-orchestrator"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Domain System
|
||||
|
||||
**아키텍처 변경 (2025-01):** Agent 기반 → 코드 직접 처리
|
||||
@@ -1310,153 +1430,3 @@ POST /api/deposit/deduct # 잔액 차감
|
||||
{ telegram_id, amount, reason }
|
||||
Header: X-API-Key: DEPOSIT_API_SECRET
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Server System (Queue-based Provisioning)
|
||||
|
||||
**아키텍처:** Queue 기반 비동기 처리로 긴 프로비저닝 작업 대응
|
||||
|
||||
### Queue 기반 비동기 처리 흐름
|
||||
|
||||
```
|
||||
사용자: "서버 생성해줘"
|
||||
↓
|
||||
메인 AI: manage_server(action="order", ...)
|
||||
↓
|
||||
1. 잔액 확인 + 차감 (즉시)
|
||||
2. server_orders 테이블에 status='pending' 저장
|
||||
3. Queue에 메시지 전송 (SERVER_PROVISION_QUEUE.send())
|
||||
↓
|
||||
사용자 응답: "⏳ 서버 생성 요청 접수 (#123)"
|
||||
↓
|
||||
┌───────────────────────────────────┐
|
||||
│ Queue Consumer (비동기 처리) │
|
||||
│ provision-consumer.ts │
|
||||
└───────────────────────────────────┘
|
||||
↓
|
||||
executeServerProvision():
|
||||
1. Linode/Vultr API 호출 (5-30초 소요)
|
||||
2. DB 업데이트: status='completed', ip_address, root_password
|
||||
3. user_servers 테이블에 소유권 추가
|
||||
↓
|
||||
성공 시 → 사용자 알림 (IP, 비밀번호)
|
||||
실패 시 → 재시도 (최대 3회) → DLQ
|
||||
```
|
||||
|
||||
### 보안 개선사항
|
||||
|
||||
**비밀번호 보안:**
|
||||
```typescript
|
||||
// ❌ 이전: 평문 저장 (보안 취약)
|
||||
root_password: string
|
||||
|
||||
// ✅ 현재: 해시 저장 + 일회성 전송
|
||||
root_password_hash: string // DB 저장용 (bcrypt)
|
||||
root_password: string // Queue 메시지에만 포함 (사용자 알림 후 파기)
|
||||
```
|
||||
|
||||
**Queue 메시지 구조:**
|
||||
```typescript
|
||||
interface ProvisionMessage {
|
||||
order_id: number;
|
||||
user_id: number;
|
||||
telegram_user_id: number;
|
||||
chat_id: number;
|
||||
}
|
||||
```
|
||||
|
||||
### Retry & DLQ 정책
|
||||
|
||||
**재시도 정책 (wrangler.toml):**
|
||||
```toml
|
||||
[[queues.consumers]]
|
||||
queue = "server-provision-queue"
|
||||
max_retries = 3 # 최대 3회 재시도
|
||||
max_batch_size = 1 # 순차 처리
|
||||
max_batch_timeout = 30 # 30초 타임아웃
|
||||
max_concurrency = 3 # 최대 3개 동시 처리
|
||||
dead_letter_queue = "provision-dlq"
|
||||
```
|
||||
|
||||
**retryable 플래그:**
|
||||
```typescript
|
||||
// provision-consumer.ts에서 활용
|
||||
if (result.retryable === false) {
|
||||
// 재시도하면 안 되는 경우 (예: 잘못된 파라미터)
|
||||
message.ack(); // DLQ로 보내지 않고 종료
|
||||
} else {
|
||||
// 일시적 오류 - 재시도 (max 3회 → DLQ)
|
||||
message.retry();
|
||||
}
|
||||
```
|
||||
|
||||
**DLQ 처리 (provision-dlq.ts):**
|
||||
```
|
||||
1. DB 상태 업데이트: status='failed'
|
||||
2. 잔액 환불 처리 (이미 차감된 경우)
|
||||
- user_deposits.balance 복원
|
||||
- deposit_transactions에 'refund' 거래 추가
|
||||
3. 사용자 알림 (환불 정보 포함)
|
||||
4. 관리자 알림 (notifyAdmin)
|
||||
5. DLQ에서 제거 (ack) - 무한 루프 방지
|
||||
```
|
||||
|
||||
### 관련 파일
|
||||
|
||||
| 파일 | 역할 |
|
||||
|------|------|
|
||||
| `queue/provision-consumer.ts` | Queue Consumer (서버 생성 실행) |
|
||||
| `queue/provision-dlq.ts` | DLQ 핸들러 (환불 처리) |
|
||||
| `server-provision.ts` | 실제 프로비저닝 로직 (Linode/Vultr API 호출) |
|
||||
| `index.ts:queue()` | Queue 메시지 라우팅 |
|
||||
|
||||
### manage_server 도구 파라미터
|
||||
|
||||
```typescript
|
||||
{
|
||||
action: 'list' | 'search' | 'order' | 'info' | 'recommend',
|
||||
provider?: 'linode' | 'vultr',
|
||||
plan?: string,
|
||||
region?: string,
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
### 사용자 알림 메시지 예시
|
||||
|
||||
**성공:**
|
||||
```
|
||||
🎉 서버 생성 완료!
|
||||
|
||||
주문번호: #123
|
||||
|
||||
📋 서버 정보
|
||||
• 사양: Linode 2GB
|
||||
• 리전: Tokyo 2
|
||||
• IP 주소: 203.0.113.5
|
||||
• 인스턴스 ID: 12345678
|
||||
|
||||
🔐 접속 정보
|
||||
• Root 비밀번호: [REDACTED]
|
||||
|
||||
📌 SSH 접속 명령어
|
||||
ssh root@203.0.113.5
|
||||
|
||||
⚠️ 보안 안내
|
||||
• 비밀번호는 이 메시지에서만 확인 가능합니다.
|
||||
• 접속 후 즉시 변경해주세요.
|
||||
```
|
||||
|
||||
**실패 (DLQ):**
|
||||
```
|
||||
❌ 서버 생성 실패
|
||||
|
||||
주문번호: #123
|
||||
|
||||
일시적인 문제로 서버를 생성할 수 없습니다.
|
||||
|
||||
✅ 결제 금액이 환불되었습니다.
|
||||
|
||||
관리자가 확인 후 연락드리겠습니다.
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user