여행 산업을 위한 WhatsApp + VOIP 기반 멀티 테넌트(Multi-tenant) CRM 구축 경험
요약
여행 산업을 위한 WhatsApp 및 VOIP 통합 멀티 테넌트 CRM 구축 경험을 공유합니다. 초기 설계 단계에서의 테넌트 격리 적용, 메시징 계층의 추상화, 그리고 WebRTC 기반 VOIP 구현 시 직면한 기술적 도전 과제들을 다룹니다.
핵심 포인트
- 설계 초기 단계부터 데이터 계층의 테넌트 격리(Multi-tenancy) 적용 필수
- BSP 변경에 유연하게 대응하기 위해 메시징 계층을 미들웨어로 추상화
- WebRTC 구현 시 NAT 트래버설을 위한 TURN 서버 설정의 중요성
- SIP 포트 노출에 따른 보안 위협(Brute-force) 대비 필요
여행사들은 혼돈 속에서 운영됩니다. 세 명의 상담원이 하루에 처리하는 40개의 WhatsApp 문의, 일정 변경에 관한 전화 통화, 환불에 관한 이메일 등 대부분의 여행사는 브라우저 탭, 스프레드시트, 그리고 기도(prayer)에 의지해 이 모든 것을 관리합니다.
저는 지난 몇 년 동안 여행사를 위해 WhatsApp Business, 음성 통화, 이메일을 하나의 공유 워크스페이스로 통합하는 멀티 테넌트 (Multi-tenant) CRM인 Airdesk Solutions Private Limited를 구축하는 데 시간을 보냈습니다. 고통스러웠던 부분을 포함하여 실제로 어떤 과정이 있었는지 소개합니다.
핵심 아키텍처 결정: 첫날부터 멀티 테넌시 (Multi-tenancy) 적용
여행사는 종종 여러 지점을 운영하며, B2B 컨솔리데이터 (Consolidators)는 하위 에이전트 네트워크에 서비스를 제공합니다. 이는 테넌트 격리 (Tenant isolation)가 사후 고려 사항이 되어서는 안 된다는 것을 의미했습니다. 모든 대화, 예약, 지갑 트랜잭션 및 권한 확인은 데이터 계층에서 테넌트 범위 (Tenant-scoped)로 지정됩니다. 나중에 이를 소급 적용하는 것은 재작성(Rewrite)을 의미했을 것입니다. 처음부터 구축하는 것은 v1 개발 속도를 늦췄지만, 그 이후의 모든 과정을 더 저렴하게 만들었습니다.
기술 스택: 프론트엔드는 Next.js/React, 백엔드는 Node.js 서비스, 데이터는 MongoDB, 파일 저장소는 Cloudflare R2를 사용하며 모두 Hetzner에서 실행됩니다.
WhatsApp Business API: BSP 문제
단순히 "WhatsApp을 연결"할 수는 없습니다. 비즈니스 솔루션 제공업체 (BSP, Business Solution Provider)를 거쳐야 합니다. 저희는 하나의 BSP로 시작하여 WATI/360dialog로 이동하고 있으며, 여기서 얻은 교훈은 다음과 같습니다. 처음부터 메시징 계층을 자체적인 웹후크 (Webhook) 미들웨어 뒤로 추상화하십시오. BSP들은 웹후크 페이로드 형태, 템플릿 처리 및 세션 규칙이 서로 다릅니다. 만약 CRM 로직이 자체적인 정규화된 메시지 모델 (Normalized message model)이 아닌 BSP와 직접 통신하게 된다면, 제공업체를 변경하는 작업은 설정 변경이 아닌 수술과 같은 고통스러운 작업이 될 것입니다.
어려운 제품 문제는 메시지를 받는 것이 아니라 공유 편지함 (Shared-inbox)의 의미론 (Semantics)입니다. 즉, 누가 이 대화를 소유하는지, 두 명의 상담원이 동일한 채팅을 열었을 때 어떤 일이 발생하는지, 그리고 고객이 눈치채지 못하게 자동화가 어떻게 상담원에게 업무를 인계하는지 등의 문제입니다.
VOIP: 아무도 경고해주지 않는 부분
우리는 Hetzner 서버에서 Asterisk를 실행하며, Node.js AMI (Asterisk Manager Interface) 서비스를 통해 관리자 백엔드와 브릿지(bridge)를 연결합니다. 브라우저 기반 통화는 WebRTC를 의미하며, WebRTC를 사용한다는 것은 다음을 의미합니다:
- 클라이언트 측의 SIP.js를 이용한 WebSocket 기반의 SIP (SIP over WebSocket)
- NAT 트래버설 (NAT traversal)을 위한 coturn TURN 서버 (이것이 없으면 "전화는 연결되는데 소리가 들리지 않아요"가 가장 흔한 버그 리포트가 됩니다)
- 창의적인 방식으로 서로 충돌하는 방화벽 규칙 (iptables/UFW)
- fail2ban (SIP 포트가 공개되는 순간, 몇 시간 내로 무차별 대입 등록 시도(brute-force registration attempts)가 시작되기 때문)
단방향 오디오(One-way audio) 문제 하나만으로도 그 어떤 네트워킹 강의보다 NAT에 대해 더 많은 것을 배웠습니다. 만약 SaaS 제품에 통화 기능을 추가하려 한다면, 전화 기술(telephony) 구현에 예상보다 3배의 시간을 할당하세요.
버티컬 SaaS (Vertical SaaS)를 구축하려는 모든 이들에게 해주고 싶은 말:
-
진정으로 다른 워크플로우를 가진 버티컬(Vertical)을 선택하세요. 여행 산업은 단순히 "영업 파이프라인 + 커스텀 필드"가 아닙니다. 예약, 에이전트 지갑, 공급업체 원장(supplier ledgers)의 특이점들은 범용 CRM이 정말로 맞지 않음을 의미하며, 바로 그 점이 해자(moat)가 됩니다.
-
통합 경계(integration boundaries)를 직접 제어하세요. 외부 API(BSP, 전화 기술 등)를 즉시 자체 모델로 정규화(Normalize)하세요.
-
멀티 테넌트 격리(Multi-tenant isolation)는 단순한 아키텍처 선택이 아니라 판매해야 할 기능입니다. 대행사들은 모든 데모에서 데이터 분리에 대해 문의합니다.
-
인프라는 곧 제품입니다. 여행 에이전트의 소프트폰(softphone) 통화가 끊겼을 때, 그들은 그것이 누구의 TURN 서버였는지 신경 쓰지 않습니다.
이 내용 중 어떤 것이든 댓글로 더 깊게 논의할 준비가 되어 있습니다. 특히 제 의견이 꽤 많은 Asterisk/WebRTC 측면에 대해서 말이죠.
Airdesk가 어떻게 완성되었는지 궁금하시다면 www.theairdesk.com에서 확인하실 수 있습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기