# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

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`

## Commands

```bash
# Development
npm run dev              # Start local development server (wrangler dev)
npm run deploy           # Deploy to Cloudflare Workers
npm run typecheck        # TypeScript type checking

# Database operations (D1)
npx wrangler d1 execute cloud-instances-db --file=schema.sql        # Apply schema
npx wrangler d1 execute cloud-instances-db --file=seed.sql          # Seed data
npx wrangler d1 execute cloud-instances-db --file=fix-tech-specs.sql # Update tech specs
npx wrangler d1 execute cloud-instances-db --command="SELECT ..."   # Ad-hoc queries

# View logs
npx wrangler tail
```

## Architecture

```
src/
├── index.ts              # Main router, CORS, request handling
├── config.ts             # Configuration constants
├── types.ts              # TypeScript type definitions
├── utils.ts              # Utilities (bandwidth, response, AI, benchmarks, candidates, techSpecs)
└── handlers/
    ├── health.ts         # GET /api/health
    ├── servers.ts        # GET /api/servers - List servers with filtering
    └── recommend.ts      # POST /api/recommend - AI-powered recommendations
```

### Key Data Flow

1. User sends request (`tech_stack`, `expected_users`, `use_case`, `region_preference`)
2. Tech specs calculation with **DB workload multiplier** based on use_case
3. Candidate filtering with **flexible region matching**
4. VPS benchmarks retrieval (Geekbench 6), **prioritizing same provider**
5. AI analysis returns 3 tiers: Budget, Balanced, Premium
6. Results cached in KV (5 min TTL, empty results not cached)

### D1 Database Tables (cloud-instances-db)

- `providers` - Cloud providers (50+)
- `instance_types` - Server specifications
- `pricing` - Regional pricing
- `regions` - Geographic regions
- `tech_specs` - Resource requirements per technology (vcpu_per_users, min_memory_mb)
- `vps_benchmarks` - Geekbench 6 benchmark data (269 records)
- `benchmark_results` / `benchmark_types` / `processors` - Phoronix benchmark data

## Key Implementation Details

### DB Workload Multiplier (`recommend.ts`)

Database resource requirements vary by workload type, not just user count:

| Workload Type | Multiplier | Example Use Cases |
|---------------|------------|-------------------|
| Heavy | 0.3x | analytics, log server, reporting, dashboard |
| Medium-Heavy | 0.5x | e-commerce, ERP, CRM, community forum |
| Medium | 0.7x | API, SaaS, app backend |
| Light | 1.0x | blog, portfolio, documentation, wiki |

**Example**: PostgreSQL (vcpu_per_users: 200) with 1000 users
- Analytics dashboard: 1000 / (200 × 0.3) = 17 vCPU
- E-commerce: 1000 / (200 × 0.5) = 10 vCPU
- Personal blog: 1000 / (200 × 1.0) = 5 vCPU

### Bandwidth Estimation (`bandwidth.ts`)

Estimates monthly bandwidth based on use_case patterns:

| Pattern | Page Size | Pages/Day | Active Ratio |
|---------|-----------|-----------|--------------|
| E-commerce | 2.5MB | 20 | 40% |
| Streaming | 50MB | 5 | 20% |
| Analytics | 0.7MB | 30 | 50% |
| Blog/Content | 1.5MB | 4 | 30% |

Heavy bandwidth (>1TB/month) prefers Linode for included bandwidth.

### Flexible Region Matching (`candidates.ts`)

Region matching supports multiple input formats:
```sql
LOWER(r.region_code) = ? OR
LOWER(r.region_code) LIKE ? OR
LOWER(r.region_name) LIKE ? OR
LOWER(r.country_code) = ?
```

Valid inputs: `"korea"`, `"KR"`, `"seoul"`, `"ap-northeast-2"`, `"icn"`

### 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
- Scoring: Cost efficiency (40%) + Capacity fit (30%) + Scalability (30%)
- Capacity response in Korean for Korean users
- **Prompt injection protection**: User inputs sanitized via `sanitizeForAIPrompt()`
- **Token optimization**: Candidates limited to top 15 by price

### Security Features

- **Input validation**: Comprehensive checks with length limits (tech_stack ≤20, use_case ≤500 chars)
- **Rate limiting**: 60 req/min per IP with in-memory fallback when KV unavailable
- **SQL injection prevention**: All queries use parameterized statements
- **Security headers**: CSP, HSTS, X-Frame-Options, X-Content-Type-Options
- **API key protection**: Keys never logged, sanitized from error messages

### Configuration (`config.ts`)

Centralized limits and constants:
```typescript
LIMITS = {
  MAX_REQUEST_BODY_BYTES: 10240,    // 10KB
  CACHE_TTL_SECONDS: 300,            // 5 minutes
  RATE_LIMIT_MAX_REQUESTS: 60,       // per minute
  MAX_AI_CANDIDATES: 15,             // reduce API cost
  MAX_TECH_STACK: 20,
  MAX_USE_CASE_LENGTH: 500,
}
```

## Bindings (wrangler.toml)

```toml
[[kv_namespaces]]
binding = "CACHE"
id = "c68cdb477022424cbe4594f491390c8a"

[[d1_databases]]
binding = "DB"
database_name = "cloud-instances-db"
database_id = "bbcb472d-b25e-4e48-b6ea-112f9fffb4a8"

[vars]
OPENAI_API_KEY = "sk-..." # Set via wrangler secret
```

## Testing

```bash
# Health check
curl https://server-recommend.kappa-d8e.workers.dev/api/health

# Recommendation (e-commerce)
curl -X POST https://server-recommend.kappa-d8e.workers.dev/api/recommend \
  -H "Content-Type: application/json" \
  -d '{
    "tech_stack": ["php", "mysql"],
    "expected_users": 1000,
    "use_case": "e-commerce shopping mall",
    "region_preference": ["korea"]
  }'

# Recommendation (analytics - heavier DB workload)
curl -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"]
  }'
```

## Recent Changes

### Architecture
- **Modular architecture**: Split from single 2370-line file into organized modules
- **Centralized config**: All magic numbers moved to `LIMITS` in config.ts
- **Type safety**: `parseAIResponse(unknown)` with proper type guards

### Features
- **DB workload multiplier**: Database resource calculation based on use_case
- **Bandwidth estimation**: Automatic bandwidth category detection for provider filtering
- **Tech specs update**: Realistic vcpu_per_users values for 150+ technologies

### Security
- **Prompt injection protection**: `sanitizeForAIPrompt()` filters malicious patterns
- **Rate limiting fallback**: In-memory Map when KV unavailable
- **Input sanitization**: All user inputs validated and length-limited

### Performance
- **O(1) VPS lookup**: Map-based benchmark matching (was O(n×m))
- **AI token optimization**: Candidates limited to 15 (was 50)
- **KV caching**: 5-minute TTL, empty results not cached
- **Parallel queries**: Promise.all for independent DB operations

### Code Quality
- **Dead code removed**: Unused `queryVPSBenchmarks` function deleted
- **DRY**: `DEFAULT_REGION_FILTER_SQL` shared between handlers
- **Name-based filtering**: Provider queries use names, not hardcoded IDs
