- esign-notification-guide.md 신규 작성 (환경별 설정, 역할 기반 알림, 템플릿 분기) - README.md 현황 업데이트 (완료 템플릿, OTP SMS, 환경별 분기 반영) - INDEX.md에 새 문서 등록
251 lines
9.4 KiB
Markdown
251 lines
9.4 KiB
Markdown
# 전자계약 알림톡/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`에 따라 템플릿명을 자동 결정한다:
|
|
|
|
```php
|
|
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 역할 판별
|
|
|
|
```php
|
|
$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**로 강제 변경된다:
|
|
|
|
```php
|
|
// 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 발송:
|
|
|
|
```php
|
|
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_ENV`가 `production`이 아닌지 확인
|
|
|
|
### 8.2 서명 PDF 누락 (이메일)
|
|
|
|
**증상**: 완료 이메일의 다운로드 링크가 서명 없는 초안 PDF 반환
|
|
**원인**: `mergeSignatures()` 실패 → `signed_file_path` 미설정 → preview PDF 폴백
|
|
**해결**: `downloadDocument()`가 완료 상태에서 자동 재생성 시도. 로그에서 trace 확인:
|
|
|
|
```bash
|
|
# 개발서버 로그 확인
|
|
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 핫픽스 완료)
|
|
|
|
---
|
|
|
|
## 관련 문서
|
|
|
|
- [바로빌 카카오톡 연동 README](./README.md) — SOAP API 전체 연동 가이드
|
|
- [E-Sign 기술 설계](../../projects/e-sign/technical-design.md) — 전자계약 아키텍처
|
|
- [E-Sign API 명세](../../projects/e-sign/api-specification.md) — API 엔드포인트
|
|
- [알림톡 연동 계획](../../plans/esign-alimtalk-integration.md) — 초기 계획 (구현 완료)
|
|
|
|
---
|
|
|
|
**최종 업데이트**: 2026-02-27
|