[Nest] Solapi 를 활용한 SMS 기능 구현

2025. 12. 2. 00:26기술 창고/Nest.js

728x90
반응형
SMALL

Solapi + NestJS 문자 발송 연동 방법 | 웹 문의 → 관리자 휴대폰 문자 알림 구현

이 글에서는 웹사이트의 문의 내용을 자동으로 관리자의 휴대폰 문자(SMS)로 보내는 기능을 Solapi 문자 API + NestJS로 구현하는 방법을 정리합니다.
고객은 웹에서 문의를 남기고, 관리자는 휴대폰 문자로 확인한 뒤 바로 답장할 수 있는 방식입니다.


📌 전체 동작 흐름

  1. 고객이 웹 문의 폼에서 이름 · 연락처 · 문의 내용을 입력
  2. 프론트엔드가 백엔드 POST /contact API 호출
  3. NestJS가 내용을 수신 후 Solapi를 통해 관리자 휴대폰 번호로 문자 전송
  4. 관리자는 문자 수신 → 내용 확인 후 고객 연락처로 바로 문자 답장
특징: 문의 저장 / DB 저장 / Webhook 처리 없이 가장 단순한 형태의 문의 알림 문자 구현

1) 웹 폼에서 API 요청 (예시)

POST /contact
{
  "name": "홍길동",
  "phone": "01012345678",
  "message": "배송 문의 드려요."
}
  

위 데이터를 백엔드로 보내면 관리자 휴대폰 번호로 아래와 같은 문자가 전송됩니다.

[웹 문의 도착]

이름: 홍길동
연락처: 01012345678
문의 내용:
배송 문의 드려요.

※ 위 번호를 탭해서 바로 문자로 답장하실 수 있습니다.
  

2) .env 환경 변수 설정

SOLAPI_API_KEY=your_api_key
SOLAPI_API_SECRET=your_api_secret

# Solapi에 발신번호로 등록한 번호 (관리자 번호 등록하면 가장 자연스러움)
SOLAPI_SENDER=010관리자번호

# 실제 문자 받을 관리자 번호 (대개 위와 동일)
ADMIN_PHONE=010관리자번호
  
⚠ Solapi는 사전 등록된 발신번호만 발신 가능하기 때문에 관리자 번호를 발신번호로 등록해두는 것이 가장 안정적입니다.

3) DTO 정의

contact.dto.ts

// src/contact/dto/contact.dto.ts
import { IsString, Matches, MinLength, MaxLength } from 'class-validator';

export class ContactDto {
  @IsString()
  @MinLength(1)
  @MaxLength(50)
  name: string;

  @IsString()
  @Matches(/^01[016789]\d{7,8}$/) // 010, 011 등 휴대폰 번호 형식
  phone: string;

  @IsString()
  @MinLength(1)
  @MaxLength(1000)
  message: string;
}
  

4) Solapi 문자 발송 Service

sms.service.ts

// src/sms/sms.service.ts
import { Injectable, InternalServerErrorException, Logger } from '@nestjs/common';
import { SolapiMessageService } from 'solapi';

@Injectable()
export class SmsService {
  private readonly logger = new Logger(SmsService.name);
  private readonly client: SolapiMessageService;
  private readonly sender: string;
  private readonly adminPhone: string;

  constructor() {
    this.client = new SolapiMessageService(
      process.env.SOLAPI_API_KEY!,
      process.env.SOLAPI_API_SECRET!,
    );
    this.sender = process.env.SOLAPI_SENDER!;
    this.adminPhone = process.env.ADMIN_PHONE!;
  }

  /** 웹 문의 내용을 관리자 폰으로 문자 전송 */
  async sendContactToAdmin(params: { name: string; phone: string; message: string }) {
    const { name, phone, message } = params;

    const text = [
      '[웹 문의 도착]',
      '',
      `이름: ${name}`,
      `연락처: ${phone}`,
      '문의 내용:',
      message,
      '',
      '※ 위 번호를 탭해서 바로 문자로 답장하실 수 있습니다.',
    ].join('\\n');

    try {
      const res = await this.client.send({
        to: this.adminPhone,
        from: this.sender,
        text,
      });
      this.logger.log(`Contact SMS sent to admin: ${JSON.stringify(res)}`);
      return res;
    } catch (err) {
      this.logger.error('Failed to send SMS', err);
      throw new InternalServerErrorException('문의 알림 문자 발송에 실패했습니다.');
    }
  }
}
  

5) Controller – 문의 수신 API

contact.controller.ts

// src/contact/contact.controller.ts
import { Body, Controller, Post } from '@nestjs/common';
import { ContactDto } from './dto/contact.dto';
import { SmsService } from '../sms/sms.service';

@Controller('contact')
export class ContactController {
  constructor(private readonly smsService: SmsService) {}

  @Post()
  async submitContact(@Body() dto: ContactDto) {
    await this.smsService.sendContactToAdmin({
      name: dto.name,
      phone: dto.phone,
      message: dto.message,
    });

    return { success: true };
  }
}
  

6) NestJS Module 설정

sms.module.ts

// src/sms/sms.module.ts
import { Module } from '@nestjs/common';
import { SmsService } from './sms.service';

@Module({
  providers: [SmsService],
  exports: [SmsService],
})
export class SmsModule {}
  

contact.module.ts

// src/contact/contact.module.ts
import { Module } from '@nestjs/common';
import { ContactController } from './contact.controller';
import { SmsModule } from '../sms/sms.module';

@Module({
  imports: [SmsModule],
  controllers: [ContactController],
})
export class ContactModule {}
  

app.module.ts

// src/app.module.ts
import { Module } from '@nestjs/common';
import { ContactModule } from './contact/contact.module';
import { SmsModule } from './sms/sms.module';
import { ConfigModule } from '@nestjs/config';

@Module({
  imports: [SmsModule, ContactModule, ConfigModule.forRoot({ isGlobal: true })],
})
export class AppModule {}

동작 요약

  • 문의 폼 → POST /contact
  • NestJS가 SMS 서비스 호출 → Solapi API로 문자 발송
  • 관리자가 문자 수신 → 고객 번호 탭 → 문자 앱으로 바로 답장 가능

 

 

 

Solapi 문자 서비스 사용 절차 정리

Solapi(구 CoolSMS)는 API Key와 Secret Key만 발급받는다고 바로 문자 발송이 가능한 것이 아닙니다. 문자 발송을 위해 반드시 서비스 신청 / 발신번호 등록 절차를 완료해야 합니다.


✔ Solapi 문자 발송 서비스 사용 절차 (필수 단계)

단계 해야 할 것 필수 여부
1 회원가입 후 Solapi 콘솔 접속
2 프로젝트 생성 (콘솔 상단)
3 API Key / Secret Key 발급
4 발신번호 사전 등록 (문자 발신 번호 인증) 🔥 필수
5 SMS 서비스 이용 신청 (과금 방식 선택)
6 포인트 충전 또는 후불 요금 설정

특히 4번 발신번호 등록은 반드시 필요합니다.
한국 규정상 발신번호 사전 등록된 번호로만 문자 발송이 허용됩니다.


📌 발신번호 등록 시 유의사항

번호 유형 등록 가능 여부
개인 휴대폰 번호 ✔ 등록 가능
업무용/서브 휴대폰 번호 ✔ 등록 가능
050 안심번호 ✔ 등록 가능
회사 대표 전화번호 ✔ 등록 가능
임의의 번호 / 사칭 번호 ❌ 불가
가짜 번호 / 랜덤 번호 ❌ 불가

관리자 개인 휴대폰으로 문의 문자 알림을 받고 싶다면 Solapi 콘솔에서 해당 번호를 발신번호로 등록해두면 바로 사용 가능합니다.


📌 발신번호 등록 심사 속도

항목 소요 시간
API Key 발급 즉시
발신번호 등록 1–10분 정도
서비스 이용 신청 거의 즉시
포인트 충전 즉시 (카드 결제)

→ 보통 같은 날 바로 문자 발송 서비스 사용 가능


👉 실제 구축 환경에 맞는 요약

다음과 같은 흐름을 구성하는 경우 가장 자연스럽습니다.

웹 문의 → 백엔드(NestJS) → Solapi → 관리자의 휴대폰으로 문자 알림
관리자가 휴대폰으로 바로 고객에게 문자 답장
변수
발신번호 관리자 휴대폰 번호 (등록 필수)
문자 수신 번호 관리자 휴대폰 번호
고객 답장 번호 문자 본문에 고객 번호 표시

✔ 여기까지 하면 모든 준비 완료

☑ Solapi 계정 생성
☑ 프로젝트 생성
☑ API Key / Secret Key 복사
☑ 관리자 휴대폰 번호 발신번호로 등록
☑ 서비스 이용 신청
☑ 일부 포인트 충전
  

그 다음 서버의 .env에 아래처럼 등록하면 바로 운영할 수 있습니다.

SOLAPI_API_KEY=XXXX
SOLAPI_API_SECRET=XXXX
SOLAPI_SENDER=010관리자번호
ADMIN_PHONE=010관리자번호
  

 

 

###

 

.env 를 사용하기 위해 Nest.js 에 dotenv 를 install 하거나 @nestjs/config 를 install 하여 app module 시작 단이나 main.ts 에서 bootstrap에서 .env 파일을 사용하기 위한 설정을 우선적으로 수행해주어야 합니다.

 

###


실수할 수 있는 부분

실수 해결 방법
발신번호 등록 없이 문자 테스트 발신번호 승인 후 사용 가능
API Key만 입력한 후 오류 발생 서비스 신청 + 충전 필요
관리자 문자 수신은 되지만 답장이 고객에게 안 감 문자 본문에 고객 번호를 포함해 탭 후 바로 답장하도록 구성
문자 길이가 90Byte 초과 자동 LMS로 전환 → 비용 증가 주의

위만 알고 있으면 Solapi 문자 서비스는 거의 문제 없이 사용할 수 있습니다.

728x90
반응형
LIST