Solapi + NestJS 문자 발송 연동 방법 | 웹 문의 → 관리자 휴대폰 문자 알림 구현
이 글에서는 웹사이트의 문의 내용을 자동으로 관리자의 휴대폰 문자(SMS)로 보내는 기능을 Solapi 문자 API + NestJS로 구현하는 방법을 정리합니다.
고객은 웹에서 문의를 남기고, 관리자는 휴대폰 문자로 확인한 뒤 바로 답장할 수 있는 방식입니다.
📌 전체 동작 흐름
- 고객이 웹 문의 폼에서 이름 · 연락처 · 문의 내용을 입력
- 프론트엔드가 백엔드
POST /contactAPI 호출 - NestJS가 내용을 수신 후 Solapi를 통해 관리자 휴대폰 번호로 문자 전송
- 관리자는 문자 수신 → 내용 확인 후 고객 연락처로 바로 문자 답장
특징: 문의 저장 / 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로 문자 발송
- 관리자가 문자 수신 → 고객 번호 탭 → 문자 앱으로 바로 답장 가능