fix(message_bizppurio): 설치 시 문자·알림톡 채널 템플릿 자동 시딩

PluginManager::activatePlugin 이 status=active 로 바꾸기 전에 activate 를
호출하므로, 그 시점엔 SeedChannelTemplatesListener 가 아직 등록되지 않아 재시딩이
sms·alimtalk 채널 template 을 붙이지 못했다(알림 설정 탭이 비어 토글도 미노출).

activate 가 재시딩 전에 해당 리스너를 명시적으로 선등록하도록 수정. register
는 동일 프로세스 내 중복 등록을 막으므로 멱등하며, 코어는 수정하지 않는다.

- plugin.php: activate 에 리스너 선등록 추가
- 회귀 테스트: activate 후 sms·alimtalk 템플릿 생성 검증 (fail→green)
- CHANGELOG: working(1.0.0) Added 항목에 설치 시 자동 시딩 문구 흡수
This commit is contained in:
chym1217
2026-07-28 12:36:27 +09:00
parent 11f1d79540
commit 5e9d046812
3 changed files with 76 additions and 3 deletions
@@ -13,7 +13,7 @@
- 발송 결과(리포트)를 받을 수신 주소를 설정 화면에서 확인·복사할 수 있습니다. 이 주소를 비즈뿌리오에 등록하면 발송 결과가 이력에 자동 기록됩니다.
- 비즈뿌리오 메시지 발송 기능에 대한 조회·관리 권한을 추가했습니다. 관련 화면은 플러그인 설정 페이지에서 진입합니다.
- 비즈뿌리오 지갑 잔액이 부족할 때 관리자에게 알리는 알림을 추가했습니다.
- 회원가입·주문 등의 알림을 문자(SMS/LMS)로 자동 발송하는 채널을 알림 설정에 추가했습니다. 본문 길이에 따라 SMS·LMS 가 자동으로 선택되며, 발신 정보가 설정되지 않은 경우 어떤 항목을 채워야 하는지 안내합니다.
- 회원가입·주문 등의 알림을 문자(SMS/LMS)로 자동 발송하는 채널을 알림 설정에 추가했습니다. 본문 길이에 따라 SMS·LMS 가 자동으로 선택되며, 발신 정보가 설정되지 않은 경우 어떤 항목을 채워야 하는지 안내합니다. 플러그인을 설치하면 회원 대상 알림의 문자·알림톡 채널 기본 템플릿(제목·본문·수신자)이 알림 설정에 자동으로 채워져, 바로 켜고 편집할 수 있습니다.
- 비회원 주문 알림도 주문 시 입력한 연락처로 문자를 받을 수 있습니다.
- 카카오 알림톡 채널을 알림 설정에 추가했습니다. (알림톡 실제 발송·템플릿 연동은 후속 단계에서 제공됩니다.)
- 비즈뿌리오가 보내는 발송 결과 통보를 받아 각 발송의 실제 도달 여부(성공/실패)를 기록합니다. 실패한 경우 사유를 함께 확인할 수 있습니다(예: 음영 지역, 잘못된 번호, 스팸 차단, 지갑 잔액 부족 등).
@@ -21,6 +21,13 @@
- 지갑 잔액 부족으로 발송이 실패하면 관리자에게 알립니다. 대량 실패 시 알림이 반복 발송되지 않도록 일정 시간 간격으로 한 번만 안내합니다.
- 설정 페이지의 알림톡 템플릿 탭에서 카카오 알림톡 템플릿을 직접 등록·수정·삭제하고 검수를 요청할 수 있습니다. 등록한 템플릿의 상태(발송가능·검수중·반려·미검수·중지 등)를 배지로 확인하고, 상태별로 가능한 관리 동작(검수 요청·중지·승인 취소 등)을 바로 실행할 수 있습니다.
- 템플릿 등록 화면에서 템플릿명·템플릿 코드(자동 생성 또는 직접 입력)·카테고리(대분류/소분류)·템플릿 유형(기본형·이미지형·강조표기형)·본문을 입력하고, 우측에서 실시간 미리보기를 확인할 수 있습니다. 이미지형은 이미지를 첨부하면 자동으로 업로드됩니다. (아이템리스트형 등 고급 유형은 비즈뿌리오 홈페이지에서 등록한 뒤에도 목록에서 함께 관리할 수 있습니다.)
- 본문에 넣을 수 있는 변수를 클릭하면 커서 위치에 바로 삽입되며, 알림 종류별로 제공되는 변수 예시를 참고표로 함께 안내합니다.
- 선택 항목(부가정보·미리보기 메시지·버튼·바로연결·대표 링크·템플릿 보안)을 체크해 필요한 것만 펼쳐 입력할 수 있습니다.
- 본문에 넣을 수 있는 변수를 회원가입·비밀번호 관련 알림별로 참고표에 정리해 항상 보여줍니다. 그 밖의 알림 변수는 해당 알림의 모듈/플러그인 설정에서 확인하도록 안내합니다.
- 선택 항목(부가정보·버튼·대표 링크·미리보기 메시지·템플릿 보안)을 필요한 것만 체크해 입력할 수 있습니다.
- 버튼은 최대 5개까지 추가할 수 있으며, 버튼 종류(웹링크·앱링크·채널추가·전화하기·배송조회 등)에 따라 필요한 입력란(모바일/PC 링크·전화번호·플러그인 ID 등)이 자동으로 나타납니다. 각 입력란에는 필수·선택 여부가 표시됩니다.
- 버튼 입력값을 카카오 규격에 맞게 검사합니다. 웹링크 주소는 http/https 형식, 앱링크는 안드로이드·iOS·모바일 중 2개 이상(전화연결 링크 불가), 전화하기 버튼명은 "전화 연결·고객센터 연결·상담원 연결" 중 하나, 대표 링크의 PC·모바일 주소는 웹 주소 형식이어야 합니다. 잘못 입력하면 어느 버튼의 어느 항목인지 알기 쉽게 안내합니다.
- 템플릿 보안(OTP)과 미리보기 메시지는 함께 쓸 수 없어, 한쪽을 켜면 다른 쪽 선택이 잠기고 그 이유를 안내합니다.
- 입력란마다 현재 글자 수와 최대 글자 수를 실시간으로 표시해, 카카오 규격을 넘지 않도록 돕습니다.
- 목록 화면과 등록 화면 상단에 템플릿 승인·검수 절차와 작성 규칙(정보성 메시지만 가능, 수신 근거 문구 권장, 등록 후에도 카카오 심사에서 반려될 수 있음)을 안내합니다.
- 등록 화면의 실시간 미리보기가 입력 폼 옆에 고정되어, 긴 폼을 스크롤하며 입력해도 미리보기를 계속 볼 수 있습니다.
- 템플릿 등록·수정이 실패하면 카카오가 알려준 실제 사유(예: 접근 불가 IP, 반려 사유 등)를 화면에 그대로 표시합니다.
- 템플릿은 [등록]으로 임시 저장하거나 [등록 후 검수요청]으로 등록과 동시에 카카오 검수를 요청할 수 있습니다.
@@ -5,6 +5,7 @@ namespace Plugins\Sirsoft\MessageBizppurio;
use App\Enums\ExtensionOwnerType;
use App\Extension\AbstractPlugin;
use App\Extension\Helpers\ExtensionMenuSyncHelper;
use App\Extension\HookListenerRegistrar;
use App\Extension\ModuleManager;
use Database\Seeders\NotificationDefinitionSeeder;
use Illuminate\Support\Facades\Log;
@@ -50,11 +51,21 @@ class Plugin extends AbstractPlugin
* 실패는 로그만 남기고 활성화 자체는 막지 않는다(발송·연동은 채널 등록만으로도 동작하며,
* template 은 다음 정상 재시딩에도 수렴).
*
* 리스너 선등록: PluginManager::activatePlugin() 은 DB status 를 active 로 바꾸기
* '전에' 이 activate() 를 호출한다. 그런데 registerPluginHookListeners() 의 active 가드는
* status=active 인 플러그인의 리스너만 등록하므로, 이 시점엔 SeedChannelTemplatesListener 가
* 아직 등록되지 않았다. 그대로 재시딩하면 시딩 필터에 우리 리스너가 편승하지 못해
* sms·alimtalk 채널 template 이 붙지 않는다(실서버 회귀). 따라서 재시딩 전에 이 리스너를
* 명시적으로 선등록한다. register() 는 동일 process 내 중복 등록을 막으므로 멱등하다.
*
* @return bool 활성화 성공 여부
*/
public function activate(): bool
{
try {
// 재시딩이 편승할 시딩 필터 리스너를 status=active 전환 이전에 명시적으로 등록한다.
HookListenerRegistrar::register(SeedChannelTemplatesListener::class, $this->getIdentifier());
app(NotificationDefinitionSeeder::class)->run();
app(ModuleManager::class)->resyncAllActiveDeclarativeArtifacts();
} catch (\Throwable $e) {
@@ -0,0 +1,55 @@
<?php
namespace Plugins\Sirsoft\MessageBizppurio\Tests\Feature\Installation;
use App\Models\NotificationTemplate;
use Database\Seeders\NotificationDefinitionSeeder;
use Plugins\Sirsoft\MessageBizppurio\Plugin;
use Plugins\Sirsoft\MessageBizppurio\Tests\PluginTestCase;
/**
* 활성화 시 코어/모듈 회원 알림에 sms·alimtalk 채널 템플릿이 자동 생성되는지 검증한다.
*
* 배경(실서버 회귀): 코어/모듈 알림 정의는 플러그인 설치 이전에 이미 DB 로 시딩돼 있고
* (mail·database 만), sms·alimtalk 채널은 SeedChannelTemplatesListener 가 시딩 필터 훅에
* 편승해 증강한다. 그러나 PluginManager::activatePlugin() 은 status 를 active 로 바꾸기
* '전에' Plugin::activate() 를 호출하므로, activate() 안의 재시딩 시점엔 이 리스너가
* 아직 자동 등록되지 않아 sms·alimtalk 이 붙지 않았다.
*
* 수정: Plugin::activate() 가 재시딩 전에 SeedChannelTemplatesListener 를 명시적으로
* 선등록하도록 하여, 설치/재활성화만으로 채널 템플릿이 채워지게 한다.
*/
class ChannelTemplateSeedOnActivateTest extends PluginTestCase
{
/**
* 활성화 전(리스너 미등록) 코어 알림을 시딩하면 sms·alimtalk 이 없다가,
* 활성화 후 회원 알림에 두 채널 템플릿이 생성된다.
*/
public function test_activate_시_회원_알림에_sms_alimtalk_템플릿이_생성된다(): void
{
// [준비] 설치 이전 상태 모사: 리스너가 등록되지 않은 채 코어 알림 정의 시딩.
// PluginTestCase 가 훅을 격리하므로 이 시점엔 SeedChannelTemplatesListener 가 없다.
app(NotificationDefinitionSeeder::class)->run();
$this->assertSame(
0,
NotificationTemplate::whereIn('channel', ['sms', 'alimtalk'])->count(),
'활성화 전에는 sms·alimtalk 채널 템플릿이 없어야 한다(설치 전 상태).'
);
// [실행] 정식 활성화 진입점. 이 안에서 리스너 선등록 → 재시딩이 채널을 증강해야 한다.
(new Plugin)->activate();
// [검증] 회원 대상 코어 알림(welcome 등)에 sms·alimtalk 템플릿이 생성됐다.
$this->assertGreaterThan(
0,
NotificationTemplate::where('channel', 'sms')->count(),
'activate() 후 sms 채널 템플릿이 회원 알림에 생성돼야 한다.'
);
$this->assertGreaterThan(
0,
NotificationTemplate::where('channel', 'alimtalk')->count(),
'activate() 후 alimtalk 채널 템플릿이 회원 알림에 생성돼야 한다.'
);
}
}