fix(core,message_bizppurio): 브랜치 검증 발견 결함 4건 — 스냅샷 회귀·조건부 skip·낡은 주석

출시 전 /validate-branch 통합 검증에서 발견한 결함을 처리한다.

- BindingShape 라우팅 diff 스냅샷이 중간 상태에서 구워져 HEAD 가 red 였다.
 발산 517건을 덤프해 신규 41건이 전부 객체·배열 리터럴 바인딩(구 정규식
 오판 계열)이고 유해 지점 스냅샷은 이미 green 임을 확인한 뒤 기록값을 맞춘다.
- 채널 잔재 정리 검증이 게시판 모듈 활성 환경에서만 실행돼 대부분의 실행에서
 미검증으로 남았다. 정리 로직이 소유자를 묻지 않는 실제 계약대로 모듈 소유
 정의를 테스트 안에서 구성해 무조건 실행되게 한다.
- activity_log 주석이 폐기된 설계(조회 전용 전환·콘솔 위임)를 서술하고 있어
 현행 사실로 정정한다. 사용자 문구는 바뀌지 않는다.
- 설정성 테이블의 상한 없는 조회 근거와 seeder 반환 키 타입을 코드에 남긴다.
This commit is contained in:
HeuJung
2026-08-24 17:03:42 +09:00
parent 0bccd867a7
commit 28d6a7752c
6 changed files with 55 additions and 16 deletions
@@ -72,7 +72,7 @@ class IdentityMessageDefinitionSeeder extends Seeder
* `extension_type='core'` / `extension_identifier='core'` 자동 주입. * `extension_type='core'` / `extension_identifier='core'` 자동 주입.
* `variables: '__common__'` 마커는 commonVariables() 로 expand. * `variables: '__common__'` 마커는 commonVariables() 로 expand.
* *
* @return array<int, array<string, mixed>> * @return array<string, array<string, mixed>> config 복합 키('mail.purpose.signup' 등) => 정의
*/ */
private function getDefaultDefinitions(): array private function getDefaultDefinitions(): array
{ {
@@ -1,9 +1,9 @@
<?php <?php
// The alimtalk template screen became read-only, so create/update/inspection/status-change // changelog:allow No user-facing string change — comment-only clarification.
// activity logs were removed. This plugin no longer writes activity logs (registration and // This plugin does not write activity logs yet. Define action/description keys here
// management are delegated to the Bizppurio console). Define action/description keys here
// when activity logging is added. // when activity logging is added.
// (Action labels live in the core lang/{ko,en}/activity_log.php SSoT — last-segment fallback.)
return [ return [
'action' => [], 'action' => [],
'description' => [], 'description' => [],
@@ -1,8 +1,9 @@
<?php <?php
// 알림톡 템플릿을 조회 전용으로 전환하면서 등록·수정·검수·상태변경 활동로그를 제거했다. // changelog:allow 사용자 문구 변경 없음 — 빈 배열 유지, 주석(안내)만 현행화
// 현재 이 플러그인은 활동로그를 기록하지 않는다(등록·관리는 비즈뿌리오 콘솔로 위임). // 이 플러그인은 현재 활동로그를 기록하지 않는다.
// 활동로그 기록을 추가할 때 action/description 키를 여기에 정의한다. // 활동로그 기록을 추가할 때 action/description 키를 여기에 정의한다.
// (action 라벨은 코어 lang/{ko,en}/activity_log.php 가 SSoT — 마지막 세그먼트 기준 fallback)
return [ return [
'action' => [], 'action' => [],
'description' => [], 'description' => [],
@@ -137,6 +137,9 @@ class BizppurioTemplateRepository implements BizppurioTemplateRepositoryInterfac
* 설정성 테이블 예외). 요약에 불필요한 대형 JSON(content/approved_content)은 제외하되, * 설정성 테이블 예외). 요약에 불필요한 대형 JSON(content/approved_content)은 제외하되,
* 반려 사유(inspection_detail)는 행 UI 의 [사유 보기]가 소비하므로 포함한다. * 반려 사유(inspection_detail)는 행 UI 의 [사유 보기]가 소비하므로 포함한다.
* *
* 행 수는 알림 정의 수(notification_type UNIQUE)에 묶인다 — 코어·확장이 선언한 알림
* 개수만큼만 존재하는 설정성 테이블이므로 상한 없는 get() 이 데이터 증가에 비례하지 않는다.
*
* @return Collection<int, BizppurioTemplate> 요약 컬럼만 실린 행 컬렉션 * @return Collection<int, BizppurioTemplate> 요약 컬럼만 실린 행 컬렉션
*/ */
public function allSummaries(): Collection public function allSummaries(): Collection
@@ -153,6 +156,9 @@ class BizppurioTemplateRepository implements BizppurioTemplateRepositoryInterfac
/** /**
* 특정 상태의 행 전체를 조회합니다 (동기화 커맨드 대상 선별). * 특정 상태의 행 전체를 조회합니다 (동기화 커맨드 대상 선별).
* *
* allSummaries() 와 같은 근거로 상한을 두지 않는다 — 알림 정의 수에 묶인 설정성 테이블의
* 부분집합이다.
*
* @param string $status BizppurioTemplateStatus value * @param string $status BizppurioTemplateStatus value
* @return Collection<int, BizppurioTemplate> * @return Collection<int, BizppurioTemplate>
*/ */
@@ -72,30 +72,62 @@ class ChannelTemplateCleanupOnUninstallTest extends PluginTestCase
/** /**
* 게시판·이커머스처럼 코어가 아닌 다른 모듈이 소유한 알림 정의도 동일하게, * 게시판·이커머스처럼 코어가 아닌 다른 모듈이 소유한 알림 정의도 동일하게,
* 정의 자체는 남고 우리 채널만 제거된다. * 정의 자체는 남고 우리 채널만 제거된다.
*
* 정리 로직(cleanupChannelContributions)은 소유자를 묻지 않고 "우리 채널 template 을
* 가진 정의" 를 대상으로 하므로, 실제 모듈 설치 여부에 의존하지 않고 모듈 소유 정의를
* 직접 구성해 검증한다 — 모듈이 활성화된 환경에서만 실행되는 조건부 테스트였다면 이
* 경로가 대부분의 실행에서 미검증으로 남는다(#597 브랜치 검증에서 교정).
*/ */
public function test_uninstall_시_모듈_소유_알림도_채널만_정리되고_정의는_보존된다(): void public function test_uninstall_시_모듈_소유_알림도_채널만_정리되고_정의는_보존된다(): void
{ {
$this->plugin->activate(); $this->plugin->activate();
$boardDefinition = NotificationDefinition::where('extension_identifier', 'sirsoft-board')->first(); $moduleDefinition = NotificationDefinition::create([
'type' => 'module_owned_notification_for_cleanup',
'hook_prefix' => 'sirsoft-board.post',
'extension_type' => 'module',
'extension_identifier' => 'sirsoft-board',
'name' => ['ko' => '모듈 소유 알림', 'en' => 'Module owned'],
'variables' => [],
'channels' => ['mail', 'sms', 'alimtalk'],
'hooks' => ['sirsoft-board.post.after_create'],
'is_active' => true,
]);
if (! $boardDefinition) { foreach (['mail', 'sms', 'alimtalk'] as $channel) {
$this->markTestSkipped('sirsoft-board 모듈이 활성화되지 않은 테스트 환경입니다.'); NotificationTemplate::create([
'definition_id' => $moduleDefinition->id,
'channel' => $channel,
'subject' => ['ko' => '제목'],
'body' => ['ko' => '본문'],
'recipients' => [['type' => 'trigger_user']],
'is_active' => true,
'is_default' => true,
]);
} }
$this->assertContains('sms', $boardDefinition->channels);
$this->plugin->uninstall(); $this->plugin->uninstall();
$boardDefinition->refresh(); $moduleDefinition->refresh();
$this->assertNotContains('sms', $boardDefinition->channels); $this->assertNotContains('sms', $moduleDefinition->channels);
$this->assertNotContains('alimtalk', $boardDefinition->channels); $this->assertNotContains('alimtalk', $moduleDefinition->channels);
$this->assertContains(
'mail',
$moduleDefinition->channels,
'모듈이 원래 갖고 있던 채널은 그대로 보존되어야 한다.'
);
$this->assertSame( $this->assertSame(
0, 0,
NotificationTemplate::where('definition_id', $boardDefinition->id) NotificationTemplate::where('definition_id', $moduleDefinition->id)
->whereIn('channel', ['sms', 'alimtalk']) ->whereIn('channel', ['sms', 'alimtalk'])
->count() ->count()
); );
$this->assertNotNull(
NotificationTemplate::where('definition_id', $moduleDefinition->id)
->where('channel', 'mail')
->first(),
'모듈 소유 정의의 mail 템플릿은 보존되어야 한다.'
);
} }
/** /**
@@ -86,7 +86,7 @@ exports[`BindingShape 라우팅 diff 하네스 > 단일 바인딩 판정: greedy
] ]
`; `;
exports[`BindingShape 라우팅 diff 하네스 > 단일 바인딩 판정: 구 정규식과 신 정본이 갈리는 총량 1`] = `516`; exports[`BindingShape 라우팅 diff 하네스 > 단일 바인딩 판정: 구 정규식과 신 정본이 갈리는 총량 1`] = `517`;
exports[`BindingShape 라우팅 diff 하네스 > 판정이 갈리는 식의 분류별 건수 요약 1`] = ` exports[`BindingShape 라우팅 diff 하네스 > 판정이 갈리는 식의 분류별 건수 요약 1`] = `
{ {