Restrict troubleshoot/billing/asset to customers only
Non-customers (no assets and no wallet balance) are redirected to onboarding agent. Customer check queries servers, domains, DDoS/VPN services, and wallet balance. Admins bypass the check. On DB error, defaults to allowing access to prevent false lockouts. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -96,6 +96,24 @@ export async function handleMessage(
|
|||||||
const intent = await classifyIntent(env, text);
|
const intent = await classifyIntent(env, text);
|
||||||
logger.info('의도 분류 결과', { intent, telegramUserId });
|
logger.info('의도 분류 결과', { intent, telegramUserId });
|
||||||
|
|
||||||
|
// 고객 전용 에이전트(troubleshoot, billing, asset)는 자산 또는 잔액이 있는 사용자만 이용 가능
|
||||||
|
// admin은 제한 없음
|
||||||
|
const customerOnlyIntents = ['troubleshoot', 'billing', 'asset'];
|
||||||
|
if (intent && customerOnlyIntents.includes(intent) && user.role !== 'admin') {
|
||||||
|
const isCustomer = await checkIsCustomer(env.DB, telegramUserId);
|
||||||
|
if (!isCustomer) {
|
||||||
|
logger.info('비고객 → 온보딩 전환', { intent, telegramUserId });
|
||||||
|
const response = await onboardingAgent.processConsultation(env.DB, telegramUserId, text, env, meta);
|
||||||
|
const { cleanText, sessionEnded } = cleanSessionMarkers(response);
|
||||||
|
await storeConversation(env.DB, user.id, text, cleanText, requestId);
|
||||||
|
await sendMessage(env.BOT_TOKEN, chatId, cleanText);
|
||||||
|
if (sessionEnded) {
|
||||||
|
await promptFeedback(env, chatId, lang, 'onboarding');
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const agentMap: Record<string, { agent: RegisterableAgent; type: string }> = {
|
const agentMap: Record<string, { agent: RegisterableAgent; type: string }> = {
|
||||||
onboarding: { agent: onboardingAgent, type: 'onboarding' },
|
onboarding: { agent: onboardingAgent, type: 'onboarding' },
|
||||||
troubleshoot: { agent: troubleshootAgent, type: 'troubleshoot' },
|
troubleshoot: { agent: troubleshootAgent, type: 'troubleshoot' },
|
||||||
@@ -173,6 +191,27 @@ async function getOrCreateUser(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function checkIsCustomer(db: D1Database, telegramUserId: string): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
const result = await db.prepare(
|
||||||
|
`SELECT
|
||||||
|
(SELECT COUNT(*) FROM servers WHERE user_id = u.id) +
|
||||||
|
(SELECT COUNT(*) FROM domains WHERE user_id = u.id) +
|
||||||
|
(SELECT COUNT(*) FROM services_ddos WHERE user_id = u.id) +
|
||||||
|
(SELECT COUNT(*) FROM services_vpn WHERE user_id = u.id) AS asset_count,
|
||||||
|
(SELECT COALESCE(balance, 0) FROM wallets WHERE user_id = u.id) AS balance
|
||||||
|
FROM users u WHERE u.telegram_id = ?`
|
||||||
|
).bind(telegramUserId).first<{ asset_count: number; balance: number }>();
|
||||||
|
|
||||||
|
if (!result) return false;
|
||||||
|
return result.asset_count > 0 || (result.balance ?? 0) > 0;
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('고객 확인 실패', error as Error, { telegramUserId });
|
||||||
|
// 에러 시 고객으로 간주 (서비스 차단 방지)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const VALID_INTENTS = ['troubleshoot', 'onboarding', 'billing', 'asset', 'general'] as const;
|
const VALID_INTENTS = ['troubleshoot', 'onboarding', 'billing', 'asset', 'general'] as const;
|
||||||
|
|
||||||
async function classifyIntent(env: Env, text: string): Promise<string | null> {
|
async function classifyIntent(env: Env, text: string): Promise<string | null> {
|
||||||
|
|||||||
Reference in New Issue
Block a user