발송 이력 화면의 "테스트 모드" 표기를 "검수 모드"로 통일하고, 검수 모드 발송 건은
상태 라벨 대신 "검수" 라벨로 표시한다. 설정 미완료 상태에서도 검수 모드 안내가
함께 표시되도록 배너 노출 조건을 수정한다.
발송 요청 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건으로 검증했다.
- 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 전용 클래스 → 공통 클래스 치환
세 갈래의 결함을 한 브랜치에서 정리한다.
## 목록 컨텍스트 왕복 시 URL 상태 소실 ( @jiwonpapa 님께서 제보해주셨습니다.)
목록에서 상세·형제 상세(이전/다음)·작성/수정 폼에 다녀오면 보고 있던
page/search/category/filters 가 사라지던 문제를 전 도메인에서 수정했다.
- 엔진(engine-v1.54.2): `mergeQuery: true` 만 적고 `query` 를 생략하면 병합이
통째로 건너뛰어지던 함정을 교정 — `ActionDispatcher.handleNavigate`/`handleReplaceUrl`.
- 게시판·이커머스·페이지·회원·마이페이지·gdpr 등 9개 확장 레이아웃의 왕복 leg 전수
적용(mergeQuery: true). 의도적 리셋(검색/필터 초기화·탭 전환·프리셋)은 면제 주석으로 구분.
- 무한스크롤 목록(브랜드·상품 공통정보·고시정보)의 새로고침이 URL 검색·정렬을 떨구던
결함 수정.
- 재발 차단: audit 룰 `layout-list-context-navigate-merge-query`(목록 클러스터 자동 도출,
page/필터 URL 신호 4종) + `layout-navigate-path-absolute`(navigate path 동작 키워드 금지).
## cellChildren 등 반복 렌더에서 단일 바인딩 파이프 미적용 ( @glitter-gim 님께서 제보해주셨습니다.)
목록 표의 각 칸에 넣은 날짜·숫자 서식(`{{row.x | datetime(...)}}`)이 빈 값이 되거나
서식 없는 원본으로 나오던 문제를, 표현식 판정 로직이 엔진 전역에 복제되며 갈라진
구조적 결함으로 진단하고 판정 경로를 단일화했다(engine-v1.54.3).
- `RenderHelpers`(renderItemChildren·evaluateIfCondition)·`ConditionEvaluator`·
`DataBindingEngine.resolveObject`·`DynamicRenderer` props 5곳에 단일 바인딩 파이프 분기 추가.
- 계획: `g7-scalable-lobster.md`(렌더 경로 비대칭 결함 일괄 수정).
## 공개 문서 내부 도구 귀속 제거
release 에 포함되는 공개 문서(`docs/**`)에서 내부 audit 룰 ID 귀속 서술을
도구 비귀속 표현("정적 검사")으로 정리. 재발 차단 룰 `public-no-internal-audit-reference` 신설.
전 계층 테스트(PHPUnit·Vitest·Playwright)·회귀 테스트 동반, 버전/CHANGELOG/활성 디렉토리 동기 완료.
여러 화면에서 조건부(FormRequest) 검증이 우회되거나 과도하게 제한되던 결함을 한 계열로 묶어 수정한다.
- 검증 규칙 확장 필터 이름 10개를 나머지 92개와 동일 규칙으로 통일
- 설명 길이를 바이트가 아닌 글자 수로 계산(한글 오검출 해소)
- 비활성 언어팩 번역 보존한 채 수정 허용
- 알림 템플릿 제목 nullable 존중, 미지원 발송 수단 저장 차단
- 일정/실행 이력 목록 조회 검증 정합
- 게시판 첨부 미사용 시 빈 확장자 통과, new_display_hours/최소 길이 0 허용, 일괄 적용 override_values 범위 검증(SSoT)
- 이커머스 클레임 사유 조회 검증, 용어 정정
- 원문 i18n 키 노출 다수 해소, 저장/삭제 실패 시 사유 화면 노출
- 아이콘 크기/다크모드 대비 회귀 수정
번들 확장(모듈3·플러그인6·템플릿2·언어팩5) 버전 new-bump 및 CHANGELOG 반영, ja 언어팩 동기.
결제 플러그인 3종(pay_kginicis/nhnkcp/nicepayments)과 sirsoft-basic 템플릿의
배포 JS 에 //# sourceMappingURL 주석과 .map 파일이 남아 있어, 공개 배포판에
원본 TS/TSX 전문(sourcesContent)이 노출될 수 있었다(NoSourcemapArtifactsTest 2건 실패).
각 확장을 --production(G7_BUILD_SOURCEMAP=0) 으로 재빌드해 소스맵 주석·.map 을
제거하고 {plugin|template}:update 로 활성 디렉토리에 반영. 기능 코드는 바이트 동일,
소스맵 주석만 제거된다. nhnkcp/nicepayments 의 components.json 파생 버전도 매니페스트
SSoT(1.0.0)로 재동기화. 매니페스트 버전은 무변경(동작 변화 없는 배포본 위생 수정).
NoSourcemapArtifactsTest 4/4 green.
코어 7.0.5 릴리즈와 함께 버전이 오른 확장·언어팩의 CHANGELOG 출시 날짜를 오늘(2026-07-16)로 맞춤.
- 코어 7.0.5, ecommerce 1.0.4, gdpr 1.0.1, pay_kginicis 1.0.1, basic 1.0.3 출시일 통일
- core-ja 1.0.4, ecommerce-ja 1.0.4 출시일 통일
- pay_kginicis-ja: [Unreleased] 항목을 1.0.1 로 릴리즈 (manifest version 1.0.0 → 1.0.1 bump)
- pay_nhnkcp-ja / pay_nicepayments-ja 1.0.1 누락 날짜 명시
두 결제 플러그인을 1.0.0-beta.4 에서 정식 1.0.0 으로 올린다.
공개 release latest(beta.3) 대비 프리릴리즈 → 정식 승격으로
버전 bump 규정에 정합(new-bump). manifest/package/composer/lock
4개 파일 버전 동기화 + CHANGELOG [Unreleased] 를 1.0.0 으로 확정
(nicepayments 는 중복 Fixed 챕터 병합). g7_version(>=7.0.5) 은
코드가 7.0.5 도입 표면(미들웨어 self-gate·애플페이 iOS 컨텍스트)에
의존하므로 그대로 유지.
확장이 SP Kernel 미들웨어 그룹을 직접 조작하거나 라우트 파일에 미들웨어
FQCN 을 직접 부착하던 임시 방식을, 확장이 부착 대상(targets)을 명시 선언하고
코어가 요청 시점에 라우트명·URI 로 매칭해 실행하는 self-gate 로 정규화.
번들 7건(ecommerce/gdpr/pay 3종) 이전, audit 룰 3건·문서·버전 동기화 동반.
부수적으로 generate-skills.cjs 가 재생성 시 신의성실(부수의무) 섹션을 소실
시키던 회귀를 수정 — 스킬별 불릿을 스크립트 SSoT 로 편입해 재생성에도 보존.
3사 PG 플러그인의 체크아웃 DOM 인젝터가 렌더 후 브랜드 마크를 주입하고
injector끼리 같은 버튼을 두고 경합하던 구조를 제거한다. 시각정보(색 배지/
SVG 로고)를 결제수단 카탈로그(_cached_brand_mark)로 편입해 코어 체크아웃
레이아웃의 신규 BrandMark 컴포넌트가 데이터 기반으로 직접 렌더한다.
reconcileKginicisPatchedDuplicates(중복 방어)도 함께 제거했다.
애플페이 iOS 게이팅도 injector 밖으로 이관: 이커머스 모듈 DetectDevice
미들웨어가 UA로 기기를 판정해 코어 core.frontend.filter_app_config 훅으로
appConfig.isIos를 주입하고(1차), 템플릿 부트스트랩이 iPadOS 데스크탑 UA를
클라 신호로 보정한다(2차). 코어는 훅만 제공하고 감지 로직은 모듈이 소유한다.
미들웨어는 Router::pushMiddlewareToGroup 이 아닌 HTTP Kernel::appendMiddlewareToGroup
으로 web 그룹에 등록한다(전자는 Router 레지스트리만 갱신해 SSR 셸 요청 파이프라인에
미반영 → isIos 항상 false). sirsoft-gdpr 선례와 동일.
코어 최소 요구 버전 7.0.5 상향(appConfig 필터 훅 도입).
PG 플러그인이 등록하는 간편결제(네이버페이 등)를 코어가 정식 결제수단으로
인식하도록 결제수단 카탈로그를 SSoT 로 전환했다. 확장 결제수단이
pg_provider=null 로 등록돼 서버가 "PG 결제가 아닌 주문"으로 오인, 결제 실패
주문에 관리자 신규주문 알림이 발송되고 TempOrder 가 즉시 삭제돼 재결제가
막히던 두 결함을 하나의 원인(능력 해석을 enum 이 답하지 못함)으로 근본 해결.
- PaymentMethodResolver 신규: 능력(PG 필요/라벨/환불수단/PG 고정) 해석을
카탈로그 SSoT 로 통일, enum case 없는 확장 ID 도 동일 판정
- 프론트 결제수단 위장(card) 제거, provider-agnostic 결제 진입(pg_payment_handler)
- 관리자 주문설정 결제수단 목록 PG 고정 3분기 UI (pg_locked/needs_pg)
- 저장된 pg_provider=null 자가치유(read-time merge) + 백필 업그레이드 스텝
- 사용자 주문완료 화면 즉시 결제완료 헤더를 입금대기 여집합으로 판정(basic 1.0.3)
- 전 계층 회귀 테스트: 훅 발화 스파이(관리자 알림 미발화/PG 환불 훅 진입),
주문 응답 계약(requires_pg_payment/pg_payment_handler)+TempOrder 보존,
관리자 3분기 렌더, 확장 E2E 인프라
미출시 예약 작업 기능에서 스케줄 권한만 위임받은 계정이 Shell/Artisan
명령으로 임의 코드를 실행할 수 있던 문제를 선제적으로 차단(KVE-2026-1567).
Shell 은 기본 차단 + 실행 파일 화이트리스트 + 셸 미경유 인자배열 실행,
Artisan 은 차단목록. 저장 시점(FormRequest)과 실행 시점(Service) 이중 검증.
아울러 공개 release 보다 앞선 미출시 버전들의 CHANGELOG 출시 날짜를
2026-07-14 로 통일.
## 소스맵 노출 차단 (공개 이슈 )
배포본에 .map 이 포함돼 원본 TS/TSX 전문(sourcesContent, 한글 주석 포함)이
그대로 노출됐다. 생성·서빙·저장소 유입 3계층을 모두 막는다.
- 빌드 config 15곳(코어 3 + _bundled 12): sourcemap 하드코딩 제거.
G7_BUILD_SOURCEMAP 판정식으로 교체 — 미설정(로컬 npm run build)이면 생성해
개발 디버깅 경험을 보존하고, 0 이면 미생성.
- Build{Core,Module,Plugin,Template}Command: 죽어 있던 --production 플래그 복구.
$productionMode 를 콘솔 문자열에만 쓰고 npm 프로세스에 env 를 넘기지 않아
산출물이 개발 빌드와 동일했다. runNpmCommand 에 $env 를 추가해 주입
(--watch 에는 미주입). Symfony Process 는 부모 환경에 병합하므로 PATH 유실 없음.
- Allowed{Module,Plugin}FileType / {Module,Plugin}Service::getMimeType:
허용 확장자 map 제거 — 익명 200 서빙 차단(템플릿은 원래 미허용, 3종 정책 일치).
- ExtensionBundleService: CSS 번들의 /*# sourceMappingURL=... */ strip 추가.
CSS 는 블록 주석이라 JS 의 //# 패턴으로는 검출되지 않던 구멍.
- 추적 .map 13개 삭제 + .gitignore 전역 *.map 규칙(경로 한정 시 새 확장에서 누락).
실측: 산출 JS 의 sourceMappingURL 13 → 0, 추적 .map 13 → 0,
확장 디렉토리 npm run build 는 여전히 map 생성(개발 경험 회귀 없음).
## 관리자 환경설정 탭 지연 로딩
코어/이커머스/게시판 환경설정 화면이 진입 즉시 전 탭의 데이터소스를 한꺼번에
호출했다. 각 데이터소스에 활성 탭 조건(if)을 걸어 해당 탭에서만 fetch 하도록
변경하고, 결제 플러그인 3종의 테스트모드 상태 조회도 주문설정 탭으로 한정.
## 동반 결함 수정 (무관 결함 — 재발 방지 목적으로 같은 세션 처리)
- 나이스페이먼츠: 체크아웃 캐시 프리페치가 라우트를 가리지 않아 플러그인 번들이
로드되는 모든 페이지(홈/게시판/로그인)에서 주문서를 조회 → 비회원 매번 422.
형제 플러그인(kginicis)의 기존 가드 패턴을 적용해 체크아웃 경로로 한정.
- admin smoke 8건: 대부분 구현이 아니라 테스트 결함이었다 — URL 오타(단수 board),
존재하지 않는 권한키, 앱 로케일이 en 인데 한국어 라벨 로케이터, DataGrid 버튼을
먼저 잡던 휴리스틱 로케이터. 레이아웃에는 sticky className / 안정 id 를 부여.
- PHPDoc ↔ Pint 충돌 3건: 설명 없는 @param 은 no_superfluous_phpdoc_tags 가
삭제해 audit phpdoc-public-method 와 무한 충돌. 한국어 설명을 붙여 양쪽 충족
(리스너 3종의 설명 누락 메서드도 전수 보강).
- Log::spy 500 3건: spy 가 Log::channel('activity') 를 null 로 만들고
logActivity 가 null->info 로 \Error → 같은 줄 catch(\Exception) 은 못 잡아
통과. 운영에선 채널이 항상 로거이므로 제품 무결 → 테스트에 activity 채널
보존 헬퍼 추가.
- NhnKcpApiServiceTest 5건: 스텁이 Unix 바이너리만 만들어 Windows 분기
(pp_cli_exe.exe)에서만 실패. #!/bin/sh 는 Windows 실행 불가 → 파일 내 기존
컨벤션대로 skip 가드.
## 테스트
- 소스맵 범위 130 passed (신규: BuildCommandSourcemapEnv, NoSourcemapArtifacts,
ExtensionBundleService CSS strip, Allowed*FileType 반전, 자산 서빙 거부)
- 결제 3플러그인 505 passed / 0 failed (skipped 9 = Windows 전용 CLI, 사유 명시)
- 나이스페이먼츠 프론트 38 passed (가드 제거 시 red 실증 후 복원)
- E2E: production-sourcemap-exposure.spec.ts 6건 + 시나리오 매니페스트
버전: sirsoft-admin_basic 1.0.2 → 1.0.3, sirsoft-board 1.0.1 → 1.0.2
(각 manifest/package/lock/composer 동기화). 코어 7.0.4 는 미출시 누적.
서버가 외부 입력으로 목적지가 제어되는 outbound HTTP 요청을 보내는 지점을
전수 조사해, 내부망(사설 IP·루프백·링크로컬·메타데이터)과 host 위조를 차단한다.
KVE-2026-1546(이니시스 인증 URL 접두사 매칭 우회)과 동일 클래스의
지점(언어팩 URL 설치, 스케줄 URL 호출, 배송비 계산 API, GitHub URL 판정)을
코어 공용 유틸 App\Support\OutboundUrlValidator 로 수렴시켰다.
- 접두사 매칭을 host 완전일치로 교체 — userinfo(@) 위장과 접미사 확장 도메인
우회 벡터 차단.
- 사내 서버 호출이 정당한 관리자 지점(스케줄·외부 API)은 신규 설정
security.allow_internal_outbound_urls(기본 off)로 옵트인.
- 언어팩 URL 설치는 원격 코드 다운로드라 옵트인과 무관하게 내부 주소 항상 차단.
- 웹소켓 연결 테스트는 localhost·사설 IP 가 정상 구성이므로 구조적 위조만 차단.
각 지점에 red 재현 → 수정 → green 회귀 테스트 + 실브라우저 E2E 로 검증.
수기 API 문서가 자동 재생성으로 소실되는 사고를 막는 PreToolUse 훅을 함께 추가한다.
- 라이브 자격증명 입력칸 브라우저 자동완성 자동 채움 차단
(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 룰 추가 (이중관리 불일치 차단)
확장 API 문서가 인덱스·목차 어디에도 노출되지 않아 처음 온 개발자/AI 가
발견할 수 없던 간극을 해소했다. 코어에 확장명을 하드코딩하지 않고(동적 로딩 원칙),
파일 시스템 패턴 스캔 + 확장 소유 목차 규약으로 발견성을 확보한다.
- ApiDocScaffolder::readmeIndex — 각 대상의 docs/api/README.md 목차(도메인 파일·
엔드포인트 수)를 @generated 블록으로 생성(멱등, 사람 개요 보존). 커맨드가 대상별
README 를 방출(readmeFile 경로 헬퍼). 코어 + 9 확장 = 10개 목차 생성.
- generate-docs-index.cjs scanExtensionApiReadmes — {modules,plugins}/_bundled/*/
docs/api/README.md 를 패턴 스캔(확장명 하드코딩 0)해 ·AGENTS.md 에
"확장 API 레퍼런스" 표로 자동 편입. 확장 추가/삭제 시 재생성만으로 반영.
- api-documentation.md 에 README 목차 규약 + 발견 경로 명문화. coverage.json 에
api-doc-readme-index(manual-only) 등록. 루트 README API 레퍼런스 링크 갱신.
테스트: readmeIndex 목차 생성·멱등 2건 + 스캐너 편입·하드코딩부재 2건(node --test).