refactor: modularize codebase and add DB workload multiplier

- Split monolithic index.ts (2370 lines) into modular structure:
  - src/handlers/ for route handlers
  - src/utils.ts for shared utilities
  - src/config.ts for configuration
  - src/types.ts for TypeScript definitions

- Add DB workload multiplier for smarter database resource calculation:
  - Heavy (analytics, logs): 0.3x multiplier
  - Medium-heavy (e-commerce, transactional): 0.5x
  - Medium (API, SaaS): 0.7x
  - Light (blog, portfolio): 1.0x

- Fix tech_specs with realistic vcpu_per_users values (150+ technologies)
- Fix "blog" matching "log" regex bug
- Update documentation to reflect new architecture

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
kappa
2026-01-25 17:46:16 +09:00
parent 0bb7296600
commit b682abc45d
9 changed files with 2729 additions and 2403 deletions

148
src/config.ts Normal file
View File

@@ -0,0 +1,148 @@
/**
* Configuration constants and use case mappings
*/
import type { UseCaseConfig } from './types';
export const USE_CASE_CONFIGS: UseCaseConfig[] = [
{
category: 'video',
patterns: /video|stream|media|youtube|netflix|vod|동영상|스트리밍|미디어/i,
dauMultiplier: { min: 8, max: 12 },
activeRatio: 0.3
},
{
category: 'file',
patterns: /download|file|storage|cdn|파일|다운로드|저장소/i,
dauMultiplier: { min: 10, max: 14 },
activeRatio: 0.5
},
{
category: 'gaming',
patterns: /game|gaming|minecraft|게임/i,
dauMultiplier: { min: 10, max: 20 },
activeRatio: 0.5
},
{
category: 'api',
patterns: /api|saas|backend|서비스|백엔드/i,
dauMultiplier: { min: 5, max: 10 },
activeRatio: 0.6
},
{
category: 'ecommerce',
patterns: /e-?commerce|shop|store|쇼핑|커머스|온라인몰/i,
dauMultiplier: { min: 20, max: 30 },
activeRatio: 0.4
},
{
category: 'forum',
patterns: /forum|community|board|게시판|커뮤니티|포럼/i,
dauMultiplier: { min: 15, max: 25 },
activeRatio: 0.5
},
{
category: 'blog',
patterns: /blog|news|static|portfolio|블로그|뉴스|포트폴리오|landing/i,
dauMultiplier: { min: 30, max: 50 },
activeRatio: 0.3
},
{
category: 'chat',
patterns: /chat|messaging|slack|discord|채팅|메신저/i,
dauMultiplier: { min: 10, max: 14 },
activeRatio: 0.7
}
];
/**
* i18n Messages for multi-language support
*/
export const i18n: Record<string, {
missingFields: string;
invalidFields: string;
schema: Record<string, string>;
example: Record<string, any>;
aiLanguageInstruction: string;
}> = {
en: {
missingFields: 'Missing required fields',
invalidFields: 'Invalid field values',
schema: {
tech_stack: "(required) string[] - e.g. ['nginx', 'nodejs']",
expected_users: "(required) number - expected concurrent users, e.g. 1000",
use_case: "(required) string - e.g. 'e-commerce website'",
traffic_pattern: "(optional) 'steady' | 'spiky' | 'growing'",
region_preference: "(optional) string[] - e.g. ['korea', 'japan']",
budget_limit: "(optional) number - max monthly USD",
provider_filter: "(optional) string[] - e.g. ['linode', 'vultr']",
lang: "(optional) 'en' | 'zh' | 'ja' | 'ko' - response language"
},
example: {
tech_stack: ["nginx", "nodejs", "postgresql"],
expected_users: 5000,
use_case: "SaaS application"
},
aiLanguageInstruction: 'Respond in English.'
},
zh: {
missingFields: '缺少必填字段',
invalidFields: '字段值无效',
schema: {
tech_stack: "(必填) string[] - 例如 ['nginx', 'nodejs']",
expected_users: "(必填) number - 预计同时在线用户数,例如 1000",
use_case: "(必填) string - 例如 '电商网站'",
traffic_pattern: "(可选) 'steady' | 'spiky' | 'growing'",
region_preference: "(可选) string[] - 例如 ['korea', 'japan']",
budget_limit: "(可选) number - 每月最高预算(美元)",
provider_filter: "(可选) string[] - 例如 ['linode', 'vultr']",
lang: "(可选) 'en' | 'zh' | 'ja' | 'ko' - 响应语言"
},
example: {
tech_stack: ["nginx", "nodejs", "postgresql"],
expected_users: 5000,
use_case: "SaaS应用程序"
},
aiLanguageInstruction: 'Respond in Chinese (Simplified). All analysis text must be in Chinese.'
},
ja: {
missingFields: '必須フィールドがありません',
invalidFields: 'フィールド値が無効です',
schema: {
tech_stack: "(必須) string[] - 例: ['nginx', 'nodejs']",
expected_users: "(必須) number - 予想同時接続ユーザー数、例: 1000",
use_case: "(必須) string - 例: 'ECサイト'",
traffic_pattern: "(任意) 'steady' | 'spiky' | 'growing'",
region_preference: "(任意) string[] - 例: ['korea', 'japan']",
budget_limit: "(任意) number - 月額予算上限(USD)",
provider_filter: "(任意) string[] - 例: ['linode', 'vultr']",
lang: "(任意) 'en' | 'zh' | 'ja' | 'ko' - 応答言語"
},
example: {
tech_stack: ["nginx", "nodejs", "postgresql"],
expected_users: 5000,
use_case: "SaaSアプリケーション"
},
aiLanguageInstruction: 'Respond in Japanese. All analysis text must be in Japanese.'
},
ko: {
missingFields: '필수 필드가 누락되었습니다',
invalidFields: '필드 값이 잘못되었습니다',
schema: {
tech_stack: "(필수) string[] - 예: ['nginx', 'nodejs']",
expected_users: "(필수) number - 예상 동시 접속자 수, 예: 1000",
use_case: "(필수) string - 예: '이커머스 웹사이트'",
traffic_pattern: "(선택) 'steady' | 'spiky' | 'growing'",
region_preference: "(선택) string[] - 예: ['korea', 'japan']",
budget_limit: "(선택) number - 월 예산 한도(원화, KRW)",
provider_filter: "(선택) string[] - 예: ['linode', 'vultr']",
lang: "(선택) 'en' | 'zh' | 'ja' | 'ko' - 응답 언어"
},
example: {
tech_stack: ["nginx", "nodejs", "postgresql"],
expected_users: 5000,
use_case: "SaaS 애플리케이션"
},
aiLanguageInstruction: 'Respond in Korean. All analysis text must be in Korean.'
}
};