고객 결제 페이지 + Toss Payments 연동

ID: 602607e3-57c1-43b5-be0f-8eb47c2158a1

높음 완료

## 작업 내용
고객이 커스텀 결제 링크를 통해 접근하여 Toss Payments로 결제할 수 있는 공개 페이지를 구현합니다.

## 1. CustomPaymentsController
로그인 불요 (공개 페이지). ApplicationController 상속하되 skip_before_action :require_authentication.

### show (GET /pay/:token)
- CustomPaymentLink.find_by!(token: params[:token])
- 만료/취소/완료 여부 체크
- 만료됨 → expired 상태 표시
- 취소됨 → canceled 상태 표시
- 결제완료 → 이미 완료 메시지
- 대기중 → 결제 폼 표시

### checkout (POST /pay/:token/checkout)
- 결제 링크 유효성 검증 (pending? && !expired?)
- 고객용 임시 User 생성 또는 guest 처리
- 실제로는 Toss에서 결제 처리하므로 user 없이도 가능
- Payment 생성 시 user_id는 결제 링크 생성자(admin)의 ID 사용
- Payments::CheckoutService 호출:
- payment_type: "CUSTOM"
- amount: custom_payment_link.amount
- description: custom_payment_link.title
- metadata: { custom_payment_link_id: link.id }
- JSON 응답으로 Toss SDK용 데이터 반환

### success (GET /pay/:token/success)
- Payments::ConfirmationService로 결제 승인
- CustomPaymentLink 상태를 completed로 변경
- payment 연결, paid_at 설정
- 성공 페이지 표시

### fail (GET /pay/:token/fail)
- 실패 메시지 표시
- 다시 시도 링크 제공

## 2. 뷰
### show.html.erb - 결제 페이지
- 독립 레이아웃 (admin/user 레이아웃 아님)
- 깔끔한 결제 카드 형태:
- 9WAY 로고
- 상품명 (title)
- 상세 설명 (description)
- 결제 금액 (amount) - 큰 글씨
- "결제하기" 버튼
- Toss Payments SDK 로드:
```html

```
- Stimulus 또는 vanilla JS로 Toss 결제 위젯 초기화
- 결제 시퀀스:
1. "결제하기" 클릭
2. POST /pay/:token/checkout으로 주문 생성
3. 응답의 orderId, amount로 Toss requestPayment() 호출
4. 성공 → /pay/:token/success?paymentKey=...&orderId=...&amount=...
5. 실패 → /pay/:token/fail?code=...&message=...
- 만료/취소/완료 시 적절한 메시지 표시

### success.html.erb - 결제 성공
- 성공 아이콘 + "결제가 완료되었습니다" 메시지
- 결제 정보 요약 (상품명, 금액, 결제일시)

### 기존 참고 코드
- app/controllers/payments_controller.rb의 checkout/success/fail 패턴
- app/services/payments/checkout_service.rb의 결제 생성 로직
- app/services/payments/confirmation_service.rb의 결제 승인 로직
- 기존 Toss client_key: Rails.application.config.toss_payments.client_key

## 3. 레이아웃
- 별도의 minimal 레이아웃 사용: layout "custom_payment"
- app/views/layouts/custom_payment.html.erb 생성
- 심플한 흰색 배경 + 가운데 정렬 카드

## 4. 라우팅
라우팅은 "백엔드" 에이전트가 처리합니다. 다음 경로를 사용합니다:
- GET /pay/:token → custom_payments#show
- POST /pay/:token/checkout → custom_payments#checkout
- GET /pay/:token/success → custom_payments#success
- GET /pay/:token/fail → custom_payments#fail

## 담당 파일
- app/controllers/custom_payments_controller.rb
- app/views/custom_payments/show.html.erb
- app/views/custom_payments/success.html.erb
- app/views/layouts/custom_payment.html.erb
- app/javascript/controllers/toss_custom_payment_controller.js
- test/controllers/custom_payments_controller_test.rb

## 완료 기준
- 유효한 토큰으로 결제 페이지 접근 가능
- 만료/취소/완료 상태 적절히 표시
- Toss Payments 결제 플로우 동작
- 결제 성공 시 CustomPaymentLink 상태 업데이트
- 컨트롤러 테스트 통과

첨부 이미지

이미지 추가 (Ctrl+V로 붙여넣기 또는 클릭)

JPEG, PNG, GIF, WebP / 최대 10MB

담당자: 결제-페이지
생성일: 2026년 02월 28일 07:20

활동 로그

  • 팀리드 상태 변경: 리뷰 → 완료

    2026년 02월 28일 07:39:55

  • 결제-페이지 상태 변경: 진행 중 → 리뷰

    2026년 02월 28일 07:38:21

  • 결제-페이지 고객 결제 페이지 + Toss Payments 연동 구현 완료, 12개 테스트 전부 통과

    2026년 02월 28일 07:38:20

    상세 보기

    ## 생성된 파일
    - `app/controllers/custom_payments_controller.rb` - 공개 결제 컨트롤러 (show/checkout/success/fail)
    - `app/views/layouts/custom_payment.html.erb` - 심플 레이아웃 (Toss SDK 포함)
    - `app/views/custom_payments/show.html.erb` - 결제 페이지 (로고+상품정보+결제버튼)
    - `app/views/custom_payments/success.html.erb` - 결제 성공 페이지
    - `app/views/custom_payments/fail.html.erb` - 결제 실패 페이지
    - `app/views/custom_payments/expired.html.erb` - 만료 안내 페이지
    - `app/views/custom_payments/canceled.html.erb` - 취소 안내 페이지
    - `app/views/custom_payments/completed.html.erb` - 이미 완료 안내 페이지
    - `app/javascript/controllers/toss_custom_payment_controller.js` - Toss Payments Stimulus 컨트롤러
    - `test/integration/custom_payments_test.rb` - 통합 테스트 12개

    ## 테스트 결과
    12 runs, 33 assertions, 0 failures, 0 errors, 0 skips

    ## 주요 구현 내용
    - `allow_unauthenticated_access`로 인증 skip (공개 페이지)
    - `Payments::CheckoutService` 연동 (checkout 액션)
    - `Payments::ConfirmationService` 연동 (success 액션)
    - 결제 링크 상태별 분기 렌더링 (pending/completed/canceled/expired)
    - Toss Payments v2 SDK + Stimulus 컨트롤러로 결제 플로우 연동
    - locale scope 밖 라우트를 위해 `default_url_options` 오버라이드

  • 결제-페이지 기존 코드 분석 완료, 컨트롤러/뷰/테스트 작성 시작

    2026년 02월 28일 07:28:57

    상세 보기

    ## 분석 완료 항목
    - ApplicationController: `Authentication` concern, `allow_unauthenticated_access` 사용
    - PaymentsController: checkout/success/fail 패턴 확인
    - Payments::CheckoutService, ConfirmationService 패턴 확인
    - 기존 toss_payment_controller.js Stimulus 패턴 확인
    - CustomPaymentLink 모델 + fixtures 확인
    - 라우트: locale scope 밖 `/pay/:token` 설정 확인

    ## 구현 계획
    1. CustomPaymentsController (인증 skip, show/checkout/success/fail)
    2. custom_payment 레이아웃
    3. show/success/fail/expired/canceled/completed 뷰
    4. toss_custom_payment Stimulus 컨트롤러
    5. 통합 테스트

  • 결제-페이지 티켓 클레임 완료

    2026년 02월 28일 07:27:55