부모 티켓
1개 티켓

백로그

0
티켓 없음

할 일

0
티켓 없음

진행 중

0
티켓 없음

리뷰

1
높음 42a75287
서브 티켓 [P4] 토스 웹훅 처리

토스 웹훅 — Payments::WebhooksController + HMAC 서명 검증 + PAYMENT_STATUS_CHANGED 처리 + 테스트

## 목표 PRD Section 11.4 기반 토스 웹훅 처리. CSRF skip, HMAC SHA-256 서명 검증, PAYMENT_STATUS_CHANGED 이벤트 처리. ## 현재 상태 - Payments::WebhooksController 스텁 존재 (receive 액션, allow_unauthenticated_access + skip_forgery_protection 설정됨) - 라우트: `post "/payments/webhook", to: "payments/webhooks#receive"` - Payment 모델: toss_payment_key, status enum {pending:0, done:1, canceled:2, failed:3}, paid_at, canceled_at ## PRD 코드 (Section 11.4) ```ruby class Payments::WebhooksController < ApplicationController skip_before_action :verify_authenticity_token allow_unauthenticated_access def receive unless valid_signature? return render json: { error: "Invalid signature" }, status: :unauthorized end payload = JSON.parse(request.body.read) case payload["eventType"] when "PAYMENT_STATUS_CHANGED" handle_payment_status_changed(payload["data"]) end render json: { received: true } end private def valid_signature? secret = ENV["TOSS_WEBHOOK_SECRET"] signature = request.headers["TossPayments-Signature"] body = request.body.read request.body.rewind expected = OpenSSL::HMAC.hexdigest("sha256", secret, body) ActiveSupport::SecurityUtils.secure_compare(expected, signature.to_s) end def handle_payment_status_changed(data) payment = Payment.find_by(toss_payment_key: data["paymentKey"]) return unless payment case data["status"] when "DONE" then payment.update!(status: :done, paid_at: Time.current) when "CANCELED" then payment.update!(status: :canceled, canceled_at: Time.current) when "ABORTED", "EXPIRED" then payment.update!(status: :failed) end end end ``` ## 구현 사항 1. **Payments::WebhooksController** — PRD 코드 기반 2. **⚠️ request.body.read 주의**: body를 두 번 읽으므로 rewind 필요 3. **HMAC SHA-256 서명 검증**: TOSS_WEBHOOK_SECRET + secure_compare 4. **PAYMENT_STATUS_CHANGED만 처리** (v2.1: BILLING_SKIPPED 삭제) 5. **allow_unauthenticated_access** 이미 설정되어 있을 수 있음 — 확인 후 유지 ### 테스트 - 유효한 서명 → 200 + Payment 상태 변경 - 무효한 서명 → 401 - DONE → payment.done, CANCELED → payment.canceled, ABORTED → payment.failed - 없는 paymentKey → 무시 (200 반환) - 알 수 없는 eventType → 무시 ### ⚠️ payments/webhooks 범위만 (developer-2는 payments/checkout, completions 작업 중) ## 대시보드 기록 (MCP) - 시작: `AddActivityLogTool` (ticket_id: "c547c6c5-b25a-4c42-a7fe-850261c83e5a", message: "토스 웹훅 시작") - 완료: `AddActivityLogTool` (message: "토스 웹훅 완료", details 필수) ## 완료 절차 1. `UpdateTicketStatusTool`로 서브 티켓 → `review` 2. `AddActivityLogTool`로 완료 기록 3. `SendMessage`로 팀리드에게 보고 (summary: "토스 웹훅 구현 완료") ⚠️ SendMessage 필수!

D
developer-1
25 days

완료 (전체)

0
티켓 없음