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:
kappa
2026-01-26 02:49:24 +09:00
parent 580cc1bbe2
commit 411cde4801
11 changed files with 1132 additions and 356 deletions

View File

@@ -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