스코프 검증 통과 직후·Post 락 획득 시점 사이에 게시글이 삭제되면
lockForUpdate 의 findOrFail 이 ModelNotFoundException 을 던지는데, 컨트롤러가
이 예외를 모르므로 일반 500 으로 새어나가 사용자가 "반응 처리에 실패했습니다"
라는 원인 불명 메시지만 보게 되던 문제를 수정. 이미 존재를 확인한 게시글이
사라진 것과 같은 의미이므로 PostNotFoundException 으로 변환해 404 로 일관 처리.
빠른 반응 전환 시 캐시된 reaction_counts 가 실제 board_reactions 행 수와
어긋나던 결함을 Post 락 직렬화 + 실제 COUNT 재집계 방식으로 수정. 반응
버튼에 aria-pressed/aria-disabled 를 추가해 스크린리더가 상태를 인지하도록
보완. 신규 게시판 생성 폼의 반응 유형 체크박스 초기값 누락, 본인 글 반응
클릭 시 안내 토스트 부재도 함께 수정.
게시판 설정 일괄 적용 화면의 대상 게시판 선택을 카드형으로 개선하고
"반응 사용" 필드 번역 키 누락(ko/en/ja)을 수정. TagInput 컴포넌트가
드롭다운 메뉴 포탈에 react-select 기본 z-index(1)를 그대로 둬 sticky
하단 버튼바에 가려지던 결함을 styles.menuPortal 오버라이드로 수정.
- 열람 권한 없는 비밀글에 추천/비추천을 남길 수 있던 결함을 서버(ReactionService)와
화면(반응 영역 미노출) 양쪽에서 차단. 신고 기능과 동일한 권한 판정 기준 재사용.
- 반응 버튼 UX를 다듬어 활성 상태는 색상으로만 표시하고, 클릭 순간에만 살짝 눌리는
촉각 피드백(active:scale-95)을 추가.
- 이슈 명세 재검토 중 describe.skip 상태였던 반응 E2E spec 에서 결함 3건 발견·수정:
대상 게시판/게시글이 실제로 반응 불가능한 대상이었던 점, 3단계(해제) 검증이 값
우연 일치로 거짓 통과 가능했던 점을 고치고 실제 실행으로 통과 확인.
빌드 스크립트로 ja 언어팩 누락 키 증분 동기화.
- g7-module-sirsoft-board-ja: 반응 메시지·검증·활동 로그·관리자 설정 20키 번역 추가
- g7-template-sirsoft-basic-ja: 반응 버튼 로그인·실패 안내 2키 번역 추가
- 각 ja 팩 CHANGELOG 항목 누적 (미릴리스 working 섹션)
Chrome MCP 검수 중 발견한 결함 수정 및 요청 반영.
- 게시글 상세 응답의 reaction_counts 가 배열로 붕괴되어 개수가 0으로
표시되던 문제 수정 (PostResource → stdClass 로 JSON 객체 보장) + 회귀 테스트
- 반응 버튼을 수정·삭제 버튼과 같은 줄에 배치
- 반응 UX 개선: 클릭 즉시 하이라이트 반영 + 개수는 응답값으로 갱신(전체
재조회 제거) + 처리 중 로딩·중복클릭 차단 + 실패 시 롤백·안내
- board.md 상세 응답 필드 + basic CHANGELOG + 시나리오 매니페스트 갱신
5단계 마무리 — 기능 동작 확인 후 마감.
- tests/scenarios/board-reaction.yaml: 단일 case 축 18조합 + effects 22개,
각 테스트에 @scenario/@effects 마킹 (test-scenario-coverage 통과)
- board-reaction-flow.spec.ts: 등록→전환→해제 E2E (describe.skip, 토큰 환경 해제)
+ reactionToken fixture
- 부수 테스트: react 활동 로그 기록, 새 게시판 반응 기본값 시드(확정 13)
- board/basic CHANGELOG Added 에 반응 기능 기재 (working 버전 누적, +2 아님)
ja 언어팩 동기화는 ANTHROPIC_API_KEY( 환경) 필요 — 후속 진행.
4단계 화면 3면 + 백엔드 수용.
- 게시글 상세(show.json): 신고 버튼 위에 반응 영역 — use_reaction &&
유형 존재 시 노출, 유형 iteration(아이콘+라벨+개수, 0도 노출), 본인 글 비활성화,
같은 유형 재클릭=해제·다른 유형=전환, 비로그인 안내 후 로그인 유도
- 관리 설정 기본값 탭 + 개별 게시판 편집 폼: 반응 사용 토글 + 유형 체크박스
(reactionTypes data_source iteration, active_reaction_types code 토글)
- FormRequest(Store/Update Board, Store/BulkApply Settings)에 use_reaction·
active_reaction_types 화이트리스트/캐스트/시드 추가 (미추가 시 토글 미저장)
- BoardResource.icon_name(fa-* 토큰) — Icon 컴포넌트 접두사 중복 방지
- ko/en 다국어 + boards/settings API 문서 갱신
- Vitest 10건(템플릿 4 + 모듈 6) green, board 관리/설정 87건 회귀 green
ja 언어팩·시나리오 매니페스트·E2E·버전 bump·CHANGELOG 는 5단계.
설정 저장 시 토큰 캐시를 무효화하여 비밀번호 변경 후 최대 23시간 옛
자격증명이 재사용되던 문제를 해소하고, 저장된 계정/비밀번호를 그
자리에서 검증하는 "연결 확인" 버튼을 추가한다. 비밀번호 필드 라벨을
G7 로그인 비밀번호와 구분되도록 정정하고, 토큰 발급 실패 시 비즈뿌리오
원문 사유를 노출해 원인 추적을 돕는다.
PR 전 마지막 재검토에서 남겨뒀던 두 항목을 처리한다.
- 게스트 세션 쿠키 HMAC 서명에 만료시각을 추가했다. 결제 플러그인
(IssuesReceiptCookie)과 동일하게 값 형식을 {uuid}|{만료시각}|{서명}
3단 구조로 바꾸고, 서명 자체가 만료시각도 함께 해시하므로 만료시각만
위조해 유효기간을 늘리는 시도도 차단된다. 만료 기간은 쿠키 자체의
브라우저 만료(1년)와 동일하게 맞췄다 — 결제 정보가 아닌 쿠키 선호도
식별자라 짧게 잘라 잦은 재발급을 강제할 실익이 없다.
- 관리자 설정 화면의 정책 버전 이력 토글 버튼에서 sequence handler의
actions 배열이 params 안에 잘못 중첩되어 있던 걸 발견해 바로잡았다.
엔진(ActionDispatcher.handleSequence)이 두 위치를 모두 인식하는
fallback을 갖고 있어 실제 동작은 정상이었지만, 정석 위치(top-level)로
정리하고 실제 클릭 시 이력 표가 펼쳐지는지 검증하는 E2E를 추가했다.
가 GDPR 관리자 설정 화면 스크린샷에서 카드 제목만 다른 확장과 달리
빨간색으로 표시되는 것을 발견해 지시했다.
「운영 주체」·「쿠키 동의 배너」·「자동 차단 정책」 카드 제목과 차단
도메인 안내 소제목이 에러/경고 전용 시맨틱(text-error-strong, red 계열)을
잘못 사용하고 있었다. 일반 카드 제목이므로 다른 정상 카드와 동일한
중립 톤(section-heading-md)으로 교체.
원래 develop 에 이미 있던 기존 결함이며 다른 확장(marketing,
pay_kginicis 등)에도 동일 패턴이 있으나, 이번엔 GDPR 플러그인 범위로
한정해 수정한다.
기존 Vitest 회귀 가드가 이 색상 버그를 "의도된 설계"로 잘못 확정해두고
있어 함께 뒤집었고, 실제 브라우저에서 색상을 검증하는 E2E 테스트도
추가했다(computed style RGB 값 검사).
PR 생성 직전 마지막 점검으로 변경분 전체를 라인 단위 재검토한 결과,
직전 커밋에서 신규 작성한 게스트→로그인 배너 재노출 E2E 시드 커맨드
(PlaywrightSeedGdprGuestLogin)에서 2건을 발견해 수정한다.
- 로그인 테스트 계정 비밀번호가 코드에 고정 문자열로 박혀 있어, 실수로
프로덕션 DB에서 실행되면 알려진 비밀번호로 로그인 가능한 계정이
남는 위험이 있었다. 실행마다 Str::random(32)로 무작위 생성하도록
변경.
- 이메일/게스트 세션 ID를 매번 새로 발급해 재실행할 때마다 계정과
동의 이력이 계속 누적됐다. 고정값으로 바꾸고 재실행 시 기존 데이터를
먼저 삭제하도록 변경(sirsoft-page 모듈의 선삭제 패턴과 동일).
2회 연속 실행 후 DB 조회로 누적되지 않음을 확인.
부수: cookie_banner.json 의 배너 재노출 조건에 "회원 로그인 후 로그아웃"
케이스가 회귀 테스트로 고정되어 있지 않아 추가 (로직 자체는 기존에도
정상 동작 확인됨 — 커버리지 보강).
이슈 체크리스트와는 별개로, 처리 완료 후 지시로 진행한
sirsoft-gdpr 플러그인 전수 비판적 검토에서 발견한 보안·결함 3건을
수정한다.
- Admin 설정 저장 API 의 검증 우회 fallback(빈 요청 시 $request->all
사용) 제거. UpdateAdminSettingsRequest 필드가 모두 nullable 이라
검증을 거치지 않은 임의 키가 저장 로직까지 전달될 수 있었다.
- 게스트 세션 식별 쿠키(gdpr_session) 에 HMAC-SHA256 서명 적용.
api 미들웨어 그룹에는 EncryptCookies 가 없어 쿠키가 평문으로 오가
임의 UUID로 타인의 게스트 동의 상태를 조회/철회할 수 있었다.
결제 플러그인들의 IssuesReceiptCookie 트레이트와 동일 컨벤션 채택.
이 조치로 배포 이전 발급된 비회원 쿠키는 1회 초기화되며 이미
배너를 닫았던 비회원은 다음 방문 시 배너를 다시 보게 된다(회원
동의 이력은 영향 없음) — CHANGELOG 에 고지.
- 게스트로 쿠키 배너를 닫은 뒤 동의 이력 없는 다른 계정으로 로그인해도
배너가 계속 숨겨져 있던 결함 수정. _global.gdprBannerDismissedFor 가
"닫힘 여부"(boolean) 대신 "누가 닫았는지"(사용자 식별자)를 저장하도록
변경해, 로그인으로 사용자가 바뀌면 다시 노출되게 한다. 실제 로그인
폼 제출을 거쳐 재현하는 E2E spec 신규 작성(PlaywrightSeedGdprGuestLogin
시드 커맨드 포함, sirsoft-page 의 PlaywrightSeedPage 패턴 재사용).
부수: 자동 차단 정책 안내에 보호 범위 한계 고지 추가, GDPR 플러그인
번들 로딩 우선순위 상향(다른 확장의 스크립트로부터 보호 범위 확대).
banner_enabled(쿠키 배너 노출) 토글 안내가 "마이페이지 동의 관리 카드"까지
함께 켜지고 꺼지는 것처럼 서술되어 있었으나, 실제로는 카드가 이 토글과
무관하게 동의/철회 이력이 있는 회원에게 항상 노출된다(GDPR Art.7(3) 철회
대칭성 보장, mypage_privacy_tab.json 회귀 가드로 이미 고정된 설계).
문구만 실제 동작과 어긋나 있어 ko/en 양쪽 hint 및 관련 코드 주석을
바로잡았다.
문구 확인 과정에서 field_legal_entity_name / field_data_storage_location /
field_banner_enabled / field_banner_position 4개 필드가 텍스트 스타일
전용 클래스(section-heading-md, grid 미정의)를 컨테이너로 잘못 사용해
안내 문구가 길어지면 입력/토글 컨트롤이 아래 줄로 밀려나던 기존 UI
결함도 함께 발견해 수정했다. 같은 파일의 field_privacy_policy_slug가
이미 쓰던 올바른 grid-3col-responsive 패턴으로 통일.
정책 버전 snapshot 모달의 본문 페이지 링크가 /{{slug}} 로 조합되어
페이지 모듈(sirsoft-page) URL 패턴 /page/{slug} 와 불일치해 404가
발생하던 문제를 수정. 쿠키 배너의 동일 링크와 조합 방식을 통일했다.
회귀 검증을 위해 GDPR 플러그인에 Playwright E2E 인프라를 최초 도입.
철회 이력(status=revoked)이 있는 항목에 한해 status_at_formatted·
status_label 을 채워 마이페이지에 철회일이 표시되도록 한다. 거부·
미설정 상태는 기존대로 미표시 유지 ( 확인).
동의/철회 날짜 줄을 초록/빨강으로 구분해 시각적으로 대등하게
강조한다 (배지·관리자 GDPR 동의 이력 화면과 동일 톤).
PR 준비 비판적 재검토 중 발견한 잔여 항목 2건 정리.
- 게시판·이커머스 알림톡 연동 UI 테스트/레이아웃의 e2e:allow 주석·describe
블록에 남아있던 작업 중 이슈번호 제거 (audit 정규식은 형식만 검사해
이슈번호 잔존은 검출하지 못함)
- alimtalk-dispatch-binding.yaml 시나리오 매니페스트에 NotificationBindingService
저장 시점 승인 재검증(assertSendable) effect 2건 추가 — 코드/테스트는
이전 커밋에 있었으나 매니페스트만 누락
PR 준비 최종 검토 중 문제코드 처리 대조표를 재검증하며 발견한 결함 2건.
- ResultCodeResolver 가 5002(요청 과다)를 재시도 대상으로 분류하지만 ko/en/ja
언어팩 어디에도 사유가 없어 코드값만 노출되던 결함 수정
- 알림톡 템플릿 연결 저장이 승인 상태(RDY/ACT) 재검증 없이 그대로 upsert되어,
화면 드롭다운(승인 템플릿만 노출)을 우회한 API 직접 호출 시 미승인 템플릿도
저장 가능했던 결함 수정 — bind 에 카카오 승인 목록 대조 추가, 조회 자체
실패 시에도 안전측으로 저장 거부
코어 알림 설정 화면에만 있던 비즈뿌리오 카카오 알림톡 템플릿 연결 UI(연결 버튼,
검수모드 배너, 안내박스)가 게시판·이커머스 알림 설정 화면에는 빠져 있었다.
Phase 6 재설계 시 "후속 작업"으로 남겨두고 실제 반영이 되지 않았던 부분이다.
- 게시판·이커머스 알림 정의 행에 코어와 동일한 notification_definition_row_footer
확장 슬롯을 추가하고, 게시판 레이아웃에는 코어/이커머스와 동일한 채널 콘텐츠
wrapper id를 신설해 구조를 맞췄다.
- 비즈뿌리오 플러그인에 게시판·이커머스 전용 overlay 확장 파일을 추가해 배너·
안내박스·연결모달·데이터소스를 각 레이아웃에 주입한다. 백엔드는 notification_type을
확장 구분 없는 문자열 키로 이미 3영역 공용 처리하고 있어 프론트 진입점만 보완했다.
- 회귀 테스트: 이커머스 화면에서 최초 구현 시 발견된 위치 버그(연결 버튼이 변수
뱃지 아래가 아니라 토글/편집 버튼 옆으로 붙던 문제)를 fail 재현 후 수정,
같은 회귀를 잡는 구조 검증 테스트를 게시판·이커머스 양쪽에 추가했다.
플러그인 README가 없어 webhook 등록, 검수/운영 계정, 알림톡 템플릿 역할 분리
등 운영자가 알아야 할 내용이 문서화되어 있지 않았다. 결제 플러그인(KG이니시스
등) README 관례를 따라 요구사항, 설치, 관리자 설정, webhook 등록, 발송 흐름,
결과 코드, 훅, API, 삭제 시 동작을 담은 README를 추가한다.
CHANGELOG는 아직 공개 저장소가 없는 미배포 상태이므로, 개발 중 쌓인 이력성
문구("예전에는 ~였지만 이제 ~")를 걷어내고 1.0.0이 처음 제공하는 기능 목록만
남기도록 정리한다. ja 번들 언어팩 CHANGELOG도 동일 기준으로 정리한다.
발송 API(/v3/message) 가 HTTP 오류로 실패하면 "메시지 발송 요청에 실패했습니다"
라는 고정 문구만 남고 비즈뿌리오가 준 실제 사유·코드를 버려, 발송 이력·로그로
원인을 알 수 없었다. 실패 응답 body 의 code·description 을 추출해 예외에 실어
발송 이력에 "발신 프로필 키가 유효하지 않음 (7103)"처럼 구체 사유가 남도록 한다.
body 가 없으면 기존 기본 문구로 폴백한다(결과코드 null).
발송 결과 코드 사유 문구를 비즈뿌리오 최신 공식 명세
(bizppurio.github.io/response-codes)에 맞춰 정비한다. 인증·계정 계열
코드(3001·3004·3007·3009 등) 설명이 실제 의미와 달라 관리자가 실패 원인을
오해할 수 있던 것을 정정하고, 누락 코드(3003·3010 IP 오류·4431 수신거부·
7103 발신프로필 키 무효)를 추가한다. 재시도 분류에 5002(요청 과다)를 포함한다.
ko/en 및 ja 언어팩 사유를 함께 갱신한다.
잔액부족 관리자 알림 본문의 {channel_label}·{result_code} 등이 실제 값으로
치환되지 않고 중괄호째 노출되던 결함을 수정한다. balance.low 훅 인자와 사이트
메타를 알림 data 로 채우는 extract_data 구독 리스너(BalanceLowNotificationDataListener)
를 추가해, 코어 알림 본문 치환이 성립하도록 한다.
후불 한도 초과(9071)를 잔액부족과 동일 분류에 포함해 관리자 알림이 발화되도록
하고, 채널군 라벨(문자/알림톡)·결과코드 사유를 ko/en 및 ja 언어팩에 추가한다.
플러그인 삭제 시 문자·알림톡 채널이 정리되고 재설치 시 복원된다는
사용자 관점 항목을 CHANGELOG 에 추가한다.
알림톡 연동 저장 방식이 "코어 저장 훅 편승"에서 "행 하단 [연결/변경]
버튼 → 우리 연결 모달 → 우리 API 직접 저장"으로 확정됐으나 일부 주석이
옛 설명으로 남아 있어, 실제 구현과 일치하도록 3곳을 정정한다(로직 불변).
라우트 파일에서 직접 부착하던 webhook IP 화이트리스트를 plugin.php
getMiddleware self-gate 선언으로 전환한다(코어 확장 미들웨어 규정).
테스트 게이트 활성 헬퍼를 이식해 webhook 보안 테스트를 복구하고,
단건 발송 Job 시나리오에 scale 축 면제를 명시한다(볼륨 무관 상수 메모리).
webhook API 문서에 self-gate 부착 방식을 함께 보강한다.
SMS 템플릿 없음·알림톡 카카오 템플릿 미연결 등으로 발송 자체를 시도하지
못한 경우, 채널 드라이버가 조용히 return하면 코어가 예외 미발생을
성공으로 착각해 발송 이력에 "성공"으로 잘못 기록했다. 드라이버가
NotificationSendSkippedException을 던지도록 바꿔, 코어의 기존
실패 처리 경로(channel_send_failed 훅)를 그대로 태워 "실패"로 정확히
기록되게 한다. 코어 파일은 수정하지 않는다.
실패 사유 메시지의 알림 유형도 내부 코드값(welcome) 대신 사람이 읽는
이름(회원가입 환영)으로 표시하도록 함께 개선했다.
코어 notification_logs.body는 알림톡의 경우 SMS 대체발송용 코어 템플릿
본문이라, 실제 카카오에 발송된 내용(승인 템플릿 전체)과 다르다. 코어
공용 파일은 다른 채널도 함께 쓰므로 직접 수정하지 않고, 결과 컬럼
오버레이 방식을 확장해 알림톡 채널일 때만 실제 발송 내용을 별도로
보여준다.
비즈뿌리오가 대체발송 미요청 건에도 webhook TELRES/KAORES 값을 채워 보내
빈 문자열 검사만으로는 요청 여부를 구분할 수 없었다. 발송 시점에 우리가
실제로 대체발송을 요청했는지(request_payload의 resend 키 존재)를 판단
기준으로 바꿔, 미요청 건은 webhook 값과 무관하게 결과를 표시하지 않는다.
발송 이력 화면의 "테스트 모드" 표기를 "검수 모드"로 통일하고, 검수 모드 발송 건은
상태 라벨 대신 "검수" 라벨로 표시한다. 설정 미완료 상태에서도 검수 모드 안내가
함께 표시되도록 배너 노출 조건을 수정한다.
발송 요청 payload가 어디에도 저장되지 않아 실패 원인을 사후 재구성할 수 없던 문제를
해결한다. bizppurio_dispatches.request_payload 컬럼을 신설해 발송 시점(성공/실패
무관)에 실제 비즈뿌리오 전송 payload를 저장하되, 다른 컬럼과 중복되는 개인식별
정보(수신번호·치환된 본문 텍스트)는 제외하고 저장한다.
카카오 알림톡 버튼 URL과 완전한 URL 변수(action_url 등, 항상 프로토콜 포함)가
결합될 때 프로토콜이 중복(https://https://...)되어 잘못된 링크로 발송되던 문제를
방지한다.
플러그인 제거 후 재설치 시 sms·alimtalk 채널 템플릿이 재생성되지 않던 문제를
해결한다. 리스너 등록 이력 캐시가 재활성화 후에도 남아있어 재등록이 조용히
스킵되던 것으로, 코어 수정 없이 플러그인 내부에서 리플렉션으로 우회한다.
비즈뿌리오는 검수/운영을 별도 계정으로 운영하도록 권장하나 본 플러그인은
계정을 1벌만 보관하므로, 관리자가 이를 인지하도록 검수 모드 카드에 안내를
상시 노출한다. 검수 모드 안내의 "(개발)" 표현도 제거했다.
또한 사전 준비 안내가 세로로 길어 보이는 문제를 개선해, 문자·카카오를
넓은 화면에서 2단 카드 + 채널 아이콘으로 정리했다(모바일 1단 유지).
자격증명 오류 등으로 카카오 템플릿 조회가 실패하면 드롭다운이 비면서
'승인된 템플릿이 없습니다'로 떠서 실제 0건과 구분되지 않던 문제를 수정한다.
데이터소스 fallback 에 load_failed 마커를 실어, 드롭다운이 비었을 때
조회 실패(설정 확인 안내)와 진짜 0건(승인 템플릿 없음)을 문구로 분기한다.
에러 토스트 재도입 없이 모달 내 인라인 문구로만 구분한다.
비활성 상태의 확장이 등록했던 발송 수단(문자·알림톡 등)을 코어 via가
저장된 채널 설정만 보고 계속 발송·"건너뜀" 로깅하던 문제를 수정한다.
사용 가능한 채널 목록에 없는 채널은 로그 없이 조용히 제외하며,
알림 설정·템플릿은 그대로 유지되어 확장을 다시 켜면 복구된다.
아울러 발송이 타임아웃·연결실패로 최종 실패할 때 pending 으로 방치되던
이력을 failed 로 마감한다(webhook 이 먼저 확정한 건은 덮어쓰지 않음).
관리자가 SMS·알림톡 채널을 꺼도 발송이 계속되던 문제 수정.
- 원인: 채널 토글 저장이 map-only 라 미등록 확장 채널(sms/alimtalk)의
on/off 가 저장되지 않았고, 백엔드는 미저장 채널을 활성으로 판정
- 프론트: 토글 저장을 upsert 로 전환(미저장 채널도 저장), 하단 채널 탭을
source 기준으로 필터(확장 채널은 미저장/OFF 시 숨김) — 코어·게시판·이커머스
- 백엔드: 플러그인이 core.notification.channel_enabled 훅을 구독해
확장 채널 미저장 시 OFF 로 게이트(코어 무수정, 코어 기본 채널은 하위호환 유지)
템플릿 등록·수정·삭제·검수·상태변경을 제거하고 목록·상태·내용 조회 +
알림 연결만 남긴다. 등록·관리는 비즈뿌리오 콘솔로 위임 — 콘솔이 이미
이미지메이커·AI생성·캐러셀을 잘 제공하고, 카카오 규격이 자주 바뀌어 등록
폼을 유지하면 규격을 영구히 쫓아가야 하는 유지보수 부채가 크기 때문이다.
이 플러그인의 고유 가치는 카카오 템플릿 ↔ G7 알림 연결(binding)이다.
주요 변경:
- 라우트/컨트롤러/서비스에서 변경(manage) 메서드 전부 제거, 조회만 유지
- dev_sample 임시 개발코드 + FormRequest 3종 + 이미지 업로드 경로 제거
- 레이아웃: 등록 폼·상태변경 모달 제거, 상세는 내용만+[닫기], 목록 관리열은 [내용]만
- 환경설정 사용 전 준비 안내 + 목록 상단 콘솔 위임 안내(배지 의미색) 추가
- 안내 배너 중복 해소: 목록 조회 실패 배너에 ready 게이트를 걸어 설정 안내와 배타 표시
동반 변경(직전 세션 잔여, lang 얽힘으로 같은 커밋):
- 연동 행 SMS 대체발송 배지(ON/OFF solid 색) 추가
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 항목에 설치 시 자동 시딩 문구 흡수
발송 결과(성공/실패·사유·잔액부족·SMS 대체발송)를 코어 "알림 발송 이력" 화면의 각 행에
표시한다. 코어 앱·코어 테이블 무수정 — 연결 표식은 bizppurio_dispatches.notification_log_id
에만 두고, 발송 사이클의 코어 after_log_sent/after_log_failed 훅으로 그 로그 id 를 연결한다.
- 결과 조회는 파라미터 없는 GET /dispatch-results/recent 로 최근 결과 맵을 받아 row.id 매칭
(목록 로드 순서에 무관 — 빈 배열 전송·타이밍으로 결과가 비던 문제 해소).
- 코어 이력 datagrid 에 결과 컬럼을 layout_extensions 로 주입하고, 행 토글에도 상세 결과를
얹는다. 메일·사이트내알림 탭에선 컬럼(헤더 포함)을 숨긴다. 다크모드 배지 색 보강.
- 브라우저 검수용 데모 시더(4상태·엣지 케이스 21건) + 전 계층 테스트(백엔드·Vitest 렌더)
+ 시나리오 매니페스트 + API 레퍼런스 동반.
- 카카오 kapi HTTP 실패 시 응답 body의 message/code를 예외에 실어
운영자에게 실제 사유(IP 차단·반려 등)를 노출 (기존 고정 문구로 뭉개지던 문제 해소)
- 설정 탭 전환을 replaceUrl→navigate(replace)로 교체
(URL만 바뀌고 화면이 전환되지 않던 문제 해소)
- 템플릿 목록 조회 실패 시 카카오 사유를 빨간 배너로 표시
- report_url 데이터소스 if 조건으로 templates 탭 불필요 재조회 억제
알림 설정 알림톡 탭에서 각 알림에 카카오 알림톡 템플릿을 연결하는 UI.
코어 편집 모달·저장 버튼은 건드리지 않는다(무오염).
- 각 알림 행 하단에 범용 확장 슬롯(notification_definition_row_footer) — 연결 상태 줄
+ [연결/변경] 버튼. 코어 편집 모달 내부 주입 불가(엔진 modals 미탐색) 회피.
- 우리 전용 연결 모달(modals 병합) — 승인 템플릿 드롭다운·SMS 대체 토글·변수 안내 +
[취소][저장]. 저장은 우리 API(코어 저장 무관). openModal 을 승인 조회보다 먼저 실행.
- 상태 배너(readiness 미충족/테스트 모드, 문제 있을 때만) + 알림톡 탭 안내 박스.
- SMS 대체발송 안내(실패 시 이 알림 본문이 SMS로 발송) + 다크 모드 solid 색.
- 카카오 API 422 는 errorHandling.suppress 로 조용히 처리(전 탭 에러 토스트 제거).
Vitest 17 통과, audit 위반 0, Chrome MCP 다크·저장 검수 통과.
Phase 6 재설계 — 코어 알림 설정 화면을 그대로 쓰고 알림톡 편집 시 전용 칸만 얹는다.
- 시딩 필터 훅(seed.*.notifications.translations) 편승으로 회원 알림에 sms·alimtalk
template 증강 (코어·모듈 무수정, cleanupStaleTemplates 에도 유지)
- 코어 편집 모달에 overlay 로 전용 칸 append(연결 템플릿·SMS 대체) — 변경 즉시 저장,
코어 저장 버튼과 무관 (코어 템플릿 무오염)
- 알림톡·SMS 탭 상태 배너(설정 미완료/테스트 모드)
- 1차 구현(우리 목록 통째 교체·게이트·우리 편집 모달) 폐기
전 계층 테스트 통과 (백엔드 170 / 프론트 63), audit 위반 0.
설정 페이지 알림톡 템플릿 탭에서 카카오 알림톡 템플릿을 등록·수정·삭제·검수·
상태변경한다. 진입은 코어 소유 설정 페이지 하나로 통일하고 getAdminMenus 는
폐기했다. 템플릿은 kapi 에 실시간 위임하며 DB 에 저장하지 않는다.
등록 폼은 계획서 §6-4 전체를 구현한다: 템플릿 코드(자동 생성/직접 입력),
카테고리 2단 드롭다운, 템플릿 유형(기본형/이미지형/강조표기형), 이미지형
파일 업로드, 본문 변수 클릭 삽입 + 알림별 변수 참고표, 선택 항목 6개
체크펼침(부가정보·미리보기·버튼·바로연결·대표링크·보안), 등록/등록 후
검수요청 2버튼.
문자·알림톡 발송 결과를 DB에 기록하고, 비즈뿌리오 webhook(URL PUSH)으로
도달 여부를 갱신한다. 결과코드를 사유+분류로 해석하고, 잔액 부족 시
관리자에게 쿨다운(기본 1시간) 내 1회만 알린다.
발송 결과를 확인하는 화면은 플러그인 독립 페이지 대신 코어 알림 이력에
얹는 방식(후속)으로 이관하기로 하여, 이번에 만든 독립 이력 화면과
화면 전용 백엔드는 제거했다. webhook 결과 저장·수신·해석 뼈대는 유지한다.
- 설정 화면을 공용 클래스·2단 그리드·상단 안내 패널·필드 인라인 에러로 통일
- 연동 환경(dev/live)을 검수 모드 Toggle(is_test_mode)로 전환, 독립 카드로
분리하고 운영 경고 박스를 API 연동 카드 상단에 배치
- 검수 모드를 끄면(운영) 발송 자격증명(아이디·비밀번호·발신번호)을
required 로 강제하는 조건부 검증 필터 훅 추가
- 리포트 수신 주소를 설정 화면에서 확인·복사 (플러그인 라우트가
config('app.url') 기준 절대 URL 반환, 코어 무수정)
- 명칭 "메시징→메시지 발송", 설명 "자동발송→발송", "(다우기술)" 제거
- 설정 저장 테스트가 실제 런타임 설정 파일을 오염시키던 결함 격리
Phase 3 — 코어 알림 시스템에 sms·alimtalk 채널을 코어 무수정으로 등록하고,
가입·주문 등 이벤트 발생 시 문자를 자동발송한다. 실제 발송·재시도는 Phase 2
발송 Job 에 위임한다.
- filter_available_channels 훅으로 sms·alimtalk 채널 노출(비회원 발송 허용).
channel_readiness 로 발신 정보 미설정 시 필요한 항목을 안내.
- 코어/게시판/이커머스 3영역의 채널 후보 훅을 구독해 자동발송 커버.
- sms 채널 드라이버를 ChannelManager 에 등록(코어 무수정) — 전화번호 해석
(회원=프로필, 비회원=주문 연락처) → 본문 길이로 SMS/LMS 판별 → 발송 위임.
- 비회원 주문 전화번호는 이커머스 알림 데이터 훅을 구독해 채운다. 이커머스
모듈은 무수정(자체 관행대로 배송지 연락처를 직접 읽음).
알림톡은 채널 등록·readiness 까지만. 실제 발송·템플릿 연동·탭 UI 는 Phase 5·6,
발송 이력 DB 는 Phase 4 로 이관.
발송 시스템(api.bizppurio.com)과 카카오 관리 시스템(kapi.ppurio.com)의
API 클라이언트를 인증 방식(토큰 vs bizId+apiKey)에 따라 분리 구현했다.
토큰 캐시(23h)·재발급, SMS/LMS EUC-KR byte 자동 판별, ShouldQueue 발송
Job(429·일시오류 재시도, 영구실패 즉시)을 포함한다. 실제 발송 없이
Http::fake 단위테스트 30건으로 검증했다.
이슈 작업 중 일본어 언어팩에 신규 키 12건을 추가했으나 language-pack.json
version(1.0.0)을 patch bump 하지 않은 채 커밋됨 (규정: 키 추가/수정 → patch up).
1.0.1로 정정 + CHANGELOG 섹션 분리 + language-pack:update --force 로 설치본 반영.
- cookie_categories_rows / blocked_domains_taginputs iteration 컨테이너의 정적 id를
index_var(categoryIdx)로 동적화 — 카테고리가 여러 개일 때 동일 HTML id가 중복 렌더되던
W3C id 유일성 위반 수정 (audit layout-iteration-static-id)
- 카테고리 「필수」 배지 dark:bg-red-800 / text-danger-soft 클래스 사이 공백 누락으로
다크 모드 배경·글자색이 미적용되던 오타 수정
이슈 작업 중 audit-branch 전수 검사에서 발견한 기존 결함 (이번 이슈 기능과 무관, )
- 토글 스위치 → 상태 배지 + 동의/철회 버튼으로 재설계
(user 템플릿 미해석 클래스로 인한 스타일 회귀 + "켜짐/꺼짐" 표현 개선)
- 동의 시에도 확인 모달 경유, 라벨에 "쿠키" 접미사, "모두 동의" 바
- 동의한 항목만 동의일 표시 (상태는 라벨 옆 배지가 표현)
- 카테고리 설명을 코드 기본값에서 조회 — 관리자 설정 화면에 설명 편집 UI가
없어 라벨만 저장 시 설명이 유실되던 문제 해결
- 철회/동의 모달 버튼을 목록 버튼과 톤 맞춰 정리 (취소=테두리형)
- cookie_banner 운영주체 라인 admin 전용 클래스 → 공통 클래스 치환
- 라이브 자격증명 입력칸 브라우저 자동완성 자동 채움 차단
(live_mid: one-time-code / live_api_key: new-password —
크롬이 autoComplete=off 를 무시함을 실측 후 강화)
- 라이브 가맹점 MID 프리픽스를 이니시스 정책 변경에 맞춰 SRA→SRB 전환.
런타임 프리픽스를 InicisIdentityProvider::LIVE_MID_PREFIX 상수로 추출,
표시 문자열(라벨·Span·힌트 ko/en/ja)은 값 교체.
- 설정 저장 테스트가 실제 스토리지 설정 파일을 오염시키던 결함 격리
(PluginTestCase 에서 plugins 디스크를 테스트 전용 경로로 격리)
- 설정 화면 배너 아이콘 크기 시맨틱 정정 (w-N h-N → text-*, 정렬 회귀 해결)
- 프리픽스 상수 ↔ 표시 문자열 정합 audit 룰 추가 (이중관리 불일치 차단)
코드/테스트 주석에 남아 있던 내부 이슈번호(-14, -15 등)를
규정에 따라 제거하고, 첨부 라우트 주석의 오해 소지 표현을 정정한다.
1.0.1 릴리스 날짜를 2026-07-06 으로 맞춘다.
- Listener/커맨드 주석, Feature/Unit/레이아웃/E2E 테스트 주석
- 시나리오 매니페스트 설명 (audit:allow 지시어는 보존)
- 첨부 라우트: admin 그룹의 오해성 "단일화" 주석 제거,
공개 pages 그룹 각 라우트에 게시판과 동일한 방식·사유를 간결히 명시
(미리보기=공개 이미지, 다운로드=발행 상태 조건부 접근 제어)
- CHANGELOG [1.0.1] 날짜를 2026-07-06 으로 정정
(page 모듈 / basic·admin_basic 템플릿 / 대응 ja 언어팩 3종)
- 로직·동작 변경 없음
목록·상세·등록/수정 화면의 버튼·선택 상자·카드 여백을 시맨틱 클래스로 통일하고,
검수 중 발견한 동작 결함을 함께 수정한다.
- 모바일 검색이 저장소 불일치(_global 저장 ↔ _local 읽기)로 미작동하던 문제 수정
- 폼 취소 이동을 수정=상세 / 등록=목록으로 명시 (기존 navigateBack 안티패턴 제거)
- 검증 에러 박스 제목 색/굵기·하단 여백, 저장 버튼 시맨틱화(spinner 포함)
- 상세: 첨부 기본 열림 + 항목별 구분선, 다크모드 카드 대비 개선,
메타 정보 2열 배치, 카드 헤더 통일(이중 여백·구분선 제거), 실패 토스트 실제 메시지 노출
- 언어 탭이 모바일에서 줄바꿈되도록 반응형 처리
레이아웃 렌더 회귀 테스트 113건 통과 + 취소 이동 E2E spec 추가.
썸네일(<img>)·다운로드(<a>)는 브라우저 직접 GET 이라 토큰을 실을 수 없는데
커밋 d48c684 가 첨부 URL 을 auth:sanctum admin 라우트로 바꿔 401 회귀가 났다.
게시판·이커머스 표준으로 정렬한다.
- 썸네일(preview): 공개 hash 서빙으로 단일화 (발행/미발행 무관 200)
- 다운로드: 공개 hash 라우트 + 권한 게이트(발행=누구나 / 미발행=pages.read 관리자만)
- 프론트 다운로드를 downloadAttachment 핸들러(토큰 fetch→blob)로 전환
- 다운로드 아이콘 arrow-down-tray(FA 미존재) → download
- 사용자 페이지에도 이미지 첨부 썸네일 추가 (관리자 상세와 일관)
- admin 첨부 preview/download 데드 라우트·메서드 제거
- iteration 안 정적 id 를 att_idx 동적 id 로 교정 (위생 정리)
- 페이지 폼 FileUploader 에 onUploadError→toast 연결 (용량/확장자 초과 안내)
- 사용자 템플릿(sirsoft-basic) 개수 초과 시 onUploadError 발화 추가 (silent 무시 방지)
- 개수 초과 문구를 이미지 전용에서 일반 파일 범용 공통 메시지로 통일 (ko/en/ja)
버전 복원 시 발화되는 after_restore 훅을 SeoPageCacheListener가
구독하지 않아, 복원 후에도 검색봇에 복원 전 버전이 계속 노출되던
문제를 수정. 복원은 콘텐츠 변경의 일종이므로 수정/삭제와 동일한
onPageChange 무효화 정책을 재사용.
미발행 페이지는 관리자여도 사용자 화면(/page/{slug})에 접근할 수 없어
발행 전 미리보기가 불가능했다. 페이지 조회 권한(sirsoft-page.pages.read)
보유 관리자는 미발행 페이지를 사용자 화면에서 미리볼 수 있게 하고, 미리보기
화면에 안내 배너를 노출한다. 비로그인·일반 회원은 기존대로 404를 유지한다.
- getPublishedPageBySlug 에 미리보기 허용 플래그 추가 (권한 판정은 컨트롤러)
- 미발행 미리보기 시 첨부 URL 을 admin 컨텍스트로 전환해 첨부까지 미리보기
- page/show.json 에 미발행 미리보기 안내 배너 + ko/en/ja 다국어
- E2E 시드 커맨드 구현 + 커맨드 등록 + 사용자 화면 미리보기 spec
- 페이지 상세 버전 이력의 "변경내역"이 title·content 등 영문 필드명으로
노출되던 문제를 field_labels 다국어 매핑으로 정정 (ko/en/ja)
- sirsoft-page 모듈에 Playwright E2E 인프라를 이커머스와 동일 패턴으로 신설
(config·fixture·seed stub + spec 3건, data-testid 보강 전까지 skip placeholder)
- 출시된 1.0.0 이후 변경이므로 module 1.0.1 bump (3곳+lock 동기화),
ja 언어팩 1.0.1 bump
- 검색 조건 '전체'가 슬러그를 검색하도록 통합하고, 검색 대상을 제목·슬러그로
한정(본문 제외 — UI '제목 또는 슬러그로 검색'과 정합). '제목' 선택 시 제목만 검색.
- 페이지당 표시 개수 기본값을 백엔드도 20으로 통일(화면 표시와 실제 조회 일치).
- 긴 검색어(공백 없는 한글 다수)가 FULLTEXT 토큰 한도를 넘겨 500을 유발하던 문제를
검색어 100자 제한으로 422 처리. 검증 메시지 필드명을 '검색어'로 노출.
페이지 목록 일괄 발행/미발행이 after_publish 훅을 발화하지 않아
활동로그에 발행/미발행이 기록되지 않던 문제를 수정한다.
- bulkChangePublishStatus 를 DB::transaction 내부에서 페이지별로
before_publish -> update -> after_publish 발화하도록 재작성 (per-item 로그)
- 존재하지 않는 id 가 섞이면 전체 롤백 (all-or-nothing)
- 단일 mass UPDATE 전용 bulkUpdatePublished 제거 (dead code, 의존 확장 영향 없음)
- 일괄 발행 성공 응답 메시지의 :count 미치환 정정
(success 의 4번째 인자 messageParams 로 치환 파라미터 전달)
- 회귀 테스트 추가 (훅 발화 횟수/published 인자/롤백/메시지 치환)
- 관리자 첨부 다운로드/미리보기를 admin 라우트 URL로 분기 (미발행 페이지 첨부를 관리자가 열 수 있도록)
- 다중 업로드 시 올린 순서대로 저장 (이커머스 패턴: temp_key 연결 + form.attachments 동기화, 코어/공용 컴포넌트 무수정)
- 수정→등록 전환 시 이전 첨부·제목·슬러그·검증안내 잔존 차단
(initialFiles를 _local.form.attachments에 바인딩 + init_actions에서 form null→기본값 초기화)
- 등록 폼 슬러그 미리보기 {{slug}} 미치환 수정 (빈 슬러그를 못 거르던 ?? → || fallback)
- 페이지 변경 시 상세 SEO 캐시 무효화 URL 패턴을 단수형(/page/{slug})으로 정정
페이지 삭제 후 동일 슬러그로 재생성 시 "이미 사용 중" 오류가 나던 문제 수정.
슬러그 중복 체크(SoftDeletes 스코프로 삭제 행 제외)와 생성 검증(Rule::unique로
삭제 행 포함)이 soft delete를 다르게 취급해 발생. Page/PageAttachment의
SoftDeletes를 제거하고 deleted_at 컬럼을 마이그레이션으로 정리해 두 경로를 정합화.