---
template: policy-doc@1
doc_id: 04-settlement-money
title: 정산·머니 도메인 — 지갑과 출처 · 지급 유형 어휘 · 조직 범위 재검증 · 결제 상태와 수단 · 카드 대표 지정 · 환불 코드 · 청구서 조립 · 청구서 소유자 검증 미배포
config: ../_meta/template-config.yaml
last_verified: 4d798f55
policies:
  - id: MONEY_WALLET_SOURCES
    status: active-prod
    evidence: [S-schema, S-route]
    limitations:
      - 지갑과 출처·사용 이력이 각각 자기 자료형을 갖는다는 것까지가 관측이다. 잔액이 어느 자료를 정본으로 삼는지는 이 문서가 판정하지 않는다
      - 개인 지갑과 기업 지갑의 합산 규칙은 세지 않았다
    anchors:
      - insuniverse-server/apps/api/src/modules/money/money-wallet.entity.ts:7
      - insuniverse-server/apps/api/src/modules/money/money-source.entity.ts:49
      - insuniverse-server/apps/api/src/modules/money/money-corp.entity.ts:7
      - insuniverse-server/apps/api/src/modules/money/money.controller.ts:39
  - id: MONEY_ISSUE_VOCAB
    status: active-prod
    evidence: [S-constant, S-schema]
    limitations:
      - 지급·회수·부여가 서로 다른 어휘로 갈린다는 것까지가 관측이다. 각 유형이 잔액에 더해지는 순서나 소멸 우선순위는 이 문서가 판정하지 않는다
      - 어휘가 담긴 자리는 열되 각 값의 운영상 뜻은 적지 않는다
    anchors:
      - insuniverse-server/apps/api/src/modules/money/money.dto.ts:36
      - insuniverse-server/apps/api/src/modules/money/money-issue.entity.ts:9
      - insuniverse-server/apps/api/src/modules/money/money-grant.entity.ts:7
  - id: MONEY_ISSUE_ORG_RECHECK
    status: active-prod
    evidence: [S-guard, S-roles]
    limitations:
      - 지급 입구가 역할 판정 뒤에 조직 범위를 한 번 더 확인한다는 것까지가 관측이다. 그 재확인이 모든 지급 경로를 덮는지는 이 문서가 전수로 세지 않았다
      - 범위 식별자의 산출은 총론 권한 축이 진다
    anchors:
      - insuniverse-server/apps/api/src/modules/money/money-admin.controller.ts:71
      - insuniverse-server/apps/api/src/modules/money/money-admin.controller.ts:86
      - insuniverse-server/apps/api/src/modules/money/money.service.ts:201
  - id: MONEY_CHARGE_CALLBACK
    status: active-prod
    evidence: [S-route, S-contract]
    limitations:
      - 충전 승인·취소가 인증 없는 별도 입구로 들어온다는 것까지가 관측이다. 그 입구의 위조 방어가 무엇인지는 이 문서가 판정하지 않는다
      - 결제사 쪽 계약 문서는 이 저장소 밖이다
    anchors:
      - insuniverse-server/apps/api/src/modules/money/money-public.controller.ts:12
      - insuniverse-server/apps/api/src/modules/money/money-charge-request.entity.ts:6
  - id: PAYMENT_STATE_AND_METHOD
    status: active-prod
    evidence: [S-constant, S-schema]
    limitations:
      - 결제 상태와 수단이 서로 다른 축이라는 것까지가 관측이다. 상태 사이의 허용 전이는 총론 상태 축이 지며 이 문서가 다시 쓰지 않는다
      - 수단 코드값이 담긴 자리는 열되 각 값과 결제사의 대응은 총론 벤더 축 소관이다
    anchors:
      - insuniverse-server/apps/api/src/modules/payment/payment.entity.ts:6
      - insuniverse-server/apps/api/src/modules/payment/payment.entity.ts:12
      - insuniverse-server/apps/api/src/modules/payment/payment.repository.ts:12
  - id: PAYMENT_SUBSCRIPTION_BRANCH
    status: active-prod
    evidence: [S-contract, S-route]
    limitations:
      - 최초 결제·정기 결제·체험 결제가 서로 다른 처리기로 갈린다는 것까지가 관측이다. 각 처리기가 실패했을 때 구독 상태가 어떻게 되는지는 `03-subscription-order.md` 축이며 여기서 다시 쓰지 않는다
      - 취소 경로가 주체 종류로 갈린다는 것은 관측이되 그 분기의 전수는 세지 않았다
    anchors:
      - insuniverse-server/apps/api/src/modules/payment/payment.service.ts:40
      - insuniverse-server/apps/api/src/modules/payment/payment.service.ts:90
      - insuniverse-server/apps/api/src/modules/payment/payment.service.ts:118
  - id: CARD_PRIMARY_SELECTION
    status: active-prod
    evidence: [S-guard, S-route]
    limitations:
      - 카드 목록과 대표 지정이 로그인 주체에 묶인다는 것까지가 관측이다. 한 주체가 등록할 수 있는 카드 수 상한은 세지 않았다
      - 카드 자료가 결제사 쪽 식별자만 담는지 원문을 담는지는 이 문서가 판정하지 않는다
    anchors:
      - insuniverse-server/apps/api/src/modules/card/card.controller.ts:22
      - insuniverse-server/apps/api/src/modules/card/card.controller.ts:41
  - id: REFUND_OUTCOME_CODES
    status: active-prod
    evidence: [S-constant, S-schema]
    limitations:
      - 환불 결과가 두 코드값으로 갈린다는 것까지가 관측이다. 반려 사유의 어휘 집합은 고정돼 있지 않다
      - 환불이 머니 잔액에 어떻게 반영되는지는 이 문서가 추적하지 않았다
    anchors:
      - insuniverse-server/apps/api/src/modules/refund/refund.entity.ts:10
      - insuniverse-server/apps/api/src/modules/refund/refund.service.ts:10
  - id: INVOICE_ASSEMBLY
    status: active-prod
    evidence: [S-roles, S-component]
    limitations:
      - 청구서가 보험사별 서식을 받아 조립된다는 것까지가 관측이다. 서식 파일의 갱신 주기와 소유자는 이 저장소가 말하지 않는다
      - 조립 결과의 보존 여부와 위치는 이 문서가 세지 않았다
    anchors:
      - insuniverse-server/apps/api/src/modules/invoice/invoice-admin.controller.ts:40
      - insuniverse-server/apps/api/src/modules/invoice/invoice-storage.service.ts:12
      - insuniverse-server/apps/api/src/modules/invoice/invoice.builder.ts:33
  - id: INVOICE_OWNER_GUARD
    status: staged-only
    evidence: [S-guard, A-release]
    limitations:
      - 미도달 판정의 근거는 이 앵커 행의 최종 변경 커밋 하나다. 그 행이 뒤에 다른 커밋으로 밀리면 같은 규칙이 도달로 뒤집힐 수 있다
      - 도달성의 정본은 릴리스 인덱스이고 그 인덱스가 배포를 확증하지는 않는다
    anchors:
      - insuniverse-server/apps/api/src/modules/invoice/invoice.controller.ts:41
---

# 정산·머니 도메인 — 지갑과 출처 · 지급 유형 어휘 · 조직 범위 재검증 · 결제 상태와 수단 · 카드 대표 지정 · 환불 코드 · 청구서 조립 · 청구서 소유자 검증 미배포

**돈이 어디서 들어와 어디로 나가는가**를 다룬다. 잔액을 담는 지갑과 그 출처, 지급·회수·부여의 어휘, 지급 입구의 조직 범위 재확인, 충전 승인 콜백, 결제의 상태·수단 축, 카드 대표 지정, 환불 결과 코드, 청구서 조립이 여기 있다.

**여기 없는 것** — 무엇을 사는가와 구독 상태는 `03-subscription-order.md` 가, 결제 알림 발송은 `06-communication.md` 가 진다. 결제사별 실패 의미와 결제 주기 스케줄, 한도 규칙의 정의는 총론 소관이며 이 문서는 그 규칙이 이 도메인 자료에 걸리는 자리만 낸다.

## 정책 (기획)

### MONEY_WALLET_SOURCES

**잔액은 하나의 통이 아니라 지갑·출처·사용 이력 여러 자료로 나뉘어 있다.** 개인 지갑과 기업 지갑이 각각 자기 자료형을 갖고, 들어온 자리와 쓰인 자리가 별도로 쌓인다. 사용자는 자기 잔액과 그 내역을 조회로 연다.

### MONEY_ISSUE_VOCAB

**머니가 늘어나는 방식은 여러 어휘로 갈린다.** 적립되는 것, 적립을 되돌리는 것, 운영이 직접 부여하는 것이 서로 다른 유형이고, 각각 대상 목록을 딸린 자료로 갖는다.

### MONEY_ISSUE_ORG_RECHECK

**머니 지급 입구는 역할 판정만으로 열리지 않는다.** 기업 측 주체가 지급을 요청하면 그 대상이 자기 조직 범위 안인지가 한 번 더 확인되고, 이 재확인은 목록 조회의 필터와 별개로 지급 처리 자체에 걸린다.

### MONEY_CHARGE_CALLBACK

**충전의 승인과 취소는 사용자 로그인 없이 들어오는 별도 입구로 통보된다.** 충전 요청은 자기 자료로 먼저 쌓이고, 결제사 쪽에서 결과가 이 입구로 돌아온다.

### PAYMENT_STATE_AND_METHOD

**결제는 상태 축과 수단 축을 따로 갖는다.** 어디까지 진행됐는가와 무엇으로 냈는가가 서로 다른 코드값이며, 결제 건은 결제사 쪽 거래 식별자로 되찾는다.

### PAYMENT_SUBSCRIPTION_BRANCH

**결제 처리는 최초·정기·체험 세 갈래로 갈린다.** 같은 입구가 아니라 각각 다른 처리기이며, 취소 경로도 주체 종류에 따라 다시 갈린다.

### CARD_PRIMARY_SELECTION

**카드는 로그인 주체에 묶이고 그중 하나가 대표가 된다.** 목록·등록·대표 변경이 모두 그 주체의 것만 다룬다.

### REFUND_OUTCOME_CODES

**환불의 결과는 완료와 반려 두 코드값으로 갈린다.** 반려에는 사유가 함께 남지만 그 사유의 어휘는 고정돼 있지 않다.

### INVOICE_ASSEMBLY

**청구서는 보험사별 서식을 받아 그 위에 값을 얹어 조립한다.** 서식·글꼴·표시 이미지가 각각 별도 저장소에서 오고, 서식 등록은 관리자 한 종류만 한다.

## 강제 지점 (개발)

### MONEY_WALLET_SOURCES

개인 지갑 자료형은 `insuniverse-server/apps/api/src/modules/money/money-wallet.entity.ts:7`, 사용 이력은 `insuniverse-server/apps/api/src/modules/money/money-source.entity.ts:49`, 기업 지갑은 `insuniverse-server/apps/api/src/modules/money/money-corp.entity.ts:7` 이다. 사용자 조회 입구의 결선 층은 `insuniverse-server/apps/api/src/modules/money/money.controller.ts:39` 다.

### MONEY_ISSUE_VOCAB

유형 어휘는 `insuniverse-server/apps/api/src/modules/money/money.dto.ts:36` 의 열거형이고, 지급과 부여가 각각 `insuniverse-server/apps/api/src/modules/money/money-issue.entity.ts:9` 과 `insuniverse-server/apps/api/src/modules/money/money-grant.entity.ts:7` 의 자료형을 갖는다.

### MONEY_ISSUE_ORG_RECHECK

입구의 결선 층은 `insuniverse-server/apps/api/src/modules/money/money-admin.controller.ts:71`, 지급 입구의 허용 역할은 `insuniverse-server/apps/api/src/modules/money/money-admin.controller.ts:86` 이 선언한다. 범위 재확인은 `insuniverse-server/apps/api/src/modules/money/money.service.ts:201` 이 인자로 받은 범위 식별자로 내린다. 층 자체의 정의는 `../02-access/03-authz-capabilities.md#ORG_WRITE_SCOPE` 가 진다.

### MONEY_CHARGE_CALLBACK

승인 통보 입구는 `insuniverse-server/apps/api/src/modules/money/money-public.controller.ts:12`, 충전 요청 자료형은 `insuniverse-server/apps/api/src/modules/money/money-charge-request.entity.ts:6` 이다.

### PAYMENT_STATE_AND_METHOD

상태 축은 `insuniverse-server/apps/api/src/modules/payment/payment.entity.ts:6`, 수단 축은 `insuniverse-server/apps/api/src/modules/payment/payment.entity.ts:12` 의 열거형이다. 거래 식별자로 되찾는 조회는 `insuniverse-server/apps/api/src/modules/payment/payment.repository.ts:12` 다. 결제 결과가 바깥에서 정해진다는 계약은 `../03-contracts/04-state-transitions.md#state:payment-outcome-decided-outside` 가 진다.

### PAYMENT_SUBSCRIPTION_BRANCH

정기 결제 처리기는 `insuniverse-server/apps/api/src/modules/payment/payment.service.ts:40`, 체험 결제는 `insuniverse-server/apps/api/src/modules/payment/payment.service.ts:90`, 취소는 `insuniverse-server/apps/api/src/modules/payment/payment.service.ts:118` 이며 취소 안에서 주체 종류로 다시 갈린다.

### CARD_PRIMARY_SELECTION

입구의 결선 층은 `insuniverse-server/apps/api/src/modules/card/card.controller.ts:22`, 대표 지정 입구는 `insuniverse-server/apps/api/src/modules/card/card.controller.ts:41` 이다.

### REFUND_OUTCOME_CODES

결과 코드값은 `insuniverse-server/apps/api/src/modules/refund/refund.entity.ts:10` 의 자료형 선언에 상수로 붙어 있고, 생성 처리기는 `insuniverse-server/apps/api/src/modules/refund/refund.service.ts:10` 이다.

### INVOICE_ASSEMBLY

서식 등록 입구의 허용 역할은 `insuniverse-server/apps/api/src/modules/invoice/invoice-admin.controller.ts:40`, 서식 가져오기는 `insuniverse-server/apps/api/src/modules/invoice/invoice-storage.service.ts:12`, 조립은 `insuniverse-server/apps/api/src/modules/invoice/invoice.builder.ts:33` 이 진다.

### INVOICE_OWNER_GUARD

사용자 쪽 청구서 조회 입구에 소유자 검증 층이 `insuniverse-server/apps/api/src/modules/invoice/invoice.controller.ts:41` 로 결선돼 있다. 그 행의 최종 변경 커밋이 릴리스 인덱스의 미도달 집합에 있다.

## 적용 범위 (actor × 서비스)

| 정책 id | server | site | admin |
|---|---|---|---|
| MONEY_WALLET_SOURCES | 세 자료형 · 조회 입구 결선 층 | 잔액·내역 화면 | 기업 지갑 요약 화면 |
| MONEY_ISSUE_VOCAB | 유형 어휘 · 지급·부여 자료형 | — | 지급 이력 화면 |
| MONEY_ISSUE_ORG_RECHECK | 결선 층 · 역할 선언 · 범위 재확인 | — | 기업 측 지급 화면 |
| MONEY_CHARGE_CALLBACK | 통보 입구 · 요청 자료형 | 충전 요청 화면 | — |
| PAYMENT_STATE_AND_METHOD | 두 축 어휘 · 거래 식별자 조회 | 결제 결과 화면 | 결제 목록의 상태·수단 열 |
| PAYMENT_SUBSCRIPTION_BRANCH | 세 처리기 · 취소 분기 | 결제 개시 | 취소 처리 |
| CARD_PRIMARY_SELECTION | 입구 결선 층 · 대표 지정 입구 | 카드 관리 화면 | — |
| REFUND_OUTCOME_CODES | 결과 코드값 · 생성 처리기 | 환불 결과 표시 | 환불 처리 화면 |
| INVOICE_ASSEMBLY | 등록 역할 선언 · 서식 가져오기 · 조립 | 청구서 내려받기 | 서식 등록 화면 |
| INVOICE_OWNER_GUARD | 소유자 검증 층 결선 | 이 층 뒤에서 청구서를 받는다 | — |

`—` = 그 서비스가 이 정책의 경로에 등장하지 않음.

이 표의 열은 서비스 3종이며 actor 는 열이 아니다. 이 문서의 축은 정산 자원에 걸리는 판정이라 actor 를 열로 두면 서버 한 칸만 차는 표가 된다. 열 이름 집합과 순서는 `../_meta/template-config.yaml` 의 `services` 를 그대로 따른다.

## 예외·폴백

| 정책 id | 예외 조건 | 폴백 동작 | 확인 근거 |
|---|---|---|---|
| MONEY_WALLET_SOURCES | 로그인하지 않고 잔액을 열려 할 때 | 결선 층에서 거부된다 | `insuniverse-server/apps/api/src/modules/money/money.controller.ts:39` |
| MONEY_ISSUE_VOCAB | 어휘 밖 유형으로 지급을 요청할 때 | 입력 검증에서 거부된다 | `insuniverse-server/apps/api/src/modules/money/money.dto.ts:36` |
| MONEY_ISSUE_ORG_RECHECK | 기업 측 주체가 자기 범위 밖 대상에게 지급할 때 | 역할 판정을 통과해도 범위 재확인에서 거부된다 | `insuniverse-server/apps/api/src/modules/money/money.service.ts:201` |
| MONEY_ISSUE_ORG_RECHECK | 주체가 관리자일 때 | 범위 식별자가 실리지 않아 재확인이 걸리지 않는다 | `insuniverse-server/apps/api/src/modules/money/money-admin.controller.ts:86` |
| MONEY_CHARGE_CALLBACK | 승인 통보가 오지 않을 때 | 충전 요청 자료만 남는다. 자동 회수는 이 경로에 없다 | `insuniverse-server/apps/api/src/modules/money/money-charge-request.entity.ts:6` |
| PAYMENT_STATE_AND_METHOD | 알 수 없는 거래 식별자로 조회할 때 | 결제 건을 찾지 못한 채로 떨어진다 | `insuniverse-server/apps/api/src/modules/payment/payment.repository.ts:12` |
| PAYMENT_SUBSCRIPTION_BRANCH | 체험 결제를 정기 처리기로 보낼 때 | 처리기가 다르므로 그 경로로 가지 않는다 | `insuniverse-server/apps/api/src/modules/payment/payment.service.ts:90` |
| PAYMENT_SUBSCRIPTION_BRANCH | 취소 대상의 주체 종류가 다를 때 | 취소 안에서 분기되어 다른 경로를 탄다 | `insuniverse-server/apps/api/src/modules/payment/payment.service.ts:118` |
| CARD_PRIMARY_SELECTION | 남의 카드 목록을 열려 할 때 | 결선 층 뒤에서 자기 것만 되돌린다 | `insuniverse-server/apps/api/src/modules/card/card.controller.ts:22` |
| REFUND_OUTCOME_CODES | 반려 사유를 비워 보낼 때 | 코드값은 고정이되 사유 문자열의 어휘는 강제되지 않는다 | `insuniverse-server/apps/api/src/modules/refund/refund.entity.ts:10` |
| INVOICE_ASSEMBLY | 보험사 서식이 저장소에 없을 때 | 가져오기 단계에서 실패한다. 대체 서식은 이 경로에 없다 | `insuniverse-server/apps/api/src/modules/invoice/invoice-storage.service.ts:12` |
| INVOICE_OWNER_GUARD | 이 규칙이 배포에 도달하지 않은 환경일 때 | 소유자 검증 없이 앞 층의 판정만 남는다 | `insuniverse-server/apps/api/src/modules/invoice/invoice.controller.ts:41` |

## 부록

이 절의 정책은 **앵커 행의 최종 변경 커밋이 릴리스 인덱스의 미도달 집합에 있어 현행 배포를 판정하지 못한다.** 배치의 정본은 `../_meta/template-config.yaml` 의 `statuses` 이며, 도달이 확인되면 상태가 바뀌고 배치도 함께 옮긴다.

### INVOICE_OWNER_GUARD

**사용자 쪽 청구서 조회에 소유자 검증 층이 붙어 있다.** 이 층이 도달한 환경에서는 남의 청구서를 식별자만 바꿔 열 수 없고, 도달하지 않은 환경에서는 그 앞 층의 판정만 남는다. 같은 커밋이 분석 조회에도 같은 층을 붙였고 그 자리는 `01-analysis.md#ANALYSIS_OWNER_GUARD` 가 진다.

## 연혁

릴리스 태그가 존재하지 않는다. 릴리스 열은 `—` 로 두고 커밋 SHA 로 추적한다.

| 릴리스 | 날짜 | SHA | 변경 요약 |
|---|---|---|---|
| — | 2024-10-04 | `f04cfa45` | 카드 입구 신설 |
| — | 2024-11-08 | `5fa8b27a` | 청구서 서식 조회 키가 보험사 코드로 정리됨 |
| — | 2024-11-20 | `0e3883f6` | 결제 상태 축 신설 |
| — | 2024-11-22 | `bc3d85b3` | 카드 대표 지정 입구 신설 |
| — | 2025-01-10 | `2ba77d9d` | 결제 수단 축이 별도 코드값으로 갈림 |
| — | 2025-03-25 | `fb1615bd` | 최초 구독 결제 처리기 신설 |
| — | 2025-04-24 | `15650549` | 결제 취소가 주체 종류로 분기됨 |
| — | 2025-06-24 | `780e6b64` | 청구서 서식 등록 입구에 역할 기반 판정 도입 |
| — | 2026-01-12 | `46efac63` | 머니 자료가 지갑·출처·사용 이력으로 분리되고 유형 어휘가 고정됨 |
| — | 2026-07-01 | `f0ce46c8` | 머니 관리자 입구에 조직 범위 층 결선 |
| — | 2026-07-02 | `a4ccfc48` | 머니 지급 처리에 조직 범위 재확인 추가 |
| — | 2026-07-28 | `47d90c30` | 사용자 쪽 청구서 조회에 소유자 검증 층 추가 |
