refactor: remove ServerSession types from types.ts
Removed: - ServerSessionStatus type - ServerSession interface - Recommendation-related fields from ManageServerArgs (tech_stack, expected_users, use_case, etc.) - Updated ManageServerArgs actions to server management only (order, start, stop, reboot, delete, list, info, images, rename) Commented out (temporary): - ServerSessionManager class in session-manager.ts - Server consultation session cleanup code in server-tool.ts (2 locations) - Server order confirmation handler in api/chat.ts These commented sections will be fully removed in subsequent commits when server-agent and related code are removed. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -319,126 +319,127 @@ async function handleChatApi(request: Request, env: Env): Promise<Response> {
|
||||
}
|
||||
}
|
||||
|
||||
// 서버 신청 확인 처리 (텍스트 기반) - Queue 기반
|
||||
if (body.message.trim() === '신청') {
|
||||
const orderSessionKey = `server_order_confirm:${telegramUserId}`;
|
||||
logger.info('신청 세션 확인', { orderSessionKey, telegramUserId });
|
||||
const orderSessionData = await env.SESSION_KV.get(orderSessionKey);
|
||||
logger.info('신청 세션 데이터', { found: !!orderSessionData, data: orderSessionData?.slice(0, 100) });
|
||||
|
||||
if (orderSessionData) {
|
||||
try {
|
||||
const orderData = JSON.parse(orderSessionData);
|
||||
|
||||
// 1. 서버 세션에서 가격 정보 가져오기
|
||||
const { ServerSessionManager } = await import('../../utils/session-manager');
|
||||
const { getSessionConfig } = await import('../../constants/agent-config');
|
||||
const sessionManager = new ServerSessionManager(getSessionConfig('server'));
|
||||
const session = await sessionManager.get(env.DB, telegramUserId);
|
||||
|
||||
if (!session || !session.last_recommendation) {
|
||||
await env.SESSION_KV.delete(orderSessionKey);
|
||||
const processingTimeMs = Date.now() - startTime;
|
||||
|
||||
return Response.json({
|
||||
success: true,
|
||||
response: '❌ 세션이 만료되었습니다.\n다시 "서버 추천"을 시작해주세요.',
|
||||
processing_time_ms: processingTimeMs,
|
||||
});
|
||||
}
|
||||
|
||||
const selected = session.last_recommendation.recommendations[orderData.index];
|
||||
if (!selected) {
|
||||
await env.SESSION_KV.delete(orderSessionKey);
|
||||
await sessionManager.delete(env.DB, telegramUserId);
|
||||
const processingTimeMs = Date.now() - startTime;
|
||||
|
||||
return Response.json({
|
||||
success: true,
|
||||
response: '❌ 선택한 서버를 찾을 수 없습니다.',
|
||||
processing_time_ms: processingTimeMs,
|
||||
});
|
||||
}
|
||||
|
||||
const price = selected.price?.monthly_krw || 0;
|
||||
|
||||
// 2. 잔액 확인
|
||||
const deposit = await env.DB.prepare(
|
||||
'SELECT balance FROM user_deposits WHERE user_id = ?'
|
||||
).bind(userId).first<{ balance: number }>();
|
||||
|
||||
if (!deposit || deposit.balance < price) {
|
||||
const processingTimeMs = Date.now() - startTime;
|
||||
|
||||
return Response.json({
|
||||
success: true,
|
||||
response:
|
||||
`❌ 잔액이 부족합니다.\n\n` +
|
||||
`• 서버 가격: ${price.toLocaleString()}원/월\n` +
|
||||
`• 현재 잔액: ${(deposit?.balance || 0).toLocaleString()}원\n` +
|
||||
`• 부족 금액: ${(price - (deposit?.balance || 0)).toLocaleString()}원\n\n` +
|
||||
`잔액을 충전 후 다시 시도해주세요.`,
|
||||
processing_time_ms: processingTimeMs,
|
||||
});
|
||||
}
|
||||
|
||||
// 3. Queue 확인
|
||||
if (!env.SERVER_PROVISION_QUEUE) {
|
||||
const processingTimeMs = Date.now() - startTime;
|
||||
|
||||
return Response.json({
|
||||
success: true,
|
||||
response: '❌ 서버 프로비저닝 시스템이 준비되지 않았습니다.',
|
||||
processing_time_ms: processingTimeMs,
|
||||
});
|
||||
}
|
||||
|
||||
// 4. 주문 생성 및 Queue 전송
|
||||
const { createServerOrder, sendProvisionMessage } = await import('../../server-provision');
|
||||
|
||||
const orderId = await createServerOrder(
|
||||
env.DB,
|
||||
userId,
|
||||
telegramUserId,
|
||||
selected.pricing_id,
|
||||
selected.region.code,
|
||||
'anvil',
|
||||
price,
|
||||
`${selected.plan_name} - ${orderData.label || session.collected_info?.useCase || 'server'}`
|
||||
);
|
||||
|
||||
await sendProvisionMessage(env.SERVER_PROVISION_QUEUE, orderId, userId, telegramUserId);
|
||||
|
||||
// 5. 세션 정리
|
||||
await env.SESSION_KV.delete(orderSessionKey);
|
||||
await sessionManager.delete(env.DB, telegramUserId);
|
||||
|
||||
// 6. 즉시 응답
|
||||
const processingTimeMs = Date.now() - startTime;
|
||||
|
||||
return Response.json({
|
||||
success: true,
|
||||
response:
|
||||
`📋 <b>서버 주문 접수 완료!</b> (주문 #${orderId})\n\n` +
|
||||
`• 서버: ${selected.plan_name}\n` +
|
||||
`• 리전: ${selected.region.name} (${selected.region.code})\n` +
|
||||
`• 가격: ${price.toLocaleString()}원/월\n\n` +
|
||||
`⏳ 서버를 생성하고 있습니다... (1-2분 소요)\n` +
|
||||
`완료되면 메시지로 알려드릴게요.`,
|
||||
processing_time_ms: processingTimeMs,
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('Chat API - 서버 신청 처리 오류', toError(error));
|
||||
const processingTimeMs = Date.now() - startTime;
|
||||
|
||||
return Response.json({
|
||||
success: true,
|
||||
response: '🚫 서버 신청 중 오류가 발생했습니다. 다시 시도해주세요.',
|
||||
processing_time_ms: processingTimeMs,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
// NOTE: Server order confirmation removed (recommendation feature deprecated)
|
||||
// This entire block was for processing server orders based on recommendation sessions
|
||||
// if (body.message.trim() === '신청') {
|
||||
// const orderSessionKey = `server_order_confirm:${telegramUserId}`;
|
||||
// logger.info('신청 세션 확인', { orderSessionKey, telegramUserId });
|
||||
// const orderSessionData = await env.SESSION_KV.get(orderSessionKey);
|
||||
// logger.info('신청 세션 데이터', { found: !!orderSessionData, data: orderSessionData?.slice(0, 100) });
|
||||
//
|
||||
// if (orderSessionData) {
|
||||
// try {
|
||||
// const orderData = JSON.parse(orderSessionData);
|
||||
//
|
||||
// // 1. 서버 세션에서 가격 정보 가져오기
|
||||
// const { ServerSessionManager } = await import('../../utils/session-manager');
|
||||
// const { getSessionConfig } = await import('../../constants/agent-config');
|
||||
// const sessionManager = new ServerSessionManager(getSessionConfig('server'));
|
||||
// const session = await sessionManager.get(env.DB, telegramUserId);
|
||||
//
|
||||
// if (!session || !session.last_recommendation) {
|
||||
// await env.SESSION_KV.delete(orderSessionKey);
|
||||
// const processingTimeMs = Date.now() - startTime;
|
||||
//
|
||||
// return Response.json({
|
||||
// success: true,
|
||||
// response: '❌ 세션이 만료되었습니다.\n다시 "서버 추천"을 시작해주세요.',
|
||||
// processing_time_ms: processingTimeMs,
|
||||
// });
|
||||
// }
|
||||
//
|
||||
// const selected = session.last_recommendation.recommendations[orderData.index];
|
||||
// if (!selected) {
|
||||
// await env.SESSION_KV.delete(orderSessionKey);
|
||||
// await sessionManager.delete(env.DB, telegramUserId);
|
||||
// const processingTimeMs = Date.now() - startTime;
|
||||
//
|
||||
// return Response.json({
|
||||
// success: true,
|
||||
// response: '❌ 선택한 서버를 찾을 수 없습니다.',
|
||||
// processing_time_ms: processingTimeMs,
|
||||
// });
|
||||
// }
|
||||
//
|
||||
// const price = selected.price?.monthly_krw || 0;
|
||||
//
|
||||
// // 2. 잔액 확인
|
||||
// const deposit = await env.DB.prepare(
|
||||
// 'SELECT balance FROM user_deposits WHERE user_id = ?'
|
||||
// ).bind(userId).first<{ balance: number }>();
|
||||
//
|
||||
// if (!deposit || deposit.balance < price) {
|
||||
// const processingTimeMs = Date.now() - startTime;
|
||||
//
|
||||
// return Response.json({
|
||||
// success: true,
|
||||
// response:
|
||||
// `❌ 잔액이 부족합니다.\n\n` +
|
||||
// `• 서버 가격: ${price.toLocaleString()}원/월\n` +
|
||||
// `• 현재 잔액: ${(deposit?.balance || 0).toLocaleString()}원\n` +
|
||||
// `• 부족 금액: ${(price - (deposit?.balance || 0)).toLocaleString()}원\n\n` +
|
||||
// `잔액을 충전 후 다시 시도해주세요.`,
|
||||
// processing_time_ms: processingTimeMs,
|
||||
// });
|
||||
// }
|
||||
//
|
||||
// // 3. Queue 확인
|
||||
// if (!env.SERVER_PROVISION_QUEUE) {
|
||||
// const processingTimeMs = Date.now() - startTime;
|
||||
//
|
||||
// return Response.json({
|
||||
// success: true,
|
||||
// response: '❌ 서버 프로비저닝 시스템이 준비되지 않았습니다.',
|
||||
// processing_time_ms: processingTimeMs,
|
||||
// });
|
||||
// }
|
||||
//
|
||||
// // 4. 주문 생성 및 Queue 전송
|
||||
// const { createServerOrder, sendProvisionMessage } = await import('../../server-provision');
|
||||
//
|
||||
// const orderId = await createServerOrder(
|
||||
// env.DB,
|
||||
// userId,
|
||||
// telegramUserId,
|
||||
// selected.pricing_id,
|
||||
// selected.region.code,
|
||||
// 'anvil',
|
||||
// price,
|
||||
// `${selected.plan_name} - ${orderData.label || session.collected_info?.useCase || 'server'}`
|
||||
// );
|
||||
//
|
||||
// await sendProvisionMessage(env.SERVER_PROVISION_QUEUE, orderId, userId, telegramUserId);
|
||||
//
|
||||
// // 5. 세션 정리
|
||||
// await env.SESSION_KV.delete(orderSessionKey);
|
||||
// await sessionManager.delete(env.DB, telegramUserId);
|
||||
//
|
||||
// // 6. 즉시 응답
|
||||
// const processingTimeMs = Date.now() - startTime;
|
||||
//
|
||||
// return Response.json({
|
||||
// success: true,
|
||||
// response:
|
||||
// `📋 <b>서버 주문 접수 완료!</b> (주문 #${orderId})\n\n` +
|
||||
// `• 서버: ${selected.plan_name}\n` +
|
||||
// `• 리전: ${selected.region.name} (${selected.region.code})\n` +
|
||||
// `• 가격: ${price.toLocaleString()}원/월\n\n` +
|
||||
// `⏳ 서버를 생성하고 있습니다... (1-2분 소요)\n` +
|
||||
// `완료되면 메시지로 알려드릴게요.`,
|
||||
// processing_time_ms: processingTimeMs,
|
||||
// });
|
||||
// } catch (error) {
|
||||
// logger.error('Chat API - 서버 신청 처리 오류', toError(error));
|
||||
// const processingTimeMs = Date.now() - startTime;
|
||||
//
|
||||
// return Response.json({
|
||||
// success: true,
|
||||
// response: '🚫 서버 신청 중 오류가 발생했습니다. 다시 시도해주세요.',
|
||||
// processing_time_ms: processingTimeMs,
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// 서버 신청 취소 처리 (다른 메시지 입력 시)
|
||||
const orderSessionKey = `server_order_confirm:${telegramUserId}`;
|
||||
|
||||
@@ -903,15 +903,15 @@ export async function executeServerDelete(
|
||||
}
|
||||
}
|
||||
|
||||
// Clear server consultation session (if any)
|
||||
try {
|
||||
const { ServerSessionManager } = await import('../utils/session-manager');
|
||||
const { getSessionConfig } = await import('../constants/agent-config');
|
||||
const sessionManager = new ServerSessionManager(getSessionConfig('server'));
|
||||
await sessionManager.delete(env.DB, telegramUserId);
|
||||
} catch (error) {
|
||||
provisionLogger.error('서버 세션 삭제 실패 (무시)', error as Error);
|
||||
}
|
||||
// NOTE: Server consultation session cleanup removed (recommendation feature deprecated)
|
||||
// try {
|
||||
// const { ServerSessionManager } = await import('../utils/session-manager');
|
||||
// const { getSessionConfig } = await import('../constants/agent-config');
|
||||
// const sessionManager = new ServerSessionManager(getSessionConfig('server'));
|
||||
// await sessionManager.delete(env.DB, telegramUserId);
|
||||
// } catch (error) {
|
||||
// provisionLogger.error('서버 세션 삭제 실패 (무시)', error as Error);
|
||||
// }
|
||||
|
||||
provisionLogger.info('서버 삭제 완료', { orderId });
|
||||
return {
|
||||
@@ -994,15 +994,15 @@ export async function executeServerOrder(
|
||||
const order = result.order;
|
||||
provisionLogger.info('서버 주문 완료', { orderId: order?.id, plan: orderData.plan });
|
||||
|
||||
// Clear server consultation session
|
||||
try {
|
||||
const { ServerSessionManager } = await import('../utils/session-manager');
|
||||
const { getSessionConfig } = await import('../constants/agent-config');
|
||||
const sessionManager = new ServerSessionManager(getSessionConfig('server'));
|
||||
await sessionManager.delete(env.DB, telegramUserId);
|
||||
} catch (error) {
|
||||
provisionLogger.error('서버 세션 삭제 실패 (무시)', error as Error);
|
||||
}
|
||||
// NOTE: Server consultation session cleanup removed (recommendation feature deprecated)
|
||||
// try {
|
||||
// const { ServerSessionManager } = await import('../utils/session-manager');
|
||||
// const { getSessionConfig } = await import('../constants/agent-config');
|
||||
// const sessionManager = new ServerSessionManager(getSessionConfig('server'));
|
||||
// await sessionManager.delete(env.DB, telegramUserId);
|
||||
// } catch (error) {
|
||||
// provisionLogger.error('서버 세션 삭제 실패 (무시)', error as Error);
|
||||
// }
|
||||
|
||||
// Build success message
|
||||
let successMessage = `✅ 서버 신청이 완료되었습니다!\n\n`;
|
||||
|
||||
68
src/types.ts
68
src/types.ts
@@ -211,31 +211,22 @@ export interface LookupDocsArgs {
|
||||
|
||||
export interface ManageServerArgs {
|
||||
action:
|
||||
| "recommend"
|
||||
| "order"
|
||||
| "start"
|
||||
| "stop"
|
||||
| "reboot"
|
||||
| "delete"
|
||||
| "list"
|
||||
| "info"
|
||||
| "images"
|
||||
| "start_consultation"
|
||||
| "continue_consultation"
|
||||
| "cancel_consultation";
|
||||
tech_stack?: string[];
|
||||
expected_users?: number;
|
||||
use_case?: string;
|
||||
traffic_pattern?: string;
|
||||
region_preference?: string[];
|
||||
budget_limit?: number;
|
||||
lang?: string;
|
||||
| "rename";
|
||||
server_id?: string;
|
||||
region_code?: string;
|
||||
label?: string;
|
||||
message?: string; // For continue_consultation
|
||||
pricing_id?: number; // For order
|
||||
order_id?: number; // For info, delete
|
||||
image?: string; // For order (OS image key)
|
||||
pricing_id?: number;
|
||||
order_id?: number;
|
||||
new_label?: string;
|
||||
image?: string;
|
||||
}
|
||||
|
||||
export interface ManageMemoryArgs {
|
||||
@@ -244,53 +235,6 @@ export interface ManageMemoryArgs {
|
||||
memory_id?: number;
|
||||
}
|
||||
|
||||
// Server Consultation Session Status
|
||||
export type ServerSessionStatus =
|
||||
| 'gathering' // 정보 수집 중
|
||||
| 'recommending' // 추천 중
|
||||
| 'selecting' // 선택 대기
|
||||
| 'ordering' // 주문 대기
|
||||
| 'completed'; // 완료
|
||||
|
||||
// Server Consultation Session (D1)
|
||||
export interface ServerSession {
|
||||
user_id: string;
|
||||
status: ServerSessionStatus;
|
||||
collected_info: {
|
||||
useCase?: string;
|
||||
scale?: 'personal' | 'business';
|
||||
budgetLimit?: number;
|
||||
regionPreference?: string[];
|
||||
expectedDau?: number; // 일일 활성 사용자 (Daily Active Users)
|
||||
expectedConcurrent?: number; // 동시접속자 (Concurrent Users)
|
||||
};
|
||||
messages: Array<{ role: 'user' | 'assistant'; content: string }>;
|
||||
created_at: number;
|
||||
updated_at: number;
|
||||
expires_at: number;
|
||||
last_recommendation?: {
|
||||
recommendations: Array<{
|
||||
pricing_id: number; // cloud-instances-db.anvil_pricing.id
|
||||
plan_name: string;
|
||||
provider: string;
|
||||
specs: { vcpu: number; ram_gb: number; storage_gb: number };
|
||||
region: { code: string; name: string };
|
||||
price: {
|
||||
monthly_krw: number;
|
||||
bandwidth_tb: number;
|
||||
estimated_monthly_tb?: number; // origin 트래픽 (서버 도달)
|
||||
gross_monthly_tb?: number; // CDN 전 트래픽
|
||||
cdn_cache_hit_rate?: number; // CDN 히트율 (0.0-1.0)
|
||||
overage_tb?: number;
|
||||
overage_cost_krw?: number;
|
||||
currency?: string; // 통화 단위 (KRW, USD 등)
|
||||
};
|
||||
score: number;
|
||||
max_users: number;
|
||||
}>;
|
||||
created_at: number;
|
||||
};
|
||||
}
|
||||
|
||||
// Troubleshooting Session Status
|
||||
export type TroubleshootSessionStatus =
|
||||
|
||||
@@ -316,24 +316,27 @@ export class DomainSessionManager extends SessionManager<DomainSession> {
|
||||
/**
|
||||
* Specialized session manager for Server Agent
|
||||
* Handles last_recommendation field
|
||||
*
|
||||
* NOTE: Temporarily commented out during server recommendation removal refactoring.
|
||||
* This class will be removed in a future commit when server-tool.ts is updated.
|
||||
*/
|
||||
export class ServerSessionManager extends SessionManager<ServerSession> {
|
||||
protected parseAdditionalFields(result: Record<string, unknown>): Partial<ServerSession> {
|
||||
return {
|
||||
last_recommendation: result.last_recommendation
|
||||
? JSON.parse(result.last_recommendation as string)
|
||||
: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
protected getAdditionalColumns(session: ServerSession): Record<string, unknown> {
|
||||
return {
|
||||
last_recommendation: session.last_recommendation
|
||||
? JSON.stringify(session.last_recommendation)
|
||||
: null,
|
||||
};
|
||||
}
|
||||
}
|
||||
// export class ServerSessionManager extends SessionManager<ServerSession> {
|
||||
// protected parseAdditionalFields(result: Record<string, unknown>): Partial<ServerSession> {
|
||||
// return {
|
||||
// last_recommendation: result.last_recommendation
|
||||
// ? JSON.parse(result.last_recommendation as string)
|
||||
// : undefined,
|
||||
// };
|
||||
// }
|
||||
//
|
||||
// protected getAdditionalColumns(session: ServerSession): Record<string, unknown> {
|
||||
// return {
|
||||
// last_recommendation: session.last_recommendation
|
||||
// ? JSON.stringify(session.last_recommendation)
|
||||
// : null,
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
|
||||
// Import types (avoid circular dependency by importing at end)
|
||||
import type { DomainSession, ServerSession } from '../types';
|
||||
import type { DomainSession } from '../types';
|
||||
|
||||
Reference in New Issue
Block a user