---
template: flow-doc@1
doc_id: 03-subscription-payment
title: site 구독·결제 절차군
config: ../_meta/template-config.yaml
last_verified: 767d1e44
flows:
  - id: subscription-purchase
    actor: 일반회원
    status: conditional-unknown
    status_source: ../06-vendors/03-payments.md#payment:__env__:mode
    unknown_reason: 결제 실행이 어느 공급자 모드로 도는지가 배포 환경 게이트 값에 달려 있고 그 값이 이 저장소에 없다. site 코드는 모듈을 초기화하고 결과 경로로 넘길 뿐이라 어느 공급자가 실제로 발화하는지 동결 트리만으로 판정할 수 없다
    evidence: [S-route, S-component]
    limitations:
      - 결제 성공·실패의 서버 쪽 정산은 이 문서가 판정하지 않는다. site 는 결과 화면까지만 본다
      - 기업 회원의 구매 경로는 일반 회원과 갈리는데 그 분기값이 계정 속성이라 DB 에만 있다
    refs:
      - ./00-ia.md#site-products
      - ./00-ia.md#site-products-payment
      - ./00-ia.md#site-products-payment-select-payment-card
      - ../06-vendors/03-payments.md#payment:__env__:mode
    anchors:
      - insuniverse-site/front/src/App.tsx:416
      - insuniverse-site/front/src/pages/products/ProductsPage.tsx:14
      - insuniverse-site/front/src/features/products/hooks/useProducts.tsx:65
      - insuniverse-site/front/src/features/payment/hooks/usePayment.tsx:100
  - id: subscription-change
    actor: 일반회원
    status: active-prod
    status_source: ./00-ia.md#site-mypage-subscription
    evidence: [S-route, S-component]
    limitations:
      - 변경 가능한 상품 조합은 서버 목록에 달려 있다. 이 문서는 그 목록의 내용을 판정하지 않는다
      - 해지·환불의 승인 규칙 정본은 서버이며 site 는 화면 순서만 갖는다
    refs:
      - ./00-ia.md#site-mypage-subscription
      - ./00-ia.md#site-mypage-subscription-change
      - ./00-ia.md#site-mypage-subscription-change-select-payment-card
      - ./00-ia.md#site-mypage-subscription-cancel
      - ./00-ia.md#site-mypage-subscription-refund
      - ./00-ia.md#site-mypage-subscription-restore-cancel
      - ./00-ia.md#site-mypage-subscription-change-cancel
    anchors:
      - insuniverse-site/front/src/App.tsx:370
      - insuniverse-site/front/src/App.tsx:377
      - insuniverse-site/front/src/pages/mypage/subscription/change/SubscriptionChangePage.tsx:64
      - insuniverse-site/front/src/features/mypage/ui/SubscriptionCard.tsx:70
  - id: subscription-money
    actor: 일반회원
    status: conditional-unknown
    status_source: ../06-vendors/03-payments.md#payment:toss:exception
    unknown_reason: 충전·환불의 실패 처리가 결제 공급자의 예외 규약을 따르는데 그 규약의 활성 조건이 배포 환경 게이트에 있고 이 저장소에 그 값이 없다. site 는 결과 경로만 갖는다
    evidence: [S-route, S-component]
    limitations:
      - 이 흐름의 이동 대상 둘에 등록된 라우트가 없다. 그 사실을 실패·이탈 표에 이름으로 적었고 코드는 고치지 않았다
      - 이탈 전수는 미검증. 이동 대상은 이 흐름에 귀속된 파일의 큰따옴표 리터럴 호출에서만 유도했고, 주석 처리된 블록 안의 호출도 그 유도에 함께 잡힌다
    refs:
      - ./00-ia.md#site-mypage-money
      - ./00-ia.md#site-mypage-money-refund
      - ./00-ia.md#site-mypage-money-payment-cancel
      - ./00-ia.md#site-payment
      - ./00-ia.md#site-payment-result
      - ./00-ia.md#site-mypage-payment-history
      - ./00-ia.md#site-mypage-edit-payment-card
      - ../06-vendors/03-payments.md#payment:toss:exception
    anchors:
      - insuniverse-site/front/src/App.tsx:380
      - insuniverse-site/front/src/App.tsx:383
      - insuniverse-site/front/src/pages/payment/PaymentPage.tsx:341
      - insuniverse-site/front/src/pages/payment/PaymentPage.tsx:481
      - insuniverse-site/front/src/pages/mypage/money/MoneyPage.tsx:276
  - id: subscription-invoice
    actor: 일반회원
    status: active-prod
    status_source: ./00-ia.md#site-invoices
    evidence: [S-route, S-component]
    limitations:
      - 팩스 전송의 성공 여부는 외부 전송 결과에 달려 있다. site 는 결과 화면까지만 본다
      - 출력 5단계 사이의 입력 보관은 화면 상태이며 새로고침 내구성은 이 창이 확인하지 않았다
    refs:
      - ./00-ia.md#site-invoices
      - ./00-ia.md#site-invoices-output-step-one
      - ./00-ia.md#site-invoices-output-step-two
      - ./00-ia.md#site-invoices-output-step-three
      - ./00-ia.md#site-invoices-output-step-four
      - ./00-ia.md#site-invoices-output-step-five
      - ./00-ia.md#site-invoices-fax-send
      - ./00-ia.md#site-invoices-fax-result
      - ./00-ia.md#site-invoices-list
    anchors:
      - insuniverse-site/front/src/App.tsx:405
      - insuniverse-site/front/src/App.tsx:413
      - insuniverse-site/front/src/pages/invoices/output/Step1Page.tsx:116
      - insuniverse-site/front/src/pages/invoices/FaxSendPage.tsx:1146
---

# site 구독·결제 절차군

이 문서는 **구독을 사고 바꾸고, 머니를 충전하고, 계산서를 뽑는** 절차군을 담는다. 화면 구조의 정본은 [화면 인벤토리](./00-ia.md)이고, 결제 공급자 규약의 정본은 [결제 벤더 정책](../06-vendors/03-payments.md)이다. 여기서는 순서만 쓴다.

네 흐름이 서로 다른 것을 보여준다. `subscription-purchase` 는 구독이 없는 계정이 구독을 얻는 구간, `subscription-change` 는 이미 구독한 계정이 상품을 바꾸거나 해지·복구하는 구간, `subscription-money` 는 구독과 별개인 선불 머니 축, `subscription-invoice` 는 결제 이력에서 계산서를 뽑는 축이다.

**결제 공급자가 걸리는 두 흐름의 status 는 `conditional-unknown` 이다.** 어느 공급자 모드로 도는지가 배포 환경 게이트 값이고 그 값이 이 저장소에 없다. 이 문서는 그 판정을 복제하지 않고 벤더 정책으로 링크한다.

**분석 요청의 구독 게이트는 이 문서에 없다.** 그쪽은 [진료·손해 분석 절차군](./01-analysis-flow.md)이며 여기서는 구독을 만드는 쪽만 쓴다.

## 흐름 목록

| flow id | 목적 | actor | status |
|---|---|---|---|
| subscription-purchase | 구독 상품을 골라 결제까지 마친다 | 일반회원 | conditional-unknown |
| subscription-change | 보유 구독을 바꾸거나 해지·환불·복구한다 | 일반회원 | active-prod |
| subscription-money | 선불 머니를 충전하고 환불·취소한다 | 일반회원 | conditional-unknown |
| subscription-invoice | 결제 이력에서 계산서를 뽑아 저장하거나 팩스로 보낸다 | 일반회원 | active-prod |

## 흐름

### subscription-purchase

**전제**

- 로그인 세션이 있다
- 결제 수단을 등록할 수 있다. 등록 화면은 이 흐름 안에 있다
- 일반 회원이다. 기업 회원은 결제 모듈 초기화 단계에서 되돌려진다 (`usePayment.tsx:194`)

**절차**

1. 회원이 `site-products` 에서 상품 목록을 연다.
2. 상품을 고르면 `site-products-payment` 로 이동한다 (`useProducts.tsx:65`).
3. 약관에 동의하고 제출하면 `site-products-payment-select-payment-card` 로 이동해 결제 수단을 고른다 (`usePayment.tsx:100`).
4. 결제가 끝나면 메인으로 돌아간다.

**결제 모듈은 화면을 떠날 때 취소된다.** 화면이 사라지는 시점에 진행 중인 결제를 취소하는 정리가 걸려 있어, 결제창을 띄운 채 뒤로 가면 그 시도는 남지 않는다.

**권한**

| 층 | 차단성 | 이 흐름에서의 강제 지점 | 실패 시 |
|---|---|---|---|
| 인증 | 차단 | 라우트 트리의 세션 가드가 세션 없는 진입을 로그인 화면으로 보낸다 (`useAuthGuard.tsx:52`) | 로그인 화면으로 이동 |
| 계정 종류 | 차단 | 결제 화면이 계정 종류를 보고 일반 회원이 아니면 메인으로 되돌린다 (`usePayment.tsx:194`). site 쪽 화면 층의 판정이며 서버 축의 정본은 [역할 총론](../02-access/02-authz-roles.md)이다 | 메인으로 이동 |
| 쓰기 스코프 | 차단 | 해당 없음 — 조직관리자 읽기전용 가드는 admin 콘솔 요청에만 발화한다 | 해당 없음 |
| 기업 노출 등급 | 차단 | 해당 없음 — admin 콘솔 축이다 | 해당 없음 |
| 메뉴 노출 | 비차단 | 상품 화면은 헤더에서도 열린다. 사이드바 노출과 무관하게 경로를 직접 열면 세션 가드만 지난다 | URL 을 직접 치면 인증 층만 통과하면 열린다 |

**실패·이탈**

| 지점 | 조건 | 결과 |
|---|---|---|
| 1단계 진입 | 문의가 필요하다 | 계속 게시판의 문의 작성 경로로 보낸다 |
| 2단계 이동 | 고른 상품이 조회되지 않는다 | 막다름. 목록 화면에 머문다 |
| 3단계 제출 | 필수 동의가 비어 있다 | 계속 동의 요구 모달을 띄운다 |
| 3단계 진입 | 계정 종류가 일반이 아니다 | ./00-ia.md#site-main 으로 되돌린다 |
| 4단계 결제 | 결제 공급자가 실패를 낸다 | fail-closed 결과를 성공으로 취급하지 않는다. 판정 규약의 정본은 [결제 벤더 정책](../06-vendors/03-payments.md)이다 |

### subscription-change

**전제**

- 로그인 세션이 있고 구독 이력이 있다
- 바꿀 상품이 서버 목록에 둘 이상 있다. 하나뿐이면 변경 버튼이 제안되지 않는다

**절차**

1. 회원이 `site-mypage-subscription` 에서 자기 구독 상태를 연다.
2. 변경을 고르면 `site-mypage-subscription-change` 로 간다 (`SubscriptionCard.tsx:70`).
3. 변경 약관에 동의하는 화면을 지난다 (`SubscriptionChangePage.tsx:64`).
4. `site-mypage-subscription-change-select-payment-card` 에서 결제 수단을 고르면 변경이 확정된다.
5. 해지는 `site-mypage-subscription-cancel`, 환불은 `site-mypage-subscription-refund`, 예약된 변경 취소는 `site-mypage-subscription-change-cancel`, 해지 철회는 `site-mypage-subscription-restore-cancel` 이 각각 맡는다.

**5단계의 네 화면은 서로 배타적이지 않다.** 구독 상태에 따라 그중 일부만 카드에 버튼으로 나타난다. 어떤 상태에서 어떤 버튼이 나오는지는 서버가 준 구독 상태값에 달려 있고 이 문서는 그 매핑을 판정하지 않는다.

**권한**

| 층 | 차단성 | 이 흐름에서의 강제 지점 | 실패 시 |
|---|---|---|---|
| 인증 | 차단 | 라우트 트리의 세션 가드 (`useAuthGuard.tsx:52`) | 로그인 화면으로 이동 |
| 계정 종류 | 차단 | 해당 없음 — 이 화면들은 계정 종류를 보고 되돌리지 않는다 | 해당 없음 |
| 쓰기 스코프 | 차단 | 해당 없음 — admin 콘솔 축이다 | 해당 없음 |
| 기업 노출 등급 | 차단 | 해당 없음 — admin 콘솔 축이다 | 해당 없음 |
| 메뉴 노출 | 비차단 | 마이페이지 하위 경로라 사이드바가 아니라 마이페이지 카드에서 열린다 | URL 을 직접 치면 인증 층만 통과하면 열린다 |

**실패·이탈**

| 지점 | 조건 | 결과 |
|---|---|---|
| 2단계 제안 | 바꿀 수 있는 상품이 둘 미만이다 | 계속 변경 버튼을 제안하지 않는다 |
| 4단계 확정 | 결제 수단 등록이 없다 | 계속 등록 화면을 먼저 연다 |
| 4단계 확정 | 확정 후 | ./00-ia.md#site-main 으로 돌아간다 |
| 5단계 해지 철회 | 철회가 끝난다 | ./00-ia.md#site-main 으로 돌아간다 |
| 전 단계 | 세션이 만료됐다 | HTTP 401. 세션 만료 처리가 로그아웃으로 이어진다 |

### subscription-money

**전제**

- 로그인 세션이 있다
- 충전에 쓸 결제 수단이 있거나 이 흐름 안에서 등록한다

**절차**

1. 회원이 `site-mypage-money` 에서 잔액과 이력을 연다.
2. 충전을 고르면 `site-payment` 로 이동한다 (`MoneyPage.tsx:352`).
3. 결제가 끝나면 `site-payment-result` 가 결과를 보여주고 잔액 화면으로 돌아간다.
4. 환불은 `site-mypage-money-refund`, 결제 취소는 `site-mypage-money-payment-cancel` 이 맡는다 (`MoneyPage.tsx:276`).
5. 결제 수단 관리는 `site-mypage-edit-payment-card`, 결제 이력은 `site-mypage-payment-history` 가 맡는다.

**이 흐름에는 등록된 라우트가 없는 이동 대상이 둘 있다.** 하나는 충전 화면의 미로그인 분기가 `/account/signin` 으로 보내는 자리다 (`PaymentPage.tsx:481`) — 이 경로는 라우트 트리에 없고 실제 로그인 경로는 `/auth/login` 이다. 다른 하나는 `/mypage/money/auto-charge` 인데 (`PaymentPage.tsx:341`) **그 호출은 주석 처리된 블록 안에 있어 현재 도달하지 않는다.** 둘 다 이 창이 코드로 고치지 않고 사실만 적는다.

**권한**

| 층 | 차단성 | 이 흐름에서의 강제 지점 | 실패 시 |
|---|---|---|---|
| 인증 | 차단 | 라우트 트리의 세션 가드 (`useAuthGuard.tsx:52`). 충전 화면 안에도 계정 식별자를 보는 분기가 하나 더 있다 (`PaymentPage.tsx:481`) | 로그인 화면으로 이동 |
| 계정 종류 | 차단 | 해당 없음 — 머니 화면은 계정 종류를 보고 되돌리지 않는다 | 해당 없음 |
| 쓰기 스코프 | 차단 | 해당 없음 — admin 콘솔 축이다 | 해당 없음 |
| 기업 노출 등급 | 차단 | 해당 없음 — admin 콘솔 축이다 | 해당 없음 |
| 메뉴 노출 | 비차단 | 마이페이지 카드에서 연다 | URL 을 직접 치면 인증 층만 통과하면 열린다 |

**실패·이탈**

| 지점 | 조건 | 결과 |
|---|---|---|
| 2단계 충전 | 계정 식별자가 없다 | 막다름. `/account/signin` 으로 보내는데 그 경로의 라우트가 등록돼 있지 않다 |
| 1단계 진입 | 자동 충전 진입점을 누른다 | 막다름. `/mypage/money/auto-charge` 로 보내는 호출이 주석 처리 블록 안이라 현재 도달하지 않는다 |
| 3단계 결과 | 결제 공급자가 실패를 낸다 | fail-closed 잔액을 올리지 않는다. 판정 규약의 정본은 [결제 벤더 정책](../06-vendors/03-payments.md)이다 |
| 4단계 환불 | 환불이 끝난다 | ./00-ia.md#site-mypage-money 로 돌아간다 |
| 4단계 취소 | 취소가 끝난다 | ./00-ia.md#site-mypage-money 로 돌아간다 |

### subscription-invoice

**전제**

- 로그인 세션이 있다
- 계산서를 뽑을 결제 이력이 있다

**절차**

1. 회원이 `site-invoices` 에서 계산서 진입점을 연다.
2. 출력은 `site-invoices-output-step-one` 부터 다섯 단계를 지난다 — `site-invoices-output-step-two` · `site-invoices-output-step-three` · `site-invoices-output-step-four` · `site-invoices-output-step-five` (`pages/invoices/output/Step1Page.tsx:116`).
3. 발행된 계산서는 `site-invoices-list` 에서 다시 연다.
4. 팩스로 보내려면 `site-invoices-fax-send` 에서 보내고 `site-invoices-fax-result` 가 결과를 보여준다 (`FaxSendPage.tsx:1146`).

**출력 단계 사이의 입력은 화면 상태로 들고 다닌다.** 세션 가드가 출력 경로를 벗어나는 순간 그 상태를 비우므로, 중간에 다른 화면으로 나갔다 오면 처음부터 다시 넣어야 한다 (`useAuthGuard.tsx:44`).

**권한**

| 층 | 차단성 | 이 흐름에서의 강제 지점 | 실패 시 |
|---|---|---|---|
| 인증 | 차단 | 라우트 트리의 세션 가드 (`useAuthGuard.tsx:52`) | 로그인 화면으로 이동 |
| 계정 종류 | 차단 | 해당 없음 — 계산서 화면은 계정 종류를 보고 되돌리지 않는다 | 해당 없음 |
| 쓰기 스코프 | 차단 | 해당 없음 — admin 콘솔 축이다 | 해당 없음 |
| 기업 노출 등급 | 차단 | 해당 없음 — admin 콘솔 축이다 | 해당 없음 |
| 메뉴 노출 | 비차단 | 계산서는 사이드바 항목으로 열린다 | URL 을 직접 치면 인증 층만 통과하면 열린다 |

**실패·이탈**

| 지점 | 조건 | 결과 |
|---|---|---|
| 2단계 진행 | 출력 경로를 벗어난다 | 계속 보관하던 입력을 비운다 |
| 2단계 완료 | 마지막 단계가 끝난다 | ./00-ia.md#site-invoices 로 돌아간다 |
| 4단계 전송 | 전송이 끝난다 | ./00-ia.md#site-invoices-fax-result 로 이동한다 |
| 4단계 전송 | 잔액이 모자란다 | 계속 충전 경로를 제안한다 |
| 전 단계 | 세션이 만료됐다 | HTTP 401. 세션 만료 처리가 로그아웃으로 이어진다 |

## 플랫폼 차이 (웹 / 웹뷰)

계산서와 결제 영수증의 저장은 [진료·손해 분석 절차군](./01-analysis-flow.md)의 PDF 저장과 같은 갈림을 탄다 — 웹은 브라우저 저장, 앱 웹뷰는 브리지 호출이다.

구독이 없는 계정이 구독 필요 안내를 받았을 때의 이동 대상도 단말에 따라 갈린다. 웹은 구매 화면으로, 앱 웹뷰는 메인으로 보낸다. 그 갈림의 서술은 분석 절차군에 있다.

## 연혁

| 릴리스 | 날짜 | SHA | 변경 요약 |
|---|---|---|---|
| — | 2026-08-27 | 767d1e44 | 최초 저작. 동결 HEAD 의 라우트 트리와 결제·구독·계산서 화면 정독에서 네 흐름을 유도했다 |
