From 1fd86c730e69865e0beca8e8006001ede41b1fea Mon Sep 17 00:00:00 2001 From: "_woo_s.j" Date: Mon, 2 Feb 2026 11:01:56 +0900 Subject: [PATCH] Add error code handling for SMS send failures --- src/controllers/smsController.js | 34 +++++++++++++++++++++++++------- src/services/smsService.js | 24 +++++++++++++++++++++- 2 files changed, 50 insertions(+), 8 deletions(-) diff --git a/src/controllers/smsController.js b/src/controllers/smsController.js index 897f9966..158d835c 100644 --- a/src/controllers/smsController.js +++ b/src/controllers/smsController.js @@ -62,12 +62,32 @@ exports.sendSmsVerification = async (req, res) => { // 5. 캐시에 저장 (sessionId 기반) smsService.saveVerification(sessionId, normalizedPhone, verificationCode); - // 6. 비동기 SMS 발송 (백그라운드에서 처리) - smsService.sendSms(normalizedPhone, verificationCode) - .then(() => console.log(`[SMS] 발송 완료: ${normalizedPhone}`)) - .catch(err => console.error(`[SMS] 발송 실패: ${normalizedPhone}`, err.message)); + // 6. SMS 발송 (결과를 기다림) + try { + await smsService.sendSms(normalizedPhone, verificationCode); + console.log(`[SMS] 발송 완료: ${normalizedPhone}`); + } catch (smsError) { + console.error(`[SMS] 발송 실패: ${normalizedPhone}`, smsError.message); + + // 서비스 이용 불가 (잔액 부족 등) + if (smsError.errorCode === 'SMS_SERVICE_UNAVAILABLE') { + return res.status(503).json({ + success: false, + errorCode: 'SMS_SERVICE_UNAVAILABLE', + message: '인증 서비스가 일시적으로 이용 불가합니다. 잠시 후 다시 시도해주세요.', + contact: 'teamitaka.official@gmail.com' + }); + } - // 7. 즉시 응답 반환 + // 기타 발송 실패 + return res.status(500).json({ + success: false, + errorCode: 'SMS_SEND_FAILED', + message: '인증번호 발송에 실패했습니다. 잠시 후 다시 시도해주세요.' + }); + } + + // 7. 성공 응답 반환 console.log(`[SMS] 인증 요청 성공: ${normalizedPhone}`); res.status(200).json({ success: true, @@ -84,8 +104,8 @@ exports.sendSmsVerification = async (req, res) => { res.status(500).json({ success: false, - error: 'SERVER_ERROR', - message: error.message || '서버 오류가 발생했습니다. 잠시 후 다시 시도해주세요.' + errorCode: 'SERVER_ERROR', + message: '서버 오류가 발생했습니다. 잠시 후 다시 시도해주세요.' }); } }; diff --git a/src/services/smsService.js b/src/services/smsService.js index 248b7b6a..47d0e448 100644 --- a/src/services/smsService.js +++ b/src/services/smsService.js @@ -99,6 +99,7 @@ class SmsService { * @param {string} phone - 수신자 전화번호 * @param {string} code - 인증번호 * @returns {Promise<{messageId: string}>} + * @throws {Error} errorCode: SMS_SERVICE_UNAVAILABLE | SMS_SEND_FAILED */ async sendSms(phone, code) { try { @@ -112,7 +113,28 @@ class SmsService { return { messageId: result.messageId }; } catch (error) { console.error(`[SMS] 발송 실패: ${phone}`, error.message); - throw new Error('SMS 발송에 실패했습니다. 잠시 후 다시 시도해주세요.'); + console.error(`[SMS] 에러 상세:`, error); + + // 잔액 부족 에러 감지 (Solapi 에러 메시지/코드 패턴) + const errorMessage = error.message || ''; + const errorCode = error.code || error.errorCode || ''; + + if ( + errorMessage.includes('NotEnoughBalance') || + errorMessage.includes('잔액') || + errorMessage.includes('balance') || + errorCode === 'NotEnoughBalance' || + errorCode === 'InsufficientBalance' + ) { + const smsError = new Error('인증 서비스가 일시적으로 이용 불가합니다.'); + smsError.errorCode = 'SMS_SERVICE_UNAVAILABLE'; + throw smsError; + } + + // 기타 발송 실패 + const smsError = new Error('인증번호 발송에 실패했습니다.'); + smsError.errorCode = 'SMS_SEND_FAILED'; + throw smsError; } }