feat: add region diversity, HTML report, and transfer pricing
Region Diversity: - No region specified → same spec from 3 different regions - Cache key now includes region_preference - Fixed server_id to use ap.id (pricing) instead of ai.id (instance) HTML Report: - New /api/recommend/report endpoint for printable reports - Supports multi-language (en, ko, ja, zh) - Displays bandwidth_info with proper KRW formatting Transfer Pricing: - bandwidth_info includes overage costs from anvil_transfer_pricing - available_regions shows alternative regions with prices Code Quality: - Extracted region-utils.ts for flexible region matching - Cleaned up AI prompt (removed obsolete provider references) - Renamed project to cloud-orchestrator Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
96
CLAUDE.md
96
CLAUDE.md
@@ -6,7 +6,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
||||
|
||||
Cloudflare Worker-based AI server recommendation service. Uses OpenAI GPT-4o-mini (via AI Gateway), D1 database, KV cache, and VPS benchmark data to recommend cost-effective servers based on natural language requirements.
|
||||
|
||||
**Production URL**: `https://server-recommend.kappa-d8e.workers.dev`
|
||||
**Production URL**: `https://cloud-orchestrator.kappa-d8e.workers.dev`
|
||||
|
||||
## Commands
|
||||
|
||||
@@ -34,10 +34,12 @@ src/
|
||||
├── config.ts # Configuration constants
|
||||
├── types.ts # TypeScript type definitions
|
||||
├── utils.ts # Utilities (bandwidth, response, AI, benchmarks, candidates, techSpecs)
|
||||
├── region-utils.ts # Region matching utilities (flexible region conditions)
|
||||
└── handlers/
|
||||
├── health.ts # GET /api/health
|
||||
├── servers.ts # GET /api/servers - List servers with filtering
|
||||
└── recommend.ts # POST /api/recommend - AI-powered recommendations
|
||||
├── recommend.ts # POST /api/recommend - AI-powered recommendations
|
||||
└── report.ts # GET /api/recommend/report - HTML report generation
|
||||
```
|
||||
|
||||
### Key Data Flow
|
||||
@@ -52,9 +54,10 @@ src/
|
||||
### D1 Database Tables (cloud-instances-db)
|
||||
|
||||
**Primary tables (Anvil pricing)**:
|
||||
- `anvil_instances` - Anvil server specifications (vcpus, memory_gb, disk_gb, etc.)
|
||||
- `anvil_instances` - Anvil server specifications (vcpus, memory_gb, disk_gb, transfer_tb, etc.)
|
||||
- `anvil_regions` - Anvil data center regions (name, display_name, country_code)
|
||||
- `anvil_pricing` - Anvil pricing data (monthly_price in USD)
|
||||
- `anvil_transfer_pricing` - Transfer/bandwidth overage pricing by region (price_per_gb in USD)
|
||||
|
||||
**Support tables**:
|
||||
- `tech_specs` - Resource requirements per technology (vcpu_per_users, min_memory_mb)
|
||||
@@ -93,7 +96,7 @@ Estimates monthly bandwidth based on use_case patterns:
|
||||
| Analytics | 0.7MB | 30 | 50% |
|
||||
| Blog/Content | 1.5MB | 4 | 30% |
|
||||
|
||||
Heavy bandwidth (>1TB/month) prefers Linode for included bandwidth.
|
||||
Heavy bandwidth (>1TB/month) triggers warning about overage costs.
|
||||
|
||||
### Flexible Region Matching
|
||||
|
||||
@@ -115,10 +118,62 @@ Country names are auto-expanded via `COUNTRY_NAME_TO_REGIONS` mapping.
|
||||
- Exchange rate fetched from open.er-api.com with 1-hour KV cache
|
||||
- Fallback rate: 1450 KRW/USD if API unavailable
|
||||
|
||||
### Transfer Pricing (`bandwidth_info`)
|
||||
|
||||
Each recommendation includes `bandwidth_info` with transfer/bandwidth cost details:
|
||||
|
||||
| Field | Description | KRW Rounding |
|
||||
|-------|-------------|--------------|
|
||||
| `included_transfer_tb` | Free bandwidth included in plan (TB/month) | - |
|
||||
| `overage_cost_per_gb` | Overage cost per GB | 1원 단위 |
|
||||
| `overage_cost_per_tb` | Overage cost per TB | 100원 단위 |
|
||||
| `estimated_monthly_tb` | Estimated monthly usage (TB) | - |
|
||||
| `estimated_overage_tb` | Estimated overage (TB) | - |
|
||||
| `estimated_overage_cost` | Estimated overage charges | 100원 단위 |
|
||||
| `total_estimated_cost` | Server + overage total | 100원 단위 |
|
||||
| `currency` | "USD" or "KRW" | - |
|
||||
|
||||
**Data sources**:
|
||||
- `included_transfer_tb`: From `anvil_instances.transfer_tb`
|
||||
- `overage_cost_per_gb`: From `anvil_transfer_pricing.price_per_gb`
|
||||
|
||||
### HTML Report Endpoint (`handlers/report.ts`)
|
||||
|
||||
`GET /api/recommend/report?data={base64}&lang={en|ko}`
|
||||
|
||||
Generates printable/PDF-friendly HTML report from recommendation results.
|
||||
|
||||
**Parameters**:
|
||||
- `data`: Base64-encoded JSON of recommendation response
|
||||
- `lang`: Language (en, ko, ja, zh) - defaults to 'en'
|
||||
|
||||
**Usage**:
|
||||
```javascript
|
||||
// Get recommendations
|
||||
const result = await fetch('/api/recommend', {...});
|
||||
const data = await result.json();
|
||||
|
||||
// Generate report URL
|
||||
const reportUrl = `/api/recommend/report?data=${btoa(JSON.stringify(data))}&lang=ko`;
|
||||
window.open(reportUrl); // Opens printable HTML
|
||||
```
|
||||
|
||||
### Region-Based Recommendation Strategy (`recommend.ts`)
|
||||
|
||||
**When region IS specified** (e.g., `region_preference: ["seoul"]`):
|
||||
- Returns 3 spec tiers (Budget/Balanced/Premium) within that region
|
||||
- Example: Seoul 1 - Standard 4GB, Standard 8GB, Pro 16GB
|
||||
|
||||
**When NO region specified**:
|
||||
- Returns same/similar spec from 3 DIFFERENT regions for location comparison
|
||||
- Example: Standard 4GB from Osaka 2, Seoul 1, Singapore 1
|
||||
- Implemented by sending only 1 server per region to AI (forces diversity)
|
||||
|
||||
### AI Prompt Strategy (`recommend.ts`)
|
||||
|
||||
- Uses OpenAI GPT-4o-mini via Cloudflare AI Gateway (bypasses regional restrictions)
|
||||
- Server list format: `[server_id=XXXX] Provider Name...` for accurate ID extraction
|
||||
- **server_id uses `ap.id`** (pricing ID, unique per instance+region combination)
|
||||
- Scoring: Cost efficiency (40%) + Capacity fit (30%) + Scalability (30%)
|
||||
- Capacity response in Korean for Korean users
|
||||
- **Prompt injection protection**: User inputs sanitized via `sanitizeForAIPrompt()`
|
||||
@@ -168,24 +223,45 @@ OPENAI_API_KEY = "sk-..." # Set via wrangler secret
|
||||
|
||||
```bash
|
||||
# Health check
|
||||
curl -s https://server-recommend.kappa-d8e.workers.dev/api/health | jq .
|
||||
curl -s https://cloud-orchestrator.kappa-d8e.workers.dev/api/health | jq .
|
||||
|
||||
# Recommendation - nodejs/redis real-time chat (Japan)
|
||||
curl -s -X POST https://server-recommend.kappa-d8e.workers.dev/api/recommend -H "Content-Type: application/json" -d '{"tech_stack":["nodejs","redis"],"expected_users":1000,"use_case":"real-time chat","region_preference":["japan"]}' | jq .
|
||||
curl -s -X POST https://cloud-orchestrator.kappa-d8e.workers.dev/api/recommend -H "Content-Type: application/json" -d '{"tech_stack":["nodejs","redis"],"expected_users":1000,"use_case":"real-time chat","region_preference":["japan"]}' | jq .
|
||||
|
||||
# Recommendation - php/mysql community forum (Korea)
|
||||
curl -s -X POST https://server-recommend.kappa-d8e.workers.dev/api/recommend -H "Content-Type: application/json" -d '{"tech_stack":["php","mysql"],"expected_users":800,"use_case":"community forum","region_preference":["korea"]}' | jq .
|
||||
curl -s -X POST https://cloud-orchestrator.kappa-d8e.workers.dev/api/recommend -H "Content-Type: application/json" -d '{"tech_stack":["php","mysql"],"expected_users":800,"use_case":"community forum","region_preference":["korea"]}' | jq .
|
||||
|
||||
# Recommendation - analytics dashboard (heavier DB workload)
|
||||
curl -s -X POST https://server-recommend.kappa-d8e.workers.dev/api/recommend -H "Content-Type: application/json" -d '{"tech_stack":["postgresql"],"expected_users":500,"use_case":"analytics dashboard","region_preference":["japan"]}' | jq .
|
||||
curl -s -X POST https://cloud-orchestrator.kappa-d8e.workers.dev/api/recommend -H "Content-Type: application/json" -d '{"tech_stack":["postgresql"],"expected_users":500,"use_case":"analytics dashboard","region_preference":["japan"]}' | jq .
|
||||
|
||||
# Server list with filters (supports flexible region: korea, seoul, tokyo, etc.)
|
||||
curl -s "https://server-recommend.kappa-d8e.workers.dev/api/servers?region=korea&minCpu=4" | jq .
|
||||
curl -s "https://cloud-orchestrator.kappa-d8e.workers.dev/api/servers?region=korea&minCpu=4" | jq .
|
||||
|
||||
# HTML Report (encode recommendation result as base64)
|
||||
# 1. Get recommendation and save to variable
|
||||
RESULT=$(curl -s -X POST https://cloud-orchestrator.kappa-d8e.workers.dev/api/recommend -H "Content-Type: application/json" -d '{"tech_stack":["nodejs"],"expected_users":500,"use_case":"simple api","lang":"ko"}')
|
||||
# 2. Generate report URL with base64-encoded data
|
||||
REPORT_URL="https://cloud-orchestrator.kappa-d8e.workers.dev/api/recommend/report?data=$(echo $RESULT | base64 | tr -d '\n')&lang=ko"
|
||||
# 3. Open in browser or fetch
|
||||
echo $REPORT_URL
|
||||
```
|
||||
|
||||
## Recent Changes
|
||||
|
||||
### Anvil Pricing Migration (Latest)
|
||||
### Region Diversity & Bug Fixes (Latest)
|
||||
- **Region diversity**: No region specified → same spec from 3 different regions for comparison
|
||||
- **Cache key fix**: `region_preference` now included in cache key
|
||||
- **Server ID fix**: Changed from `ai.id` (instance) to `ap.id` (pricing) for unique region+instance identification
|
||||
- **Prompt cleanup**: Removed obsolete Linode/Vultr/DigitalOcean references (Anvil only)
|
||||
|
||||
### Transfer Pricing & Reporting
|
||||
- **Transfer pricing**: Added `anvil_transfer_pricing` table data to recommendations
|
||||
- **bandwidth_info**: Each recommendation includes transfer costs (included_tb, overage costs)
|
||||
- **available_regions**: Lists other regions where same server spec is available with prices
|
||||
- **HTML report**: New `/api/recommend/report` endpoint for printable reports
|
||||
- **KRW conversion**: Bandwidth costs converted to KRW for Korean users (GB: 1원, TB/total: 100원 rounding)
|
||||
|
||||
### Anvil Pricing Migration
|
||||
- **New tables**: Migrated from `pricing` to `anvil_pricing` tables
|
||||
- **Provider**: Now uses "Anvil" as single provider (previously Linode/Vultr)
|
||||
- **Exchange rate**: Real-time USD→KRW conversion via open.er-api.com
|
||||
|
||||
Reference in New Issue
Block a user