# P2P 수수료 구조 재설계 — Handoff

> **상태**: ✅ 재설계 확정 (2026-06-11) — 후속 문서: **`P2P_FEE_REDESIGN_GUIDE.md` v2.0** (구현 지침서, DDL v2.3 반영 완료)
> **결정 (최종)**: 구매자(입금측)만 부담 / **글로벌 단일률** 1~3% (시작 2%, 파트너별 오버라이드 없음 — partners.p2p_fee_rate 제거) / 분배: Admin 글로벌 설정 총판 n% + 매장 n%, 시스템 = 잔여 / 기존 정산 파이프라인 합류
> **이전 세션**: Task #53 이후 수수료 구조 재정리 요청 → "전체 재설계 필요" 선택
> **마지막 커밋**: `02c56c1` (P2P default activation + partner self-toggle)
> ⚠️ 이 문서는 AS-IS 분석 기록용. 구현은 GUIDE 문서를 따를 것.

---

## 1. 현재 P2P 수수료 구조 (AS-IS)

### 데이터 모델

| 위치 | 컬럼/필드 | 값 | 설명 |
|------|-----------|-----|------|
| `partners` 테이블 | `p2p_fee_rate` | DECIMAL(10,6) DEFAULT 0 | 파트너별 P2P 구매자 수수료율 |
| `p2p_deposit_orders` | `fee_rate` | DECIMAL(10,6) DEFAULT 0.020000 | 주문 생성 시 스냅샷 |
| `p2p_deposit_orders` | `fee_amount` | BIGINT DEFAULT 0 | 계산된 KRW 수수료 |

### 코드 흐름

```
1. P2pDepositService.createAndMatch()
   → partner.getP2pFeeRate() 읽기 (현재 전체 0)
   → feeAmount = krwAmount × feeRate (= 0)
   → P2pDepositOrder에 fee_rate, fee_amount 저장

2. P2pSettlementService.completeSettlement()
   → dpo.getFeeAmount() 읽기
   → p2pFeeUsdt = feeAmount / exchangeRate (USDT 환산)
   → settlementService.credit(B파트너, usdtAmount)  ← 전액 입금
   → settlementService.recordFee(B파트너, p2pFeeUsdt) ← 수수료 차감
   → 구매자 실수령 = CREDIT - FEE

3. 결과: FEE가 ledger_entries에 기록됨 (LedgerReferenceType.P2P_SETTLEMENT)
```

### 관련 파일

| 파일 | 역할 |
|------|------|
| `common/entity/Partner.java:97` | `private BigDecimal p2pFeeRate;` |
| `core/p2p/P2pDepositService.java:62-78` | 수수료 계산 + 주문 생성 |
| `core/p2p/P2pSettlementService.java:268-288` | USDT 환산 + FEE 원장 기록 |
| `admin-api/dto/request/PartnerFeeUpdateRequest.java` | Admin에서 p2pFeeRate 설정 |
| `partner-api/dto/p2p/P2pSettingsResponse.java` | 파트너 조회 시 p2pFeeRate 반환 |
| `v2-docs/CRYPTOMENTS_V2_DDL.sql:223` | DDL 정의 |

---

## 2. 문제점 (5가지)

### ❶ 수수료율 0% — 실질 무료
- `p2p_fee_rate`이 전체 37개 파트너 모두 0으로 설정됨
- DDL DEFAULT도 0 → 신규 파트너도 자동 0
- **수익 모델이 작동하지 않는 상태**

### ❷ 단일 수수료율 — 분배 구조 없음
- 현재: 구매자 → 단일 FEE → 끝
- 필요: 구매자 수수료를 플랫폼 마진 / 총판 쉐어 / 매장 쉐어로 분배
- DDL 주석에 "총판 쉐어는 기존 parent_fee_rate 트리 사용" 있지만 **코드 미구현**

### ❸ 일반 입금 정산과 분리
- 일반 입금: `deposit_fee_rate` → `settlement_balances`에 일별 집계 → `settlement_invoices`로 정산
- P2P: `p2p_fee_rate` → `ledger_entries`에 FEE 기록만 → 집계/정산 파이프라인 미연결
- `SettlementDailyAggregationJob`이 P2P FEE를 포함하는지 확인 필요

### ❹ 구매자(B측)만 수수료 부담
- 판매자(A측) 수수료 개념 없음
- A측 출금은 일반 출금 흐름을 타므로 별도 P2P 수수료 없음 (이게 의도적인지 확인 필요)

### ❺ 수수료율 설정 UX 부족
- Admin에서 파트너별 `p2pFeeRate` 설정 가능 (PartnerFeeUpdateRequest)
- 하지만 적정 값 가이드라인 없음, 글로벌 기본값 없음
- 파트너가 자체 조정 가능한지도 불명확 (현재 partner-api에 수정 EP 없음)

---

## 3. 기존 일반 입금 수수료 구조 (참고)

일반(비-P2P) 입금 수수료는 다단계 트리 구조:

```
[Cryptoments 시스템]
  └── DISTRIBUTOR A (parent_fee_rate = 0.5%)  → 0.5% 가져감
       └── MERCHANT B (deposit_fee_rate = 2%) → 실제 입금 수수료율
           min_fee_rate = 0.5% (상위 합)
           매장 수익 = 2% - 0.5% = 1.5%
```

- **핵심**: `deposit_fee_rate`이 최종 사용자 부담률, `parent_fee_rate`이 상위 가져가는 몫
- `min_fee_rate` = 상위 전체 합 (비정규화), `max_fee_cap` = 하위 설정 가능 최대
- 정산 시: `SettlementDailyAggregationJob` → 일별 집계 → `SettlementRealizationJob` → Invoice

---

## 4. 재설계에서 결정해야 할 사항

### A. 수수료 부담자
- 구매자(B측)만? 양측? 판매자(A측)만?
- Cryptoments는 중개 플랫폼이므로 양측 수수료가 일반적

### B. 수수료율 체계
- 고정률 (예: 2%) vs 파트너별 차등 vs 글로벌 기본 + 파트너 오버라이드?
- 건당 최소/최대 한도(cap)?

### C. 수익 분배 (가장 중요)
- P2P 수수료도 `parent_fee_rate` 트리를 탈 것인가?
- 예: 구매자 2% 중 → 시스템 0.5% + 총판 0.5% + 매장 1.0%?
- 아니면 P2P 전용 별도 분배 구조?

### D. 정산 파이프라인 연동
- 기존 `settlement_balances` → `settlement_invoices` 흐름에 합류?
- 아니면 P2P 전용 정산?

### E. 출금측(A측) 수수료
- A측 파트너는 출금 시 수수료를 내는가?
- 기존 출금 수수료(`withdrawal_fee_rate` — 현재 미정의)와 관계?
- A측 출금은 이미 일반 출금 흐름으로 처리 중 → P2P 전환 출금이라고 추가 수수료?

---

## 5. 이 세션에서 하지 못한 것

- 사용자에게 위 A~E 선택지를 질문하려 했으나 AskUserQuestion UI 이슈로 진행 못함
- **다음 세션에서**: 위 5가지 결정사항을 사용자와 합의 → DDL 변경 → 코드 수정 → 정산 연동

---

## 6. 빠른 참조

### 운영 DB 현재 상태
```sql
-- 전체 파트너 p2p_fee_rate 확인 (모두 0)
SELECT id, partner_code, name, p2p_fee_rate FROM partners;
```

### 관련 enum / 상수
- `LedgerReferenceType.P2P_SETTLEMENT` — P2P 정산 원장 참조
- `LedgerEntryType.CREDIT` / `FEE` — 입금 / 수수료

### 빌드 & 배포 (변경 후)
```bash
# 로컬 빌드 (Desktop Commander)
cd ~/git/cryptoments && ./gradlew :common:compileJava :core:compileJava :admin-api:compileJava :partner-api:compileJava :open-api:compileJava :scheduler:compileJava

# DDL 적용 (bastion 경유)
ssh cryptoments-bastion "ssh db-01 'mysql -u cryptoments -p\"Crypt0m3nts!2026\" cryptoments_db -e \"ALTER TABLE ...\"'"

# 배포
cd ~/git/cryptoments && git add . && git commit -m "..." && git push origin main
```
