Files
sam-docs/sam/docs/features/barobill-kakaotalk/esign-notification-guide.md
김보곤 d24a19a3f1 docs: [esign] 전자계약 알림톡/SMS 환경별 설정 가이드 작성
- esign-notification-guide.md 신규 작성 (환경별 설정, 역할 기반 알림, 템플릿 분기)
- README.md 현황 업데이트 (완료 템플릿, OTP SMS, 환경별 분기 반영)
- INDEX.md에 새 문서 등록
2026-02-27 08:26:14 +09:00

9.4 KiB

전자계약 알림톡/SMS 환경별 설정 가이드

작성일: 2026-02-27 상태: 운영 중 대상 프로젝트: MNG


1. 개요

1.1 목적

전자계약(E-Sign) 시스템의 카카오톡 알림톡, SMS, 이메일 발송을 **3개 환경(로컬/개발/운영)**에서 올바르게 설정하고 테스트하기 위한 가이드이다.

1.2 핵심 원칙

  • 역할 기반 알림: 본사(creator)는 이메일, 상대방(counterpart)은 카카오톡/SMS
  • 환경별 템플릿 분리: 운영은 원본 템플릿, 개발은 _DEV 접미사 템플릿 사용
  • URL 자동 분기: config('app.url')로 환경별 도메인 자동 적용

2. 환경별 설정

2.1 도메인 및 APP_URL

환경 APP_ENV APP_URL 알림톡 버튼 URL 도메인
로컬 (Docker) local https://mng.sam.kr 로컬 — 알림톡 미사용
개발 서버 local https://admin.codebridge-x.com admin.codebridge-x.com
운영 서버 production https://mng.codebridge-x.com mng.codebridge-x.com

2.2 바로빌 서버 모드

barobill_members.server_mode 컬럼으로 바로빌 API 엔드포인트를 결정한다:

server_mode WSDL (카카오톡) WSDL (SMS) 용도
test testws.baroservice.com/KAKAOTALK.asmx testws.baroservice.com/SMS.asmx 테스트
production ws.baroservice.com/KAKAOTALK.asmx ws.baroservice.com/SMS.asmx 실제 발송

server_mode는 환경(로컬/개발/운영)과 독립적이다. 개발서버에서도 production 모드로 실제 발송 가능.

2.3 알림톡 템플릿 환경별 분기

코드에서 resolveTemplateName() 메서드가 APP_ENV에 따라 템플릿명을 자동 결정한다:

private function resolveTemplateName(string $baseName): string
{
    return $baseName . (app()->environment('production') ? '' : '_DEV');
}
기본 템플릿명 운영 (production) 개발/로컬 (기타)
전자계약_서명요청 전자계약_서명요청 전자계약_서명요청_DEV
전자계약_완료 전자계약_완료 전자계약_완료_DEV
전자계약_리마인드 전자계약_리마인드 전자계약_리마인드_DEV

3. 등록된 알림톡 템플릿

3.1 운영 템플릿 (mng.codebridge-x.com)

템플릿명 용도 상태 버튼 URL
전자계약_서명요청 서명 요청 알림 승인 완료 https://mng.codebridge-x.com/esign/sign/#{토큰}
전자계약_완료 서명 완료 알림 승인 완료 https://mng.codebridge-x.com/esign/sign/#{토큰}
전자계약_리마인드 서명 독촉 알림 승인 완료 https://mng.codebridge-x.com/esign/sign/#{토큰}

3.2 개발 템플릿 (admin.codebridge-x.com)

템플릿명 용도 상태 버튼 URL
전자계약_서명요청_DEV 서명 요청 알림 심사 중 https://admin.codebridge-x.com/esign/sign/#{토큰}
전자계약_완료_DEV 서명 완료 알림 심사 중 https://admin.codebridge-x.com/esign/sign/#{토큰}
전자계약_리마인드_DEV 서명 독촉 알림 심사 중 https://admin.codebridge-x.com/esign/sign/#{토큰}

개발 템플릿 본문은 운영 템플릿과 동일하며, 버튼 URL 도메인만 다르다.

3.3 템플릿 변수

변수 용도 사용 템플릿
#{이름} 서명자 이름 서명요청, 완료, 리마인드
#{계약명} 계약 제목 서명요청, 완료, 리마인드
#{기한} 서명 기한 서명요청, 리마인드
#{완료일} 계약 완료일 완료
#{토큰} 서명자 액세스 토큰 버튼 URL

4. 역할 기반 알림 흐름

4.1 전체 흐름

① 계약 발송 ─→ 본사: 이메일 / 상대방: 카카오톡 알림톡
② OTP 인증 ─→ 본사: 이메일 / 상대방: SMS
③ 다음 서명자 ─→ 본사: 이메일 / 상대방: 카카오톡 알림톡
④ 서명 완료 ─→ 본사: 이메일(PDF) / 상대방: 카카오톡(PDF 다운로드)

4.2 역할 판별

$isCounterpart = $signer->role === EsignSigner::ROLE_COUNTERPART;
역할 상수 알림톡 SMS(OTP) 이메일
본사 (creator) ROLE_CREATOR 항상
상대방 (counterpart) ROLE_COUNTERPART 우선 OTP만 폴백

4.3 이메일 폴백 조건

상대방(counterpart)에게도 이메일을 보내는 경우:

  • 전화번호가 없을 때 ($signer->phone 없음)
  • 알림톡 발송 실패 시 ($alimtalkFailed = true)
  • 발송 방식이 email 또는 both일 때

4.4 완료 알림 특수 처리

완료 알림톡 버튼은 서명 페이지가 아닌 문서 다운로드 URL로 강제 변경된다:

// sendCompletionAlimtalk() 내부
$documentUrl = config('app.url') . '/esign/sign/' . $signer->access_token . '/api/document';

// 버튼 URL 강제 변경 (서명페이지 → 문서 다운로드)
if (str_contains($btn[$urlKey], '/esign/sign/') && !str_contains($btn[$urlKey], '/api/document')) {
    $btn[$urlKey] = $documentUrl;
}

5. SMS (OTP 인증)

5.1 발송 조건

상대방(counterpart)이 alimtalk 또는 both 발송 방식이고 전화번호가 있을 때 SMS로 OTP 발송:

if (in_array($sendMethod, ['alimtalk', 'both'])
    && $signer->phone
    && $signer->role === EsignSigner::ROLE_COUNTERPART) {
    $this->sendOtpViaSms($contract, $signer, $otpCode);
}

5.2 SMS 발송 파라미터

항목
API BarobillService::sendSMSMessage()
발신번호 barobill_members.manager_hp
수신번호 esign_signers.phone
메시지 [SAM] 전자계약 인증코드: {코드} (5분 이내 입력)
OTP 유효시간 5분
최대 시도 5회

5.3 SMS 실패 시 이메일 폴백

SMS 발송 실패 → 이메일 OTP 폴백 → 이메일도 없으면 500 에러 반환.


6. 바로빌 템플릿 등록 절차

6.1 관리자 페이지

https://www.barobill.co.kr 로그인 → 카카오톡 → 템플릿관리

6.2 DEV 템플릿 등록 시 주의사항

  1. 본문: 운영 템플릿과 완전히 동일 (1글자도 다르면 안 됨)
  2. 버튼 URL: 도메인만 admin.codebridge-x.com으로 변경
  3. 템플릿명: 운영 이름 + _DEV 접미사 (예: 전자계약_서명요청_DEV)
  4. 검수 기간: 영업일 기준 2~3일

6.3 새 템플릿 추가 시 체크리스트

  • 바로빌에서 운영용 + 개발용 2개 등록
  • 코드에서 resolveTemplateName('기본명')으로 호출
  • 본문의 변수 치환 로직 추가 (str_replace)
  • 버튼 URL의 #{토큰} 치환 확인
  • 2단계 검증 (SendKey → GetSendKakaotalk) 포함

7. 관련 파일

파일 역할
app/Http/Controllers/ESign/EsignApiController.php 계약 발송, sendAlimtalk(), resolveTemplateName()
app/Http/Controllers/ESign/EsignPublicController.php OTP SMS, 완료 알림톡, sendCompletionAlimtalk()
app/Services/Barobill/BarobillService.php SOAP 클라이언트 (sendATKakaotalkEx, sendSMSMessage)
app/Models/ESign/EsignSigner.php ROLE_CREATOR, ROLE_COUNTERPART 상수
app/Mail/EsignCompletedMail.php 완료 이메일 (PDF 다운로드 링크)
app/Services/ESign/PdfSignatureService.php 서명 PDF 합성 (mergeSignatures)

8. 트러블슈팅

8.1 환경별 템플릿 미스매치

증상: ResultCode=4 (템플릿 데이터 일치 오류) 원인: 개발서버에서 운영용 템플릿(전자계약_서명요청)으로 발송 시 버튼 URL 도메인 불일치 해결: DEV 템플릿 등록 후 APP_ENVproduction이 아닌지 확인

8.2 서명 PDF 누락 (이메일)

증상: 완료 이메일의 다운로드 링크가 서명 없는 초안 PDF 반환 원인: mergeSignatures() 실패 → signed_file_path 미설정 → preview PDF 폴백 해결: downloadDocument()가 완료 상태에서 자동 재생성 시도. 로그에서 trace 확인:

# 개발서버 로그 확인
ssh pro@114.203.209.83 "tail -100 /home/webservice/mng/storage/logs/laravel.log | grep 'PDF 서명'"

주요 실패 원인:

  • storage/fonts/Pretendard-Regular.ttf 폰트 파일 누락
  • FPDI/TCPDF 패키지 미설치 → composer install 필요
  • storage/app/esign/{tenant_id}/signed/ 디렉토리 권한 문제

8.3 MNG 모델 상수 누락

증상: Undefined constant App\Models\ESign\EsignSigner::ROLE_COUNTERPART 원인: API 프로젝트와 MNG 프로젝트의 모델이 독립적 — API에만 상수 정의됨 해결: MNG EsignSigner.php에도 동일한 상수 추가 (2026-02-26 핫픽스 완료)


관련 문서


최종 업데이트: 2026-02-27