# 하위 파트너 상세 화면 — UI 기능 추가 지침서

> **대상 화면**: 파트너 콘솔 → 하위 파트너 관리 → 상세 페이지
> **관련 API**: `partner-api` — `/api/partner/sub-partners/{partnerId}`
> **작성일**: 2026-04-05

## 현재 화면 구성

기존 상세 페이지는 **읽기 전용**:
- 파트너코드, 유형, 상태, 상위 파트너, 이메일, 등록일
- 수수료 정보 (수수료율)
- 거래 요약 (최근 30일 총 입금, 총 수수료, 총 출금, 하위 파트너 수)

## 추가할 기능 4가지

### 1. 수수료율 수정

**UI 위치**: 수수료 정보 섹션 우측에 "수정" 버튼

**동작**:
- "수정" 클릭 → 수수료율 필드가 인라인 인풋으로 전환 (또는 모달)
- 입력 제한: `minFeeRate ≤ 값 ≤ maxFeeCap`
  - minFeeRate, maxFeeCap은 `GET /{partnerId}/detail` 응답에 포함됨
- "저장" 클릭 → API 호출 → 성공 시 토스트 알림

**API**:
```
PATCH /api/partner/sub-partners/{partnerId}
Content-Type: application/json
Authorization: Bearer {token}

{
  "feeSettings": {
    "depositFeeRate": 0.5
  }
}
```

**Response**: `Partner` 엔티티 (수정된 전체 파트너 정보)

**유효성 검사 (프론트)**:
- 숫자만 허용 (소수점 포함)
- minFeeRate 이상, maxFeeCap 이하
- 빈 값 불가

**에러 처리**:
- `5001 FEE_RATE_OUT_OF_RANGE` → "수수료율이 허용 범위를 벗어났습니다 (최소: {minFeeRate}%, 최대: {maxFeeCap}%)"

---

### 2. 계정 상태 변경

**UI 위치**: 상태 뱃지 우측에 토글 또는 드롭다운

**동작**:
- 현재 상태가 `활성` → "정지" 버튼 표시 (빨간색)
- 현재 상태가 `정지` → "활성화" 버튼 표시 (초록색)
- 클릭 시:
  - 정지 → 확인 모달 (사유 입력 필드 포함, 선택사항)
  - 활성화 → 간단 확인 모달

**API**:
```
PATCH /api/partner/sub-partners/{partnerId}/status
Content-Type: application/json
Authorization: Bearer {token}

{
  "status": "SUSPENDED",
  "reason": "정산 미완료로 인한 일시 정지"
}
```

또는:
```json
{
  "status": "ACTIVE"
}
```

**Response**: `Partner` 엔티티

**상태 전이 규칙**:
- `ACTIVE` → `SUSPENDED` (사유 선택적)
- `SUSPENDED` → `ACTIVE`
- `PENDING`, `TERMINATED` → 변경 불가 (버튼 비활성화)

**에러 처리**:
- `409 Conflict` → "현재 상태에서는 변경할 수 없습니다"

---

### 3. 정보 수정

**UI 위치**: 기본 정보 섹션 우측에 "편집" 버튼

**동작**:
- "편집" 클릭 → 파트너명, 이메일 필드가 인풋으로 전환
- 파트너코드, 유형, 등록일은 **읽기 전용 유지**
- "저장" / "취소" 버튼 표시

**수정 가능 필드**:
| 필드 | 타입 | 검증 |
|------|------|------|
| partnerName | text | 필수, 2~50자 |
| loginEmail | email | 필수, 이메일 형식 |

**API**:
```
PATCH /api/partner/sub-partners/{partnerId}
Content-Type: application/json
Authorization: Bearer {token}

{
  "partnerName": "데모2 수정",
  "loginEmail": "new-email@cryptoments.cc"
}
```

**Response**: `Partner` 엔티티

**에러 처리**:
- `5003 EMAIL_ALREADY_EXISTS` → "이미 사용 중인 이메일입니다"

---

### 4. 계정 삭제

**UI 위치**: 페이지 하단 또는 상단 "더보기" 메뉴 안에 "파트너 삭제" (빨간색)

**동작**:
1. "파트너 삭제" 클릭
2. 확인 모달:
   - 경고 문구: "이 파트너를 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다."
   - 파트너명 표시
   - "삭제" 버튼 (빨간색), "취소" 버튼
3. 2FA 활성화된 경우 → OTP 입력 필드 추가 (X-OTP-Code 헤더)
4. 성공 시 → 목록 페이지로 리다이렉트 + 토스트 "파트너가 삭제되었습니다"

**API**:
```
DELETE /api/partner/sub-partners/{partnerId}
Authorization: Bearer {token}
X-OTP-Code: 123456  (2FA 활성화 시)
```

**Response**: `200 OK` (본문 없음)

**삭제 불가 조건** (백엔드에서 검증, 프론트에서도 안내):
- 하위 파트너가 있는 경우 → `409 CANNOT_DELETE "하위 파트너가 있는 파트너는 삭제할 수 없습니다"`
- 거래 이력이 있는 경우 → `409 CANNOT_DELETE "거래 이력이 있는 파트너는 삭제할 수 없습니다"`

**UI 힌트**: 거래 요약에서 입금/출금이 0이 아니면 삭제 버튼을 비활성화하거나 툴팁으로 안내

---

## 화면 레이아웃 가이드

```
┌──────────────────────────────────────────────────────┐
│  ← 목록으로                          [더보기 ▾]       │
│                                      ├ 비밀번호 초기화 │
│  파트너명 (데모2)                     ├ 파트너 삭제     │
│                                      └───────────────  │
├──────────────────────────────────────────────────────┤
│  기본 정보                                [편집]      │
│  ┌─────────────────────────────────────────────────┐ │
│  │ 파트너코드   P157484       유형        가맹점    │ │
│  │ 상태     [활성] [정지 버튼]  상위 파트너   test   │ │
│  │ 이메일   demo2@...         등록일    2026-04-05  │ │
│  └─────────────────────────────────────────────────┘ │
├──────────────────────────────────────────────────────┤
│  수수료 정보                                [수정]    │
│  ┌─────────────────────────────────────────────────┐ │
│  │ 수수료율        0.3%                             │ │
│  │ (허용범위: 0.15% ~ 5.0%)                         │ │
│  └─────────────────────────────────────────────────┘ │
├──────────────────────────────────────────────────────┤
│  거래 요약 (최근 30일)                                │
│  ┌─────────────────────────────────────────────────┐ │
│  │ 총 입금    총 수수료    총 출금    하위 파트너    │ │
│  │ 0 USD     0 USD       0 USD     0개             │ │
│  └─────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────┘
```

## API 응답 참조 (GET /{partnerId}/detail)

```json
{
  "id": 123,
  "partnerCode": "P157484",
  "name": "데모2",
  "partnerType": "MERCHANT",
  "status": "ACTIVE",
  "parentPartnerId": 1,
  "parentPartnerName": "test",
  "depositFeeRate": 0.3,
  "parentFeeRate": 0.15,
  "minFeeRate": 0.15,
  "maxFeeCap": 5.0,
  "loginEmail": "demo2@cryptoments.cc",
  "createdAt": "2026-04-05 09:22:38",
  "totalDepositUsd": 0,
  "totalFeeUsd": 0,
  "totalWithdrawalUsd": 0,
  "subPartnerCount": 0
}
```

수수료 수정 시 프론트에서 `minFeeRate`와 `maxFeeCap`을 사용해 입력 범위 제한.

## 주의사항

1. **PATCH 요청은 부분 업데이트** — null 필드는 서버에서 무시함. 변경할 필드만 전송
2. **2FA(OTP)** — 삭제 시에만 필요. 수정/상태변경에는 불필요
3. **상태가 TERMINATED인 파트너** — 모든 수정 버튼 비활성화
4. **수수료 범위** — detail API 응답의 `minFeeRate`, `maxFeeCap` 사용
5. **이메일 변경** — 중복 검사는 서버에서 처리하므로 프론트는 형식 검증만
