refactor: 파일 분리 리팩토링 (routes, services, tools, utils)
아키텍처 개선: - index.ts: 921줄 → 205줄 (77% 감소) - openai-service.ts: 1,356줄 → 148줄 (89% 감소) 새로운 디렉토리 구조: - src/routes/ - Webhook, API, Health check 핸들러 - webhook.ts (287줄) - api.ts (318줄) - health.ts (14줄) - src/services/ - 비즈니스 로직 - bank-sms-parser.ts (143줄) - deposit-matcher.ts (88줄) - src/tools/ - Function Calling 도구 모듈화 - weather-tool.ts (37줄) - search-tool.ts (156줄) - domain-tool.ts (725줄) - deposit-tool.ts (183줄) - utility-tools.ts (60줄) - index.ts (104줄) - 도구 레지스트리 - src/utils/ - 유틸리티 함수 - email-decoder.ts - Quoted-Printable 디코더 타입 에러 수정: - routes/webhook.ts: text undefined 체크 - summary-service.ts: D1 타입 캐스팅 - summary-service.ts: Workers AI 타입 처리 - n8n-service.ts: Workers AI 타입 + 미사용 변수 제거 빌드 검증: - TypeScript 타입 체크 통과 - Wrangler dev 로컬 빌드 성공 문서: - REFACTORING_SUMMARY.md 추가 - ROUTE_ARCHITECTURE.md 추가 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
88
src/services/deposit-matcher.ts
Normal file
88
src/services/deposit-matcher.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
import { BankNotification } from '../types';
|
||||
|
||||
/**
|
||||
* 자동 매칭 결과
|
||||
*/
|
||||
export interface MatchResult {
|
||||
transactionId: number;
|
||||
userId: number;
|
||||
amount: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 입금 SMS와 대기 중인 거래를 자동 매칭
|
||||
*
|
||||
* 매칭 조건:
|
||||
* - 입금자명 앞 7글자 일치 (은행 SMS가 7글자까지만 표시)
|
||||
* - 금액 일치
|
||||
* - 상태가 'pending'인 거래
|
||||
*
|
||||
* 매칭 성공 시:
|
||||
* - deposit_transactions.status = 'confirmed'
|
||||
* - user_deposits.balance 증가
|
||||
* - bank_notifications.matched_transaction_id 업데이트
|
||||
*
|
||||
* @param db - D1 Database 인스턴스
|
||||
* @param notificationId - bank_notifications 테이블의 ID
|
||||
* @param notification - 파싱된 은행 알림
|
||||
* @returns 매칭 결과 또는 null (매칭 실패)
|
||||
*/
|
||||
export async function matchPendingDeposit(
|
||||
db: D1Database,
|
||||
notificationId: number,
|
||||
notification: BankNotification
|
||||
): Promise<MatchResult | null> {
|
||||
// 매칭 조건: 입금자명(앞 7글자) + 금액이 일치하는 pending 거래
|
||||
// 은행 SMS는 입금자명이 7글자까지만 표시됨
|
||||
const pendingTx = await db.prepare(
|
||||
`SELECT dt.id, dt.user_id, dt.amount
|
||||
FROM deposit_transactions dt
|
||||
WHERE dt.status = 'pending'
|
||||
AND dt.type = 'deposit'
|
||||
AND SUBSTR(dt.depositor_name, 1, 7) = ?
|
||||
AND dt.amount = ?
|
||||
ORDER BY dt.created_at ASC
|
||||
LIMIT 1`
|
||||
).bind(notification.depositorName, notification.amount).first<{
|
||||
id: number;
|
||||
user_id: number;
|
||||
amount: number;
|
||||
}>();
|
||||
|
||||
if (!pendingTx) {
|
||||
console.log('[matchPendingDeposit] 매칭되는 pending 거래 없음');
|
||||
return null;
|
||||
}
|
||||
|
||||
console.log('[matchPendingDeposit] 매칭 발견:', pendingTx);
|
||||
|
||||
try {
|
||||
// 트랜잭션: 거래 확정 + 잔액 증가 + 알림 매칭 업데이트
|
||||
await db.batch([
|
||||
db.prepare(
|
||||
"UPDATE deposit_transactions SET status = 'confirmed', confirmed_at = CURRENT_TIMESTAMP WHERE id = ?"
|
||||
).bind(pendingTx.id),
|
||||
db.prepare(
|
||||
'UPDATE user_deposits SET balance = balance + ?, updated_at = CURRENT_TIMESTAMP WHERE user_id = ?'
|
||||
).bind(pendingTx.amount, pendingTx.user_id),
|
||||
db.prepare(
|
||||
'UPDATE bank_notifications SET matched_transaction_id = ? WHERE id = ?'
|
||||
).bind(pendingTx.id, notificationId),
|
||||
]);
|
||||
|
||||
console.log('[matchPendingDeposit] 매칭 완료:', {
|
||||
transactionId: pendingTx.id,
|
||||
userId: pendingTx.user_id,
|
||||
amount: pendingTx.amount,
|
||||
});
|
||||
|
||||
return {
|
||||
transactionId: pendingTx.id,
|
||||
userId: pendingTx.user_id,
|
||||
amount: pendingTx.amount,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('[matchPendingDeposit] DB 업데이트 실패:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user