Files
Gnuboard7/plugins/_bundled/sirsoft-tosspayments/AGENTS.md
T
HeuJung 3a0aba85bc feat(core,extensions): 확장 문서 호칭 통일과 레이아웃 편집기 문서 축 신설
확장 문서의 제품 호칭을 「그누보드7」로 통일했다. 가 지적한 두 문구는
개별 오타가 아니라 생성기가 찍는 정형 문구여서, 산출물이 아니라 방출 지점
세 곳을 먼저 고쳤다 — 그러지 않으면 21번째 확장부터 다시 샌다. 정리 범위는
확장 문서와 그 생성기까지이며, 코어 docs 와 언어팩 표시명은 의도적으로 남긴다.

레이아웃 편집기 대응 문서가 없던 문제는 확장마다 docs/editor-spec.md 를
두어 닫았다. 실측은 EditorSpecCollector 가 유지하며, 합본에 런타임과 같은
EditorSpecAssembler 를 써서 문서가 말하는 스펙과 편집기가 읽는 스펙이
갈라질 경로를 두지 않았다. 스펙을 두지 않은 확장에도 문서를 둔다 — 미보유가
정상일 수 있고, 그 정상 여부를 적을 자리가 없으면 다음 사람이 부재를 누락으로
오해하거나 필요한 시점을 놓친다.

초안이 낸 수치 다섯 건이 틀렸고 전부 오류 없이 "사실" 로 실릴 값이었다.
블록 최상위 키를 세어 팔레트가 79 대신 3 이 되던 것, `_` 접두 일괄 배제가
실제 항목을 삼키던 것 등을 정정했다.

게이트를 인위적으로 깨뜨려 점검한 결과 사각 하나가 드러났다 — 채워 넣으라는
표시만 지우고 서술을 쓰지 않으면 검사를 통과해, 빈 문서가 완비로 집계됐다.
미채움을 두 축으로 만들어 닫았고 되돌림으로 검산했다. 편집기 스펙 편집 시
규정이 주입되지 않던 것과 스캐폴딩 안내가 새 문서를 빠뜨리던 것도 함께 고쳤다.
2026-09-01 12:02:55 +09:00

14 KiB

토스페이먼츠 — 에이전트 가이드

이 문서는 이 플러그인을 수정하는 에이전트·확장개발자를 위한 것입니다. 도입 검토·운영 관점은 README.md 를 보세요.

TL;DR (5초 요약)

1. 유형: 플러그인 (sirsoft-tosspayments) — 토스페이먼츠 PG 연동(통합결제창 SDK/가상계좌 웹훅 secret 대조/에스크로 3-상태). 소유 테이블 없음 — 상태는 sirsoft-ecommerce 소유
2. 확장 방식: `RegisterPgProviderListener`/`RegisterTossPaymentMethodsListener`/`RegisterCashReceiptProviderListener` 로 이커머스 레지스트리에 등록 — 이커머스 코드는 이 플러그인을 모른다
3. 건드리면 안 되는 것: 결제 승인 확인 시 서버가 재계산한 금액과 PG 콜백 금액 대조(amount mismatch 검사) 생략, 가상계좌 웹훅의 secret 대조(`webhook_secret_verify`) 우회 — 토스는 notify IP 목록·서명을 제공하지 않아 secret 대조가 유일한 위조 방지 수단
4. 작업 위치: `plugins/_bundled/sirsoft-tosspayments` — 활성 디렉토리 직접 수정 금지
5. 반영: `php artisan plugin:update sirsoft-tosspayments --force`

1. 이 확장은 무엇인가

토스페이먼츠 PG(결제 게이트웨이)를 sirsoft-ecommerce에 연결하는 어댑터입니다. 승인은 브라우저 리다이렉트 기반입니다 — 통합결제창 SDK(js.tosspayments.com/v2/standard)가 결제를 처리한 뒤 브라우저를 ?paymentKey&orderId&amount가 붙은 콜백 URL로 리다이렉트하고, 서버가 그 파라미터로 승인 확인 API를 호출합니다. 다른 PG 플러그인(iframe 팝업/CLI/SOAP)과 달리 프론트엔드 계층이 SDK 호출 하나로 끝나고 프로토콜 복잡도가 대부분 서버 쪽(확인·웹훅)에 있습니다.

이 플러그인은 결제창형과 주문서형(order_sheet_mode) 두 UI 모드를 지원합니다. 결제창형은 통합결제창이 결제수단을 전부 처리하는 카드 하나로 노출되고, 주문서형은 method_* 설정으로 활성화한 개별 토스 결제수단(카드/가상계좌/계좌이체/휴대폰/토스페이/ 카카오페이/네이버페이/페이코/삼성페이)이 체크아웃 화면에 개별 버튼으로 뜹니다 — 어느 쪽이든 최종 처리는 토스 결제창 하나로 귀결되므로 각 수단은 pg_provider 를 이 플러그인 자신으로 고정(pg_locked)합니다(§AGENTS.md "4. 확장점").

설계 원칙: 이 플러그인도 상태를 소유하지 않습니다(§data-model.md — 모델·테이블 0개). 가상계좌 웹훅 검증은 토스가 notify IP 목록이나 서명을 제공하지 않는다는 제약에서 비롯됩니다 — 승인 확인 응답에만 실리는 secret 값을 payment_meta에 저장해 두었다가 웹훅이 도착하면 대조하는 것이 토스 공식 문서가 제시하는 유일한 위조 방지 수단입니다.

의도적으로 하지 않는 것: 승인 확인 시 PG가 돌려준 금액과 서버가 재계산한 주문 금액이 다르면(amount_mismatch) 결제를 완료 처리하지 않고 실패로 되돌립니다 — 콜백 URL의 amount 쿼리 파라미터는 브라우저를 거치므로 신뢰할 수 없는 입력이기 때문입니다.

2. 디렉토리 지도

경로 역할 수정 시 필요한 절차
plugin.json manifest (버전 SSoT) version 변경 시 package.json·package-lock.json·composer.json 동기화
plugin.php 진입 클래스 (선언형 표면 SSoT) 표면 변경 시 ext:docgen 재실행 + 코어 최소 버전 검토
src/Controllers/ 컨트롤러 API 표면 변경 시 api:docgen 재실행
src/Http/Requests/ FormRequest (검증 SSoT) 검증 규칙은 Service 가 아니라 여기에 둔다
src/Services/ 비즈니스 로직 Repository 인터페이스 주입 (구체 클래스 금지)
src/Listeners/ 훅 리스너 Repository 경유 (Model·DB 파사드 직접 접근 금지)
src/routes/ 라우트 모든 라우트에 name() 필수
upgrades/ 업그레이드 스텝 DB·설정 구조 변경 시 작성 (모듈/플러그인 전용)
resources/layouts/ 레이아웃 JSON php artisan plugin:update sirsoft-tosspayments --force (빌드 불필요)
resources/js/ 프론트 엔트리·핸들러 php artisan plugin:build → php artisan plugin:update sirsoft-tosspayments --force
resources/extensions/ 다른 확장 레이아웃에 주입하는 조각 php artisan plugin:update sirsoft-tosspayments --force
dist/ 커밋되는 빌드 산출물 --production 으로 재빌드 (sourceMappingURL 잔존 금지)
config/ 확장 config 설정 기본값은 settings 스키마와 어긋나지 않게
tests/ 테스트 변경 범위만 필터 실행
CHANGELOG.md 변경 이력 버전 상향 시 항목 추가 (미기재 시 버전 상향 불가)
components.json 편집기 컴포넌트 선언 (레이아웃 저작자가 읽는 props 계약) php artisan plugin:update sirsoft-tosspayments --force
docs/ 개발자 문서 표면 변경 시 php artisan ext:docgen 재실행
lang/ 다국어 키 추가 시 ko·en 동시 반영 + 번들 ja 팩 동기화

3. 핵심 흐름

결제 승인: 통합결제창이 브라우저를 /payment/callback?paymentKey&orderId&amount로 리다이렉트 → PaymentCallbackController가 주문 조회 → sirsoft-tosspayments.payment.before_confirm 훅 → TossPaymentsApiService::confirmPayment() 가 토스 승인 확인 API 호출 → 응답 금액과 서버 재계산 금액 대조(불일치 시 실패 처리) → sirsoft-tosspayments.payment.after_confirm 훅 → 이커머스 주문 결제 완료 처리. 가상계좌가 발급된 경우 응답에 실린 secret을 payment_meta.toss_secret에 저장해 이후 웹훅 대조에 씁니다.

가상계좌 입금 웹훅: 토스가 /webhook/deposit으로 POST → 저장된 toss_secret과 웹훅 본문의 secret을 대조(webhook_secret_verify 설정이 꺼져 있지 않은 한 강제) → 일치하면 결제 완료 처리, 불일치하면 경고 로그만 남기고 처리하지 않습니다.

결제 취소(환불): 관리자가 주문 취소(cancel_pg=true) → 코어가 sirsoft-ecommerce.payment.refund 필터 발화 → PaymentRefundListener가 토스 취소 API 호출 → before_cancel/after_cancel 훅 발화.

설정 저장 검증: 관리자가 플러그인 설정을 저장 → core.plugin_settings.before_save (동기 훅, sync: true) → ValidateTossSettingsListener가 vbank_valid_hours(1~2160시간)와 use_escrow(off/on/buyer_choice 3-상태) 범위를 검증 → 위반 시 ValidationException으로 저장 자체를 막습니다.

4. 확장점

확장점 수 상세
발행 훅 4개 발행 훅
구독 훅 9개 구독 훅
훅 리스너 6개 훅 리스너
레이아웃 확장 3개 레이아웃 확장
미들웨어 0개 미들웨어
브로드캐스트 채널 0개 브로드캐스트 채널
스케줄 0개 스케줄
알림 정의 0개 알림 정의

before_confirm/before_cancel은 API 호출 전 개입 지점이라 예외를 던지면 실제 토스 호출이 일어나지 않습니다. core.plugin_settings.before_save를 ValidateTossSettingsListener 가 구독하는 것은 다른 PG 플러그인에는 없는 패턴입니다 — 이 훅은 코어 PluginSettingsService 가 발행하며, sync: true가 없으면 큐로 비동기 디스패치되어 ValidationException이 워커 안에서 죽고 저장은 그대로 진행됩니다(§CLAUDE.md "Listener 데이터 접근 규정" 의 sync 훅 규칙과 동일한 이유).

5. 수정 시 동반 의무

  • _bundled 에서만 수정하고 php artisan plugin:update sirsoft-tosspayments --force 로 반영
  • manifest version 상향 시 package.json · package-lock.json · composer.json 동기화 + CHANGELOG 기재
  • 발행 훅 추가·이름 변경 시 php artisan ext:docgen 재실행 (구독하는 확장의 계약이 바뀝니다)
  • API 표면 변경 시 php artisan api:docgen --scope=plugin:sirsoft-tosspayments 재실행 + docs/api/** 갱신
  • 레이아웃 JSON 변경 시 빌드 없이 update 만 — 신규 Tailwind 클래스는 빌드된 CSS 에 존재하는지 확인
  • TSX/TS 변경 시 --production 재빌드 후 dist/ 커밋 (sourceMappingURL 잔존 금지)
  • 다국어 키 추가 시 ko·en 동시 반영 + 번들 ja 언어팩 증분 동기화
  • 승인 확인에서 금액 대조(amount_mismatch) 로직을 우회하거나 완화하지 않는다
  • 가상계좌 웹훅의 secret 대조(webhook_secret_verify)를 기본값 true 이외로 바꾸지 않는다 — 끄면 토스 노티 위조를 막을 수단이 사라진다
  • order_sheet_mode 관련 로직을 고칠 때 RegisterPgProviderListener(enabled_methods)와 RegisterTossPaymentMethodsListener(builtin 결제수단 주입) 양쪽을 함께 갱신 — 한쪽만 고치면 설정과 노출 목록이 어긋난다
  • ValidateTossSettingsListener에 새 범위 검증을 추가하면 core.plugin_settings.before_save 의 sync: true를 유지
  • 레이아웃·컴포넌트·data_source 를 건드렸다면 docs/editor-spec.md 를 확인 — 이 확장은 편집기 스펙이 없어도 되는 상태(공용 ID 만 사용)다. 이 확장만 쓰는 data_source 를 새로 붙이는 순간 editor-spec.json 신설이 필요해진다

6. 금지 패턴

금지 올바른 사용 이유
콜백 URL의 amount 쿼리 파라미터를 그대로 신뢰해 결제 완료 처리 서버가 주문 금액을 재계산해 PG 응답 금액과 대조, 불일치 시 실패 처리 콜백은 브라우저를 거치므로 사용자가 쿼리 파라미터를 조작해 실제 결제 금액보다 낮은 금액으로 완료 처리를 유도할 수 있다
가상계좌 웹훅의 secret 대조를 생략하거나 항상 통과 payment_meta.toss_secret과 웹훅 본문의 secret을 항상 대조 토스는 notify IP 목록·서명을 제공하지 않아 secret 대조가 유일한 위조 방지 수단이다 — 생략하면 제3자가 임의 주문에 대해 위조 입금통보를 보낼 수 있다
core.plugin_settings.before_save 리스너에 sync: true 없이 등록 저장을 막아야 하는 검증 훅은 반드시 sync: true 기본값(비동기 큐)이면 ValidationException이 워커 안에서 죽고 저장이 그대로 진행되어 검증이 무력화된다
라이브 시크릿 키를 로그·에러 메시지에 노출 운영 키는 항상 마스킹하거나 로그 대상에서 제외 노출되면 제3자가 서버측 API를 위조 호출할 수 있다

7. 테스트 실행

종류 개수 위치
PHPUnit 12개 plugins/_bundled/sirsoft-tosspayments/tests
Vitest 5개 vitest.config.ts
Playwright 0개 —
시나리오 매니페스트 3개 tests/scenarios

기저 TestCase: tests/PluginTestCase.php — 확장 테스트는 이 클래스를 상속합니다 (Tests\TestCase 직접 상속 금지).

# PHPUnit (변경 범위만) (Bash)
php vendor/bin/phpunit plugins/_bundled/sirsoft-tosspayments/tests --filter='<대상클래스>'

# Vitest (확장 디렉토리에서) (PowerShell)
cd plugins/_bundled/sirsoft-tosspayments && powershell -Command "npm run test:run -- <대상>"

무필터 전체 실행은 금지되어 있습니다 — 변경 범위에 걸리는 대상만 지정해 실행합니다.

8. 문서 목차

문서 내용 상태
docs/README.md 문서 통합 목차와 실측 집계 ✅
docs/architecture.md 설계 의도·계층 지도·디렉토리 맵 ✅
docs/extension-points.md 발행/구독 훅·미들웨어·채널·스케줄 ✅
docs/data-model.md 모델·소유 테이블·마이그레이션·Enum ✅
docs/settings.md 설정 스키마·권한·메뉴·라우트·의존 관계 ✅
docs/frontend.md 레이아웃·액션 핸들러·전역 진입점·에셋 ✅
docs/editor-spec.md 레이아웃 편집기에 선언한 팔레트·컨트롤·샘플 데이터 ✅
docs/api/ API 레퍼런스 (엔드포인트별 파라미터·응답 필드) ✅
CHANGELOG.md 변경 이력 ✅