feat: add server selection and order flow after recommendation

- Add 'selecting' and 'ordering' status to ServerSession
- Add lastRecommendation field to store recommendation results
- Keep session alive after recommendation (don't delete immediately)
- Add selection pattern matching (1번, 첫번째, 1번 선택 등)
- Add order confirmation message with inline buttons
- Add server_order/server_cancel callback handlers
- Add ServerOrderKeyboardData type for button data

Flow: recommend → select number → confirm with buttons → order/cancel

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
kappa
2026-01-27 10:45:04 +09:00
parent e4ccff9f87
commit 0c3bfede7d
5 changed files with 297 additions and 11 deletions

View File

@@ -119,6 +119,122 @@ ${result.error}
return;
}
// 서버 주문 확인
if (data.startsWith('server_order:')) {
const parts = data.split(':');
if (parts.length !== 3) {
await answerCallbackQuery(env.BOT_TOKEN, queryId, { text: '잘못된 데이터입니다.' });
return;
}
const userId = parts[1];
const index = parseInt(parts[2], 10);
if (isNaN(index) || index < 0 || index > 2) {
await answerCallbackQuery(env.BOT_TOKEN, queryId, { text: '잘못된 선택입니다.' });
return;
}
await answerCallbackQuery(env.BOT_TOKEN, queryId, { text: '처리 중...' });
await editMessageText(
env.BOT_TOKEN,
chatId,
messageId,
'⏳ 서버 주문 처리 중...'
);
// 세션 조회
const { getServerSession, deleteServerSession } = await import('../../server-agent');
if (!env.SESSION_KV) {
await editMessageText(
env.BOT_TOKEN,
chatId,
messageId,
'❌ 세션 저장소가 설정되지 않았습니다.'
);
return;
}
const session = await getServerSession(env.SESSION_KV, userId);
if (!session || !session.lastRecommendation) {
await editMessageText(
env.BOT_TOKEN,
chatId,
messageId,
'❌ 세션이 만료되었습니다.\n다시 "서버 추천"을 시작해주세요.'
);
return;
}
const selected = session.lastRecommendation.recommendations[index];
if (!selected) {
await editMessageText(
env.BOT_TOKEN,
chatId,
messageId,
'❌ 선택한 서버를 찾을 수 없습니다.'
);
await deleteServerSession(env.SESSION_KV, userId);
return;
}
// 주문 처리 (현재는 준비 중)
const { executeServerAction } = await import('../../tools/server-tool');
const result = await executeServerAction(
'order',
{
server_id: selected.plan_name, // 임시
region_code: selected.region.code,
label: `${session.collectedInfo.useCase || 'server'}-1`
},
env,
userId
);
await editMessageText(
env.BOT_TOKEN,
chatId,
messageId,
`📋 ${selected.plan_name} 신청\n\n${result}`
);
// 세션 삭제
await deleteServerSession(env.SESSION_KV, userId);
return;
}
// 서버 주문 취소
if (data.startsWith('server_cancel:')) {
const parts = data.split(':');
if (parts.length !== 2) {
await answerCallbackQuery(env.BOT_TOKEN, queryId, { text: '잘못된 데이터입니다.' });
return;
}
const userId = parts[1];
await answerCallbackQuery(env.BOT_TOKEN, queryId, { text: '취소되었습니다.' });
await editMessageText(
env.BOT_TOKEN,
chatId,
messageId,
'❌ 서버 신청이 취소되었습니다.'
);
// 세션 삭제
const { deleteServerSession } = await import('../../server-agent');
if (env.SESSION_KV) {
await deleteServerSession(env.SESSION_KV, userId);
}
return;
}
// 알 수 없는 callback data
await answerCallbackQuery(env.BOT_TOKEN, queryId);
}