refactor: 추천 시스템 제거

삭제된 파일:
- src/routes/recommend.ts
- src/services/recommendation.ts
- src/services/recommendation.test.ts
- src/services/stackConfig.ts
- src/services/regionFilter.ts

수정된 파일:
- src/index.ts: /recommend 라우트 제거
- src/routes/index.ts: handleRecommend export 제거
- src/constants.ts: RECOMMENDATIONS TTL, rate limit 제거
- src/middleware/rateLimit.ts: /recommend 설정 제거
- src/types.ts: 추천 관련 타입 제거
- scripts/e2e-tester.ts: recommend 시나리오 제거
- scripts/api-tester.ts: recommend 테스트 제거

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
kappa
2026-01-26 00:35:59 +09:00
parent 01b062f86a
commit 1e750a863b
12 changed files with 13 additions and 1660 deletions

View File

@@ -121,119 +121,15 @@ function sleep(ms: number): Promise<void> {
// ============================================================
/**
* Scenario 1: WordPress Server Recommendation → Detail Lookup
*
* Flow:
* 1. POST /recommend with WordPress stack (nginx, php-fpm, mysql)
* 2. Extract first recommended instance ID
* 3. GET /instances with instance_id filter
* 4. Validate specs meet requirements
*/
async function scenario1WordPress(context: TestContext, dryRun: boolean): Promise<boolean> {
console.log('\n▶ Scenario 1: WordPress Server Recommendation → Detail Lookup');
if (dryRun) {
console.log(' [DRY RUN] Would execute:');
console.log(' 1. POST /recommend with stack: nginx, php-fpm, mysql');
console.log(' 2. Extract instance_id from first recommendation');
console.log(' 3. GET /instances?instance_id={id}');
console.log(' 4. Validate memory >= 3072MB, vCPU >= 2');
return true;
}
try {
// Step 1: Request recommendation
logStep(1, 'Request WordPress server recommendation...');
const recommendResp = await apiRequest('/recommend', {
method: 'POST',
body: JSON.stringify({
stack: ['nginx', 'php-fpm', 'mysql'],
scale: 'medium',
}),
});
logResponse('POST', '/recommend', recommendResp.status, recommendResp.duration);
if (recommendResp.status !== 200) {
console.log(` ❌ Expected 200, got ${recommendResp.status}`);
return false;
}
const recommendData = recommendResp.data as {
success: boolean;
data?: {
recommendations?: Array<{ instance: string; provider: string; price: { monthly: number }; region: string }>;
};
};
if (!recommendData.success || !recommendData.data?.recommendations?.[0]) {
console.log(' ❌ No recommendations returned');
return false;
}
const firstRec = recommendData.data.recommendations[0];
console.log(` Recommended: ${firstRec.instance} ($${firstRec.price.monthly}/mo) in ${firstRec.region}`);
// Step 2: Extract instance identifier (we'll use provider + instance name for search)
const instanceName = firstRec.instance;
const provider = firstRec.provider;
context.recommendedInstanceId = instanceName;
// Step 3: Fetch instance details
logStep(2, 'Fetch instance details...');
const detailsResp = await apiRequest(
`/instances?provider=${encodeURIComponent(provider)}&limit=100`,
{ method: 'GET' }
);
logResponse('GET', '/instances', detailsResp.status, detailsResp.duration);
if (detailsResp.status !== 200) {
console.log(` ❌ Expected 200, got ${detailsResp.status}`);
return false;
}
const detailsData = detailsResp.data as {
success: boolean;
data?: {
instances?: Array<{ instance_name: string; vcpu: number; memory_mb: number }>;
};
};
const instance = detailsData.data?.instances?.find((i) => i.instance_name === instanceName);
if (!instance) {
console.log(` ❌ Instance ${instanceName} not found in details`);
return false;
}
// Step 4: Validate specs
logStep(3, 'Validate specs meet requirements...');
const memoryOk = instance.memory_mb >= 3072; // nginx 256 + php-fpm 1024 + mysql 2048 + OS 768 = 4096
const vcpuOk = instance.vcpu >= 2;
logValidation(memoryOk, `Memory: ${instance.memory_mb}MB >= 3072MB required`);
logValidation(vcpuOk, `vCPU: ${instance.vcpu} >= 2 required`);
const passed = memoryOk && vcpuOk;
console.log(` ${passed ? '✅' : '❌'} Scenario ${passed ? 'PASSED' : 'FAILED'} (${recommendResp.duration + detailsResp.duration}ms)`);
return passed;
} catch (error) {
console.log(` ❌ Scenario FAILED with error: ${error instanceof Error ? error.message : String(error)}`);
return false;
}
}
/**
* Scenario 2: Budget-Constrained Instance Search
* Scenario 1: Budget-Constrained Instance Search
*
* Flow:
* 1. GET /instances?max_price=50&sort_by=price&order=asc
* 2. Validate all results <= $50/month
* 3. Validate price sorting is correct
*/
async function scenario2Budget(context: TestContext, dryRun: boolean): Promise<boolean> {
console.log('\n▶ Scenario 2: Budget-Constrained Instance Search');
async function scenario1Budget(context: TestContext, dryRun: boolean): Promise<boolean> {
console.log('\n▶ Scenario 1: Budget-Constrained Instance Search');
if (dryRun) {
console.log(' [DRY RUN] Would execute:');
@@ -297,15 +193,15 @@ async function scenario2Budget(context: TestContext, dryRun: boolean): Promise<b
}
/**
* Scenario 3: Cross-Region Price Comparison
* Scenario 2: Cross-Region Price Comparison
*
* Flow:
* 1. GET /instances?region=ap-northeast-1 (Tokyo)
* 2. GET /instances?region=ap-northeast-2 (Seoul)
* 3. Compare average prices and instance counts
*/
async function scenario3RegionCompare(context: TestContext, dryRun: boolean): Promise<boolean> {
console.log('\n▶ Scenario 3: Cross-Region Price Comparison (Tokyo vs Seoul)');
async function scenario2RegionCompare(context: TestContext, dryRun: boolean): Promise<boolean> {
console.log('\n▶ Scenario 2: Cross-Region Price Comparison (Tokyo vs Seoul)');
if (dryRun) {
console.log(' [DRY RUN] Would execute:');
@@ -395,15 +291,15 @@ async function scenario3RegionCompare(context: TestContext, dryRun: boolean): Pr
}
/**
* Scenario 4: Provider Sync and Data Verification
* Scenario 3: Provider Sync and Data Verification
*
* Flow:
* 1. POST /sync with provider: linode
* 2. GET /health to check sync_status
* 3. GET /instances?provider=linode to verify data exists
*/
async function scenario4ProviderSync(context: TestContext, dryRun: boolean): Promise<boolean> {
console.log('\n▶ Scenario 4: Provider Sync and Data Verification');
async function scenario3ProviderSync(context: TestContext, dryRun: boolean): Promise<boolean> {
console.log('\n▶ Scenario 3: Provider Sync and Data Verification');
if (dryRun) {
console.log(' [DRY RUN] Would execute:');
@@ -562,10 +458,9 @@ interface ScenarioFunction {
}
const scenarios: Record<string, ScenarioFunction> = {
wordpress: scenario1WordPress,
budget: scenario2Budget,
region: scenario3RegionCompare,
sync: scenario4ProviderSync,
budget: scenario1Budget,
region: scenario2RegionCompare,
sync: scenario3ProviderSync,
ratelimit: scenario5RateLimit,
};