# Cryptoments Admin Console — v2 API 설계

> **버전**: v1.2
> **작성일**: 2026-03-17
> **기반**: 화면설계서 v2.0 + 상세 기능 정의서 v1.1 + HANDOFF 변경사항 통합
> **총 API**: 121개 (인증 3 + 대시보드 4 + 파트너 21 + 거래 18 + CS 4 + 인프라 37 + 정산 6 + 가스비/원장 12 + 시스템 7 + 관리자 8 + 유지보수 2)
> **범위**: 1차(파트너/거래/CS) + 2차(대시보드/인프라) 화면별 상세 스펙 포함 + 컨트랙트 관리 추가

---

## Part 1: 화면별 API 매핑

### SCR-1000 — 대시보드

| # | Method | Endpoint | 용도 |
|---|--------|----------|------|
| 1 | GET | `/api/admin/dashboard/summary` | 요약 카드 (오늘 입금/출금, 미식별, 알림) |
| 2 | GET | `/api/admin/dashboard/alerts` | 이상 알림 목록 |
| 3 | GET | `/api/admin/dashboard/unidentified` | 미식별 입금 목록 (최근 N건) |
| 4 | GET | `/api/admin/dashboard/settlement` | 정산 현황 요약 |

**`GET /summary` Response** (`DashboardSummaryResponse` — flat 구조):
```json
{
  "todayDepositCount": 523,
  "todayDepositAmount": "12450.000000",
  "todayWithdrawalCount": 87,
  "todayWithdrawalAmount": "5200.000000",
  "pendingApprovalCount": 5,
  "unidentifiedCount": 3,
  "alertCount": 2
}
```
- 소스: deposits(TODAY, status IN CONFIRMED/COLLECTING/SETTLED), withdrawals(TODAY, CONFIRMED), PENDING_APPROVAL 상태 출금, UNIDENTIFIED 타입 미처리 입금

**`GET /alerts` Response** (`List<AlertResponse>`):
```json
[
  {
    "alertType": "FEE_LOW",
    "severity": "WARNING",
    "message": "BSC GAS 지갑 잔액 부족 (0.002 BNB)",
    "entityType": "WALLET",
    "entityId": 12,
    "detectedAt": "2026-03-03 09:30:00"
  }
]
```
- alertType: `GAS_LOW`, `NONCE_STUCK`, `RELAYER_DOWN`, `WEBHOOK_FAIL`
- severity: `WARNING`, `CRITICAL`

**`GET /unidentified` Response**: `XPage<UnidentifiedDepositResponse>` (CS 도구와 동일 구조)

**`GET /settlement` Response** (`SettlementSummaryResponse`):
```json
{
  "totalUnrealizedUsd": "1234.560000",
  "totalRealizedUsd": "45678.900000",
  "currentMonthFeeCount": 320,
  "currentMonthFeeAmount": "987.650000",
  "pendingRealizationCount": 8
}
```

---

### SCR-2100 — 파트너 목록

| # | Method | Endpoint | 용도 |
|---|--------|----------|------|
| 1 | GET | `/api/admin/partners` | 파트너 목록 (페이지네이션, 필터) |
| 2 | POST | `/api/admin/partners` | 파트너 등록 |
| 3 | PATCH | `/api/admin/partners/:id/status` | 행별 상태 변경 (ACTIVE↔SUSPENDED) |

**검색 파라미터** (`GET /api/admin/partners`):
```
?page=1&size=20&sort=createdAt,DESC
&partnerCode=P001          # LIKE
&name=검색어               # LIKE
&partnerType=DISTRIBUTOR   # enum
&status=ACTIVE,SUSPENDED   # multi-select
&email=test@               # contact_email OR login_email LIKE
&parentPartnerId=1         # exact
&fromDate=2026-01-01       # created_at >=
&toDate=2026-03-03         # created_at <=
```

**Response**: `XPage<PartnerListResponse>`
- id, partnerCode, name, partnerType, status, parentPartnerName, depositFeeRate, parentFeeRate, apiKey(마스킹), contactEmail, createdAt

---

### SCR-2110 — 파트너 등록

| # | Method | Endpoint | 용도 |
|---|--------|----------|------|
| 1 | POST | `/api/admin/partners` | 파트너 등록 |
| 2 | GET | `/api/admin/partners` | 상위 파트너 Autocomplete용 (q 파라미터) |

**Request** (`POST /api/admin/partners`):
```json
{
  "name": "D매장",
  "businessName": "D컴퍼니",
  "partnerType": "MERCHANT",
  "parentPartnerId": 2,
  "contactEmail": "d@example.com",
  "contactPhone": "010-1234-5678",
  "loginEmail": "d-admin@example.com",
  "password": "초기비밀번호",
  "parentFeeRate": "0.003000",
  "maxFeeCap": "0.020000",
  "depositFeeRate": "0.010000",
  "withdrawalFeeFixed": "1.000000",
  "webhookUrl": "https://example.com/webhook",
  "timezone": "Asia/Seoul",
  "locale": "ko"
}
```
- `partnerCode`: 서버 자동 생성 (P + 6자리)
- `apiKey`, `apiSecretHash`: 서버 자동 생성
- `status`: ACTIVE 기본
- `minFeeRate`: 서버 자동 계산 (부모 min_fee_rate + parent_fee_rate)

**수수료 검증 로직**: 2003(fee < min), 2004(fee > cap), 2005(cap > parent cap), 2001(code 중복), 2002(email 중복)

---

### SCR-2200 — 파트너 상세 (6탭)

#### Tab1: 기본 정보

| # | Method | Endpoint | 용도 |
|---|--------|----------|------|
| 1 | GET | `/api/admin/partners/:id` | 파트너 상세 조회 |
| 2 | PUT | `/api/admin/partners/:id` | 기본 정보 수정 |
| 3 | PATCH | `/api/admin/partners/:id/status` | 상태 변경 (ACTIVE↔SUSPENDED↔TERMINATED) |
| 4 | POST | `/api/admin/partners/:id/api-key/regenerate` | API Key 재발급 |
| 5 | POST | `/api/admin/partners/:id/2fa/reset` | 2FA 리셋 |
| 6 | PUT | `/api/admin/partners/:id/fees` | 수수료 수정 (cascade) |

**`GET /api/admin/partners/:id` Response** (`PartnerDetailResponse`):
- 기본: id, partnerCode, name, businessName, partnerType, parentPartnerId, parentPartnerName, status
- 연락처: contactEmail, contactPhone
- 계정: loginEmail, lastLoginAt, lastLoginIp, twoFactorEnabled
- 수수료: parentFeeRate, minFeeRate, maxFeeCap, depositFeeRate, withdrawalFeeFixed
- 연동: apiKey(마스킹), webhookUrl, timezone, locale
- 메타: activatedAt, suspendedAt, suspendReason, createdAt, updatedAt

**`PUT /api/admin/partners/:id` Request** (기본 정보 수정):
```json
{
  "name": "D매장 (수정)",
  "businessName": "D컴퍼니",
  "contactEmail": "new@example.com",
  "contactPhone": "010-9999-8888",
  "webhookUrl": "https://new.example.com/webhook",
  "timezone": "Asia/Seoul",
  "locale": "ko"
}
```

**`PUT /api/admin/partners/:id/fees` Request** (수수료 수정):
```json
{
  "parentFeeRate": "0.005000",
  "maxFeeCap": "0.020000",
  "depositFeeRate": "0.012000",
  "withdrawalFeeFixed": "1.500000"
}
```
- cascade: parentFeeRate 변경 시 하위 트리 minFeeRate 일괄 업데이트

**`PATCH /api/admin/partners/:id/status` Request**:
```json
{
  "status": "SUSPENDED",
  "reason": "정지 사유"
}
```
- 상태 전환: PENDING→ACTIVE, ACTIVE↔SUSPENDED, ACTIVE/SUSPENDED→TERMINATED
- 불가능한 전환 시 에러 2006

#### Tab2: 체인/통화 설정

| # | Method | Endpoint | 용도 |
|---|--------|----------|------|
| 1 | GET | `/api/admin/partners/:id/chain-configs` | 체인 설정 조회 |
| 2 | PUT | `/api/admin/partners/:id/chain-configs` | 체인 설정 일괄 저장 |

**`GET` Response**: `List<PartnerChainConfigResponse>`
```json
[
  {
    "id": 1,
    "networkId": 1, "networkCode": "ETH", "networkName": "Ethereum",
    "currencyId": 1, "currencyCode": "USDT",
    "depositMethod": "HD_WALLET",
    "createdAt": "2026-01-15 09:00:00"
  }
]
```

**`PUT` Request**: `List<PartnerChainConfigUpdateRequest>` (전체 교체)
```json
[
  { "networkId": 1, "currencyId": 1, "depositMethod": "HD_WALLET" },
  { "networkId": 2, "currencyId": 1, "depositMethod": "HD_WALLET" }
]
```

#### Tab3: 출금 정책

| # | Method | Endpoint | 용도 |
|---|--------|----------|------|
| 1 | GET | `/api/admin/partners/:id/withdrawal-policy` | 출금 정책 조회 |
| 2 | PUT | `/api/admin/partners/:id/withdrawal-policy` | 출금 정책 수정 |
| 3 | GET | `/api/admin/partners/:id/whitelist` | 주소 화이트리스트 조회 |
| 4 | POST | `/api/admin/partners/:id/whitelist` | 화이트리스트 추가 |
| 5 | DELETE | `/api/admin/partners/:id/whitelist/:wid` | 화이트리스트 삭제 |

**`PUT /withdrawal-policy` Request**:
```json
{
  "autoApproveThreshold": "1000.000000",
  "dailyLimit": "50000.000000",
  "singleLimit": "10000.000000",
  "addressWhitelistEnabled": true
}
```

**`POST /whitelist` Request**:
```json
{
  "networkId": 1,
  "address": "0x...",
  "label": "메인 출금 주소"
}
```

#### Tab4: 연동 설정

| # | Method | Endpoint | 용도 |
|---|--------|----------|------|
| 1 | GET | `/api/admin/partners/:id/axim` | Axim 설정 조회 |
| 2 | PUT | `/api/admin/partners/:id/axim` | Axim 설정 수정 |
| 3 | GET | `/api/admin/partners/:id/telegram` | Telegram 설정 조회 |
| 4 | PUT | `/api/admin/partners/:id/telegram` | Telegram 설정 수정 |
| 5 | PUT | `/api/admin/partners/:id/telegram/subscriptions` | 구독 이벤트 수정 |
| 6 | GET | `/api/admin/partners/:id/webhook-logs` | 최근 Webhook 전달 로그 |

**`PUT /telegram` Request**:
```json
{
  "chatId": "123456789",
  "threadId": "1",
  "botTokenRef": "bot-token-ref",
  "isActive": true
}
```

**`PUT /telegram/subscriptions` Request**:
```json
{
  "subscriptions": [
    { "eventType": "DEPOSIT_CONFIRMED", "isEnabled": true },
    { "eventType": "WITHDRAWAL_CONFIRMED", "isEnabled": true },
    { "eventType": "WITHDRAWAL_REQUESTED", "isEnabled": false },
    { "eventType": "COLLECTION_COMPLETED", "isEnabled": false },
    { "eventType": "BALANCE_LOW", "isEnabled": true }
  ]
}
```

#### Tab5: 하위 파트너

| # | Method | Endpoint | 용도 |
|---|--------|----------|------|
| 1 | GET | `/api/admin/partners` | `?parentPartnerId=:id` 필터로 하위 파트너 목록 |

(파트너 목록 API 재활용, `parentPartnerId` 필터 적용)

#### Tab6: 활동 로그

| # | Method | Endpoint | 용도 |
|---|--------|----------|------|
| 1 | GET | `/api/admin/audit-logs` | `?targetType=PARTNER&targetId=:id` 필터 |

(감사 로그 API 재활용)

---

### SCR-3100 — 입금 목록

| # | Method | Endpoint | 용도 |
|---|--------|----------|------|
| 1 | GET | `/api/admin/deposits` | 입금 목록 (페이지네이션, 필터) |

**검색 파라미터**:
```
?page=1&size=20&sort=createdAt,DESC
&depositCode=dep_2602_a     # 완전 일치
&partnerId=3                # exact
&partnerUserId=user001      # LIKE
&txHash=0xabc               # 완전 일치
&networkId=1                # exact
&currencyId=1               # exact
&depositType=USER_DEPOSIT   # enum
&depositMethod=HD_WALLET    # enum
&status=CONFIRMED,SETTLED   # multi-select
&minAmount=100              # amount >=
&maxAmount=1000             # amount <=
&fromDate=2026-03-01        # created_at >=
&toDate=2026-03-03          # created_at <=
```

**Response**: `XPage<DepositListResponse>`
- id, depositCode, partnerName, partnerUserId, networkSymbol, currencyCode, amount, feeAmount, netAmount, depositType, depositMethod, txHash, status, confirmedAt, createdAt

**상단 요약 카드** (별도 API 또는 목록 API에 포함):
→ `GET /api/admin/deposits/summary?fromDate=&toDate=` 로 분리 추천
- todayCount, todayAmount, pendingCount, pendingAmount, confirmedCount, confirmedAmount, unidentifiedCount, unidentifiedAmount

---

### SCR-3110 — 입금 상세

| # | Method | Endpoint | 용도 |
|---|--------|----------|------|
| 1 | GET | `/api/admin/deposits/:id` | 입금 상세 (세션/집금/상태이력 포함) |
| 2 | GET | `/api/admin/deposits/:id/history` | 상태 변경 이력 (별도 호출) |

**`GET /api/admin/deposits/:id` Response** (`DepositDetailResponse`):
- 섹션A: depositCode, status, depositType, depositMethod, partnerId, partnerName, partnerUserId, networkId, networkName, currencyId, currencyCode
- 섹션B: amount, feeAmount, netAmount, priceKrw, priceUsd
- 섹션C: txHash, fromAddress, toAddress, blockNumber, confirmedAt, settledAt
- 섹션D (관련 데이터):
  - depositSession: sessionCode, requestedAmount, receivedAmount, amountMatchStatus, expiresAt (nullable)
  - collection: collectionCode, status, collectionTxHash (nullable)

**`GET /api/admin/deposits/:id/history` Response**: `List<TransactionStatusHistoryResponse>`
- fromStatus, toStatus, changedBy, changeSource, note, createdAt

---

### SCR-3120 — 입금 세션 목록

| # | Method | Endpoint | 용도 |
|---|--------|----------|------|
| 1 | GET | `/api/admin/deposit-sessions` | 세션 목록 (페이지네이션, 필터) |

**검색 파라미터**:
```
?page=1&size=20&sort=createdAt,DESC
&sessionCode=ses_xxx       # 완전 일치
&partnerId=3               # exact
&status=WAITING,RECEIVED   # multi-select
&depositMethod=HD_WALLET   # enum
&fromDate=2026-03-01
&toDate=2026-03-03
```

**Response**: `XPage<DepositSessionListResponse>`
- sessionCode, partnerName, partnerUserId, requestSource, depositMethod, requestedAmount, depositAddress(축약), receivedAmount, amountMatchStatus, status, expiresAt, createdAt

---

### SCR-3130 — 집금 현황

| # | Method | Endpoint | 용도 |
|---|--------|----------|------|
| 1 | GET | `/api/admin/collections` | 집금 목록 (페이지네이션, 필터) |
| 2 | GET | `/api/admin/collections/:id` | 집금 상세 |
| 3 | POST | `/api/admin/collections/:id/retry` | 집금 재시도 (FAILED 상태) |
| 4 | POST | `/api/admin/collections/:id/cancel` | 집금 취소 (QUEUED 상태) |

**검색 파라미터** (`GET /api/admin/collections`):
```
?page=1&size=20&sort=createdAt,DESC
&collectionCode=col_xxx     # 완전 일치
&partnerId=3                # exact
&networkId=1                # exact
&status=QUEUED,COLLECTING,CONFIRMED   # multi-select
&collectionMode=IMMEDIATE   # enum
&fromDate=2026-03-01
&toDate=2026-03-03
```

**Response**: `XPage<CollectionListResponse>`
- collectionCode, partnerName, networkSymbol, currencyCode, amount, collectionMode, status (QUEUED/COLLECTING/BROADCASTING/CONFIRMED/FAILED), collectionTxHash, scheduledAt, createdAt

---

### SCR-3140 — 결제 링크 목록

| # | Method | Endpoint | 용도 |
|---|--------|----------|------|
| 1 | GET | `/api/admin/payment-links` | 결제 링크 목록 |

**검색 파라미터**:
```
?page=1&size=20&sort=createdAt,DESC
&linkCode=lnk_xxx          # 완전 일치
&partnerId=3               # exact
&status=ACTIVE             # enum
&fromDate=2026-03-01
&toDate=2026-03-03
```

**Response**: `XPage<PaymentLinkListResponse>`
- linkCode, partnerName, currencyCode, networkSymbol, amount, title, status, expiresAt, createdAt

---

### SCR-3200 — 출금 목록

| # | Method | Endpoint | 용도 |
|---|--------|----------|------|
| 1 | GET | `/api/admin/withdrawals` | 출금 목록 (페이지네이션, 필터) |

**검색 파라미터**:
```
?page=1&size=20&sort=createdAt,DESC
&withdrawalCode=wdr_xxx     # 완전 일치
&partnerId=3                # exact
&partnerUserId=user001      # LIKE
&txHash=0xabc               # 완전 일치
&toAddress=0x123            # LIKE
&networkId=1                # exact
&currencyId=1               # exact
&withdrawalType=USER_PAYOUT # enum
&requestSource=API          # enum
&status=REQUESTED,APPROVED  # multi-select
&minAmount=100
&maxAmount=1000
&fromDate=2026-03-01
&toDate=2026-03-03
```

**Response**: `XPage<WithdrawalListResponse>`
- id, withdrawalCode, partnerName, partnerUserId, networkSymbol, currencyCode, amount, toAddress(축약), withdrawalType, requestSource, txHash, status, confirmedAt, createdAt

**상단 요약 카드** (별도 API):
→ `GET /api/admin/withdrawals/summary?fromDate=&toDate=`
- pendingApprovalCount/Amount, processingCount/Amount, todayConfirmedCount/Amount, failedCount/Amount

---

### SCR-3210 — 출금 상세

| # | Method | Endpoint | 용도 |
|---|--------|----------|------|
| 1 | GET | `/api/admin/withdrawals/:id` | 출금 상세 |
| 2 | GET | `/api/admin/withdrawals/:id/history` | 상태 변경 이력 |
| 3 | POST | `/api/admin/withdrawals/:id/approve` | 승인 |
| 4 | POST | `/api/admin/withdrawals/:id/reject` | 거부 |
| 5 | POST | `/api/admin/withdrawals/:id/retry` | 재시도 (FAILED) |

**`GET /api/admin/withdrawals/:id` Response** (`WithdrawalDetailResponse`):
- 섹션A: withdrawalCode, status, withdrawalType, requestSource, requestedBy, partnerId, partnerName, partnerUserId, networkName, currencyCode, toAddress
- 섹션B: amount, priceKrw, priceUsd
- 섹션C: txHash, blockNumber, confirmedAt
- 섹션D: partnerReference, refCode, partnerMetadata

**`POST /reject` Request**:
```json
{ "reason": "수신 주소 미확인" }
```

---

### SCR-3300 — 출금 승인

| # | Method | Endpoint | 용도 |
|---|--------|----------|------|
| 1 | GET | `/api/admin/withdrawals/pending-approval` | 승인 대기 목록 |
| 2 | POST | `/api/admin/withdrawals/:id/approve` | 단건 승인 |
| 3 | POST | `/api/admin/withdrawals/:id/reject` | 단건 거부 |
| 4 | POST | `/api/admin/withdrawals/batch-approve` | 일괄 승인 |
| 5 | POST | `/api/admin/withdrawals/batch-reject` | 일괄 거부 |

**`GET /pending-approval` Response**: `XPage<WithdrawalApprovalResponse>`
- (출금 목록 컬럼 + autoApproveEligible, whitelistVerified 추가)

**`POST /batch-approve` Request**:
```json
{ "withdrawalIds": [5, 6, 7] }
```

**`POST /batch-reject` Request**:
```json
{
  "withdrawalIds": [8, 9],
  "reason": "일괄 거부 사유"
}
```

**승인 검증**: 3001(일일 한도), 3002(건당 한도), 3003(화이트리스트), 3005(이미 처리됨)

---

### SCR-4100 — 미식별 입금 매칭/환불

| # | Method | Endpoint | 용도 |
|---|--------|----------|------|
| 1 | GET | `/api/admin/cs/unidentified` | 미식별 입금 목록 |
| 2 | POST | `/api/admin/cs/unidentified/:id/match` | 파트너/유저 매칭 |
| 3 | POST | `/api/admin/cs/unidentified/:id/refund` | 환불 처리 |

**검색 파라미터** (`GET /cs/unidentified`):
```
?page=1&size=20&sort=createdAt,DESC
&txHash=0xabc              # 완전 일치
&fromAddress=0x            # LIKE
&toAddress=0x              # LIKE
&networkId=1               # exact
&minAmount=10
&maxAmount=1000
&processed=false           # 미처리/매칭완료/환불완료
&fromDate=2026-03-01
&toDate=2026-03-03
```

**`POST /match` Request**:
```json
{
  "partnerId": 3,
  "partnerUserId": "user_001"
}
```
- 에러 4001: 이미 매칭

**`POST /refund` Request**:
```json
{
  "toAddress": "0xabc...",
  "networkId": 1
}
```
- 에러 4002: 환불 불가 상태

---

### SCR-4200 — TX Hash 글로벌 검색

| # | Method | Endpoint | 용도 |
|---|--------|----------|------|
| 1 | GET | `/api/admin/cs/tx-search?q={txHash}` | TX Hash 크로스 검색 |

**Response** (`TxSearchResponse`):
```json
{
  "deposits": [{ "id": 1, "depositCode": "dep_2602_a", "amount": "100", "status": "SETTLED", "partnerName": "C매장" }],
  "withdrawals": [],
  "collections": [{ "id": 1, "collectionCode": "col_2602_a", "amount": "100", "status": "CONFIRMED" }],
  "gasCosts": [{ "id": 1, "txType": "COLLECTION", "feeNative": "0.002", "feeUsd": "3.50" }],
  "ledgerEntries": []
}
```

검색 대상: deposits.tx_hash, withdrawals.tx_hash, collection_queue.collection_tx_hash, gas_cost_records.tx_hash, ledger_entries.tx_hash

---

### SCR-5100 — 네트워크 관리

| # | Method | Endpoint | 용도 |
|---|--------|----------|------|
| 1 | GET | `/api/admin/networks` | 네트워크 목록 (페이지네이션) |
| 2 | POST | `/api/admin/networks` | 네트워크 추가 |
| 3 | PUT | `/api/admin/networks/:id` | 네트워크 수정 |

**Response**: `XPage<BlockchainNetwork>` (Entity 직접 반환)

**`POST /networks` Request**:
```json
{
  "code": "BSC",
  "name": "BNB Smart Chain",
  "chainId": 56,
  "nativeCurrency": "BNB",
  "explorerUrl": "https://bscscan.com",
  "explorerTxFormat": "https://bscscan.com/tx/{txHash}",
  "explorerAddressFormat": "https://bscscan.com/address/{address}",
  "displayOrder": 3
}
```
- 에러: 코드 중복 시 409

**`PUT /networks/:id` Request**: POST와 동일 구조 (code 제외 수정 가능)

---

### SCR-5200 — 통화 관리

| # | Method | Endpoint | 용도 |
|---|--------|----------|------|
| 1 | GET | `/api/admin/currencies` | 통화 목록 |
| 2 | POST | `/api/admin/currencies` | 통화 추가 |
| 3 | PUT | `/api/admin/currencies/:id` | 통화 수정 |
| 4 | GET | `/api/admin/currencies/:id/networks` | 통화-네트워크 매핑 조회 |
| 5 | POST | `/api/admin/currencies/:id/networks` | 매핑 추가 |
| 6 | PUT | `/api/admin/currency-networks/:id` | 매핑 수정 |

**Response**: `XPage<Currency>` (Entity 직접 반환)

**`POST /currencies` Request**:
```json
{
  "code": "USDT",
  "name": "Tether USD",
  "currencyType": "STABLE",
  "decimals": 6,
  "iconUrl": "https://cdn.example.com/usdt.png",
  "displayOrder": 1
}
```
- currencyType: `STABLE`, `CRYPTO`

**`POST /currencies/:id/networks` Request** (매핑 추가):
```json
{
  "networkId": 2,
  "contractAddress": "0x55d398326f99059fF775485246999027B3197955",
  "minDepositAmount": "1.000000",
  "maxDepositAmount": "100000.000000"
}
```

**`GET /currencies/:id/networks` Response**: `List<CurrencyNetwork>` (Entity 직접 반환)

---

### SCR-5300 — 지갑 관리 (3탭)

#### Tab1: 전체 지갑 목록

| # | Method | Endpoint | 용도 |
|---|--------|----------|------|
| 1 | GET | `/api/admin/wallets` | 전체 지갑 목록 (검색 + 페이지네이션) |
| 2 | GET | `/api/admin/wallets/:id` | 지갑 상세 |
| 3 | GET | `/api/admin/wallets/:id/balances` | 지갑 잔액 목록 |
| 4 | POST | `/api/admin/wallets/sync-balances` | 잔액 일괄 동기화 |

**검색 파라미터** (`GET /wallets`):
```
?page=1&size=20&sort=id,DESC
&keyword=0xabc     # 주소 LIKE 검색
&networkId=1       # exact
&status=ACTIVE     # WalletAddressStatus enum
```

**`GET /wallets/:id` Response** (`WalletDetailResponse`):
- Layer 1 (주소): id, address, networkId, networkCode, networkName, hdWalletId, derivationIndex, derivationPath, status
- 할당 정보: assignment.walletType, assignment.partnerId, assignment.partnerName, assignment.partnerUserId
- 통화별 잔액: balances[{ currencyId, currencyCode, balance }]
- Approve 상태: approvals[{ currencyId, spenderAddress, approvedAmount, approveStatus }]
- 논스 추적: nonceTracker.nextNonce, nonceTracker.lastConfirmedNonce, nonceTracker.status

#### Tab2: HD Wallet

| # | Method | Endpoint | 용도 |
|---|--------|----------|------|
| 1 | GET | `/api/admin/hd-wallets` | HD Wallet 목록 |
| 2 | GET | `/api/admin/hd-wallets/:id` | HD Wallet 상세 |

**`GET /hd-wallets` Response**: `XPage<HdWalletDetailResponse>`
- id, networkId, networkCode, networkName, derivationBasePath, currentIndex, addressCount, createdAt, updatedAt

#### Tab3: 인덱스 관리

| # | Method | Endpoint | 용도 |
|---|--------|----------|------|
| 1 | GET | `/api/admin/wallet-index` | 인덱스 관리 목록 |

**`GET /wallet-index` Response**: `XPage<WalletIndexResponse>`
- id, networkId, networkCode, walletType, partnerId, partnerName, currentIndex, maxIndex

---

### SCR-5400 — 인프라 지갑 (ADMIN/GAS/SETTLEMENT)

| # | Method | Endpoint | 용도 |
|---|--------|----------|------|
| 1 | GET | `/api/admin/infra-wallets` | 인프라 지갑 목록 (ADMIN/GAS/SETTLEMENT/RELAYER) |
| 2 | POST | `/api/admin/infra-wallets/admin` | ADMIN 지갑 생성 (네트워크당 1개) |
| 3 | POST | `/api/admin/infra-wallets/gas` | GAS 지갑 생성 |
| 4 | POST | `/api/admin/infra-wallets/settlement` | SETTLEMENT 지갑 생성 |

**검색 파라미터** (`GET /infra-wallets`):
```
?page=1&size=20&sort=id,DESC
&walletType=GAS         # WalletType enum (선택)
&networkId=1            # exact (선택)
```

**`GET /infra-wallets` Response**: `XPage<InfraWalletResponse>`
- id, address, networkId, networkCode, networkName, walletType, balance, status, createdAt

**`POST /infra-wallets/admin` Request**:
```json
{ "networkId": 1, "hdWalletId": 5 }
```
- 네트워크당 1개만 허용 (이미 존재하면 기존 지갑 정보 반환)
- 응답: 200 OK + AdminWalletResponse (신규 생성 또는 기존 반환)

**`POST /infra-wallets/fee|settlement` Request**:
```json
{ "networkId": 1 }
```
- 실제 지갑 생성은 백엔드 비동기 처리 (TODO: 지갑 생성 서비스 연동)
- 응답: 204 No Content

---

### SCR-5500 — Relayer 관리

| # | Method | Endpoint | 용도 |
|---|--------|----------|------|
| 1 | GET | `/api/admin/relayer-wallets` | Relayer 목록 (DB 기준) |
| 2 | POST | `/api/admin/relayer-wallets` | Relayer 등록 (온체인 TX 포함) |
| 3 | PATCH | `/api/admin/relayer-wallets/:id/status` | 상태 변경 (ACTIVE/PAUSED) |
| 4 | GET | `/api/admin/relayer-wallets/:id` | Relayer 상세 조회 |
| 5 | POST | `/api/admin/relayer-wallets/:id/deactivate` | Relayer 해제 (온체인 TX 포함) |
| 6 | GET | `/api/admin/relayer-wallets/live` | 실시간 목록 (폴러 상태 포함) |
| 7 | GET | `/api/admin/relayer-wallets/health` | 헬스 집계 (상태별/네트워크별) |

**검색 파라미터** (`GET /relayer-wallets`):
```
?page=1&size=20&sort=id,DESC
&networkId=1               # exact (선택)
&registrationStatus=REGISTERED  # RegistrationStatus enum: PENDING, REGISTERING, REGISTERED, DEREGISTERING, REVOKED (선택)
&status=ACTIVE             # RelayerWalletStatus enum: ACTIVE, PAUSED (선택)
```

**`GET /relayer-wallets` Response**: `XPage<RelayerDetailResponse>`
- id, networkId, networkCode, walletAddressId, walletAddress, relayerRole (COLLECTION/WITHDRAWAL), registrationTxHash, registrationStatus, status (ACTIVE/PAUSED), createdAt, updatedAt

**`POST /relayer-wallets` Request** (변경됨 — contractAddress 제거, relayerRole 추가):
```json
{
  "networkId": 1,
  "walletAddressId": 42,
  "relayerRole": "COLLECTION"
}
```
- relayerRole: `COLLECTION` | `WITHDRAWAL`
- 응답: 201 Created + RelayerDetailResponse
- 응답 시간: 10~30초 (온체인 TX 대기)

**`GET /relayer-wallets/:id` Response**: `RelayerDetailResponse`
- Relayer 상세 정보 + 온체인 TX 이력

**`POST /relayer-wallets/:id/deactivate` Request**:
```json
{}
```
- pending TX가 있으면 `registrationStatus = DEREGISTERING` (온체인 해제 대기)
- pending TX가 없으면 즉시 해제 (온체인 `removeRelayer` TX 포함)
- 응답 시간: 5~60초 (TX 포함 여부에 따라)

**`PATCH /relayer-wallets/:id/status` Request**:
```json
{ "status": "PAUSED" }
```
- 허용 전환: ACTIVE↔PAUSED

**`GET /relayer-wallets/live` Response**: `List<RelayerLiveResponse>`
- Node.js relayer-api 경유 실시간 데이터
- fields: id, networkId, walletAddress, relayerRole, status, registrationStatus, pendingTxCount, lastPolledAt

**`GET /relayer-wallets/health` Response**: `RelayerHealthResponse`
```json
{
  "totalCount": 10,
  "activeCount": 8,
  "pausedCount": 2,
  "byNetwork": [
    { "networkId": 1, "networkCode": "ETH", "activeCount": 5, "pausedCount": 1 },
    { "networkId": 2, "networkCode": "BSC", "activeCount": 3, "pausedCount": 1 }
  ],
  "registrationStatus": {
    "REGISTERED": 8,
    "REGISTERING": 1,
    "DEREGISTERING": 1
  }
}
```

---

### SCR-5600 — Wallet Approval

| # | Method | Endpoint | 용도 |
|---|--------|----------|------|
| 1 | GET | `/api/admin/wallet-approvals` | Approval 목록 |
| 2 | POST | `/api/admin/wallet-approvals/:id/retry` | Approve 재시도 (FAILED → PENDING) |

**검색 파라미터** (`GET /wallet-approvals`):
```
?page=1&size=20&sort=id,DESC
&approveStatus=FAILED      # ApproveStatus enum (선택)
&networkId=1               # exact (선택)
&walletAddressId=42        # exact (선택)
```

**`GET /wallet-approvals` Response**: `XPage<WalletApprovalListResponse>`
- id, walletAddressId, walletAddress, currencyId, currencyCode, networkId, networkCode, spenderAddress, approvedAmount, approveTxHash, approveStatus, approvedAt, createdAt

**재시도 조건**: `approveStatus = FAILED` 인 경우만 가능
- 에러: 409 (재시도 불가 상태)

---

### SCR-5700 — Nonce Tracker

| # | Method | Endpoint | 용도 |
|---|--------|----------|------|
| 1 | GET | `/api/admin/nonce-trackers` | 논스 목록 |
| 2 | POST | `/api/admin/nonce-trackers/:id/sync` | 온체인 논스 동기화 |
| 3 | POST | `/api/admin/nonce-trackers/:id/unlock` | 강제 락 해제 |

**`GET /nonce-tracker` Response**: `XPage<NonceTrackerResponse>`
- id, walletAddressId, walletAddress, networkId, networkCode, nextNonce, lastConfirmedNonce, status, updatedAt
- status: `IDLE`, `LOCKED`

**`POST /sync` Response**: 동기화된 `NonceTracker` 반환
- 온체인 조회 후 nextNonce 갱신 (TODO: 블록체인 RPC 연동)
- 에러 5001: 온체인 조회 실패

**`POST /unlock` Response**: 락 해제된 `NonceTracker` 반환
- 조건: `status = LOCKED` 인 경우만 가능
- 에러 409: 잠기지 않은 상태

---

### SCR-5300 — TX 온체인 상태 조회 (범용)

| # | Method | Endpoint | 용도 |
|---|--------|----------|------|
| 1 | GET | `/api/admin/tx/status/{txHash}?networkId=` | TX 온체인 상태 조회 |

**Response**:
```json
{
  "txHash": "0xabc123...",
  "status": "confirmed",
  "blockNumber": 18000000,
  "confirmations": 15,
  "gasUsed": "65000"
}
```
- status: `pending` | `confirmed` | `failed`
- blockchain-api 연동으로 실시간 확인
- **UI 활용**: 입금 상세, 출금 상세, 집금 상세 등에서 "온체인 확인" 버튼으로 사용

---

### SCR-5800 — 컨트랙트 관리 (신규)

| # | Method | Endpoint | 용도 |
|---|--------|----------|------|
| 1 | GET | `/api/admin/contracts` | 전체 ACTIVE 컨트랙트 목록 |
| 2 | GET | `/api/admin/contracts/{networkId}/status` | 온체인 + DB 상태 조회 |
| 3 | POST | `/api/admin/contracts/register` | 컨트랙트 등록 (수동 배포 후) |
| 4 | POST | `/api/admin/contracts/add-relayer` | Relayer 추가 |
| 5 | POST | `/api/admin/contracts/remove-relayer` | Relayer 제거 |
| 6 | POST | `/api/admin/contracts/pause` | 긴급 정지 |
| 7 | POST | `/api/admin/contracts/{networkId}/unpause` | 정지 해제 |

**`GET /contracts` Response**: `XPage<ContractListResponse>`
```json
[{
  "id": 1,
  "networkId": 1,
  "networkCode": "ETH",
  "contractAddress": "0x...",
  "ownerAddressId": 15,
  "ownerAddress": "0x...",
  "abiVersion": "1.0",
  "status": "ACTIVE",
  "pausedReason": null,
  "createdAt": "2026-03-01 10:00:00"
}]
```
- status: `ACTIVE` (초록), `PAUSED` (주황), `DEPRECATED` (회색)

**`GET /contracts/{networkId}/status` Response**: `ContractStatusResponse`
```json
{
  "contractAddress": "0x...",
  "ownerAddress": "0x...",
  "pausedOnchain": false,
  "relayerCount": 3,
  "relayerAddresses": ["0x...", "0x...", "0x..."],
  "dbStatus": "ACTIVE",
  "lastSyncAt": "2026-03-17 14:30:00"
}
```
- 온체인: `contract.owner()`, `contract.paused()`, Relayer 목록
- DB: 컨트랙트 상태

**`POST /contracts/register` Request**:
```json
{
  "networkId": 1,
  "contractAddress": "0x...",
  "deployTxHash": "0x...",
  "ownerAddressId": 15,
  "abiVersion": "1.0"
}
```
- 요구사항: 수동 배포(Hardhat/Tronbox) → `transferOwnership(ADMIN)` 완료
- 응답: 201 Created + ContractListResponse
- 응답 시간: 5~15초

**`POST /contracts/add-relayer` Request**:
```json
{
  "networkId": 1,
  "relayerWalletId": 42
}
```
- 온체인: `contract.addRelayer(relayerAddress)` TX 포함
- 응답 시간: 10~30초

**`POST /contracts/remove-relayer` Request**:
```json
{
  "networkId": 1,
  "relayerWalletId": 42
}
```
- 온체인: `contract.removeRelayer(relayerAddress)` TX 포함
- 응답 시간: 10~30초

**`POST /contracts/pause` Request**:
```json
{
  "networkId": 1,
  "reason": "보안 감사 중"
}
```
- 온체인: `contract.pause()` TX 포함
- reason 필수 (감사 로그)
- UI: 이중 확인 모달 필수
- 응답 시간: 10~30초

**`POST /contracts/{networkId}/unpause` Request**:
```json
{}
```
- 온체인: `contract.unpause()` TX 포함
- UI: 확인 모달
- 응답 시간: 10~30초

---

## Part 2: 전체 API 엔드포인트 (121개)

### 0. 인증 (3개)

| # | Method | Endpoint | 설명 | 컨트롤러 |
|---|--------|----------|------|---------|
| 1 | POST | `/api/admin/auth/login` | 로그인 (email + password) | AuthController |
| 2 | POST | `/api/admin/auth/2fa/verify` | 2FA TOTP 검증 | AuthController |
| 3 | POST | `/api/admin/auth/logout` | 로그아웃 | AuthController |

### 1. 대시보드 (4개) — 2차 확장

| # | Method | Endpoint | 설명 | 컨트롤러 |
|---|--------|----------|------|---------|
| 4 | GET | `/api/admin/dashboard/summary` | 요약 카드 (오늘 입금/출금, 미식별, 알림) | DashboardController |
| 5 | GET | `/api/admin/dashboard/alerts` | 이상 알림 목록 | DashboardController |
| 6 | GET | `/api/admin/dashboard/unidentified` | 미식별 입금 목록 (최근 N건) | DashboardController |
| 7 | GET | `/api/admin/dashboard/settlement` | 정산 현황 요약 | DashboardController |

### 2. 파트너 관리 (21개) — 1차 핵심

| # | Method | Endpoint | 설명 | 컨트롤러 | 화면 |
|---|--------|----------|------|---------|------|
| 8 | GET | `/api/admin/partners` | 파트너 목록 | PartnerManagementController | SCR-2100 |
| 9 | POST | `/api/admin/partners` | 파트너 등록 | PartnerManagementController | SCR-2110 |
| 10 | GET | `/api/admin/partners/:id` | 파트너 상세 | PartnerManagementController | SCR-2200 |
| 11 | PUT | `/api/admin/partners/:id` | 기본 정보 수정 | PartnerManagementController | SCR-2200/Tab1 |
| 12 | PATCH | `/api/admin/partners/:id/status` | 상태 변경 | PartnerManagementController | SCR-2100, SCR-2200/Tab1 |
| 13 | PUT | `/api/admin/partners/:id/fees` | 수수료 수정 (cascade) | PartnerManagementController | SCR-2200/Tab1 |
| 14 | GET | `/api/admin/partners/:id/chain-configs` | 체인 설정 조회 | PartnerManagementController | SCR-2200/Tab2 |
| 15 | PUT | `/api/admin/partners/:id/chain-configs` | 체인 설정 일괄 저장 | PartnerManagementController | SCR-2200/Tab2 |
| 16 | GET | `/api/admin/partners/:id/withdrawal-policy` | 출금 정책 조회 | PartnerManagementController | SCR-2200/Tab3 |
| 17 | PUT | `/api/admin/partners/:id/withdrawal-policy` | 출금 정책 수정 | PartnerManagementController | SCR-2200/Tab3 |
| 18 | GET | `/api/admin/partners/:id/whitelist` | 주소 화이트리스트 조회 | PartnerManagementController | SCR-2200/Tab3 |
| 19 | POST | `/api/admin/partners/:id/whitelist` | 화이트리스트 추가 | PartnerManagementController | SCR-2200/Tab3 |
| 20 | DELETE | `/api/admin/partners/:id/whitelist/:wid` | 화이트리스트 삭제 | PartnerManagementController | SCR-2200/Tab3 |
| 21 | GET | `/api/admin/partners/:id/telegram` | Telegram 설정 조회 | PartnerManagementController | SCR-2200/Tab4 |
| 22 | PUT | `/api/admin/partners/:id/telegram` | Telegram 설정 수정 | PartnerManagementController | SCR-2200/Tab4 |
| 23 | PUT | `/api/admin/partners/:id/telegram/subscriptions` | 구독 이벤트 수정 | PartnerManagementController | SCR-2200/Tab4 |
| 24 | GET | `/api/admin/partners/:id/axim` | Axim 설정 조회 | PartnerManagementController | SCR-2200/Tab4 |
| 25 | PUT | `/api/admin/partners/:id/axim` | Axim 설정 수정 | PartnerManagementController | SCR-2200/Tab4 |
| 26 | POST | `/api/admin/partners/:id/api-key/regenerate` | API Key 재발급 | PartnerManagementController | SCR-2200/Tab1 |
| 27 | POST | `/api/admin/partners/:id/2fa/reset` | 파트너 2FA 리셋 | PartnerManagementController | SCR-2200/Tab1 |
| 28 | GET | `/api/admin/partners/:id/webhook-logs` | Webhook 전달 로그 | PartnerManagementController | SCR-2200/Tab4 |

### 3. 거래 관리 (15개) — 1차 핵심

| # | Method | Endpoint | 설명 | 컨트롤러 | 화면 |
|---|--------|----------|------|---------|------|
| 29 | GET | `/api/admin/deposits` | 입금 목록 | DepositManagementController | SCR-3100 |
| 30 | GET | `/api/admin/deposits/:id` | 입금 상세 | DepositManagementController | SCR-3110 |
| 31 | GET | `/api/admin/deposits/:id/history` | 입금 상태 이력 | DepositManagementController | SCR-3110 |
| 32 | GET | `/api/admin/deposit-sessions` | 입금 세션 목록 | DepositManagementController | SCR-3120 |
| 33 | GET | `/api/admin/collections` | 집금 목록 | CollectionManagementController | SCR-3130 |
| 34 | GET | `/api/admin/collections/:id` | 집금 상세 | CollectionManagementController | SCR-3130 |
| 35 | POST | `/api/admin/collections/:id/retry` | 집금 재시도 | CollectionManagementController | SCR-3130 |
| 36 | POST | `/api/admin/collections/:id/cancel` | 집금 취소 | CollectionManagementController | SCR-3130 |
| 37 | GET | `/api/admin/payment-links` | 결제 링크 목록 | PaymentLinkController | SCR-3140 |
| 38 | GET | `/api/admin/withdrawals` | 출금 목록 | WithdrawalManagementController | SCR-3200 |
| 39 | GET | `/api/admin/withdrawals/:id` | 출금 상세 | WithdrawalManagementController | SCR-3210 |
| 40 | GET | `/api/admin/withdrawals/:id/history` | 출금 상태 이력 | WithdrawalManagementController | SCR-3210 |
| 41 | GET | `/api/admin/withdrawals/pending-approval` | 승인 대기 목록 | WithdrawalManagementController | SCR-3300 |
| 42 | POST | `/api/admin/withdrawals/:id/approve` | 출금 승인 | WithdrawalManagementController | SCR-3210, SCR-3300 |
| 43 | POST | `/api/admin/withdrawals/:id/reject` | 출금 거부 | WithdrawalManagementController | SCR-3210, SCR-3300 |

### 3-B. 출금 일괄 처리 (2개)

| # | Method | Endpoint | 설명 | 컨트롤러 | 화면 |
|---|--------|----------|------|---------|------|
| 44 | POST | `/api/admin/withdrawals/batch-approve` | 일괄 승인 | WithdrawalManagementController | SCR-3300 |
| 45 | POST | `/api/admin/withdrawals/batch-reject` | 일괄 거부 | WithdrawalManagementController | SCR-3300 |

### 4. CS 도구 (4개) — 1차 핵심

| # | Method | Endpoint | 설명 | 컨트롤러 | 화면 |
|---|--------|----------|------|---------|------|
| 46 | GET | `/api/admin/cs/unidentified` | 미식별 입금 목록 | CsToolController | SCR-4100 |
| 47 | POST | `/api/admin/cs/unidentified/:id/match` | 미식별 매칭 | CsToolController | SCR-4100 |
| 48 | POST | `/api/admin/cs/unidentified/:id/refund` | 미식별 환불 | CsToolController | SCR-4100 |
| 49 | GET | `/api/admin/cs/tx-search` | TX Hash 글로벌 검색 | CsToolController | SCR-4200 |

### 5. 인프라 관리 (37개) — 2차 확장 + 컨트랙트 관리

| # | Method | Endpoint | 설명 | 컨트롤러 |
|---|--------|----------|------|---------|
| 50 | GET | `/api/admin/networks` | 네트워크 목록 | NetworkManagementController |
| 51 | POST | `/api/admin/networks` | 네트워크 추가 | NetworkManagementController |
| 52 | PUT | `/api/admin/networks/:id` | 네트워크 수정 | NetworkManagementController |
| 53 | GET | `/api/admin/currencies` | 통화 목록 | CurrencyManagementController |
| 54 | POST | `/api/admin/currencies` | 통화 추가 | CurrencyManagementController |
| 55 | PUT | `/api/admin/currencies/:id` | 통화 수정 | CurrencyManagementController |
| 56 | GET | `/api/admin/currencies/:id/networks` | 통화-네트워크 매핑 | CurrencyManagementController |
| 57 | POST | `/api/admin/currencies/:id/networks` | 매핑 추가 | CurrencyManagementController |
| 58 | PUT | `/api/admin/currency-networks/:id` | 매핑 수정 | CurrencyManagementController |
| 59 | GET | `/api/admin/hd-wallets` | HD Wallet 목록 | WalletManagementController |
| 60 | GET | `/api/admin/hd-wallets/:id` | HD Wallet 상세 | WalletManagementController |
| 61 | GET | `/api/admin/wallet-index` | 인덱스 관리 목록 | WalletManagementController |
| 62 | GET | `/api/admin/infra-wallets` | 인프라 지갑 목록 (ADMIN/GAS/SETTLEMENT) | InfraWalletController |
| 63 | POST | `/api/admin/infra-wallets/admin` | ADMIN 지갑 생성 | InfraWalletController |
| 64 | POST | `/api/admin/infra-wallets/gas` | GAS 지갑 생성 | InfraWalletController |
| 65 | POST | `/api/admin/infra-wallets/settlement` | SETTLEMENT 지갑 생성 | InfraWalletController |
| 66 | GET | `/api/admin/relayer-wallets` | Relayer 목록 | RelayerManagementController |
| 67 | POST | `/api/admin/relayer-wallets` | Relayer 등록 | RelayerManagementController |
| 68 | GET | `/api/admin/relayer-wallets/:id` | Relayer 상세 조회 | RelayerManagementController |
| 69 | PATCH | `/api/admin/relayer-wallets/:id/status` | Relayer 상태 변경 | RelayerManagementController |
| 70 | POST | `/api/admin/relayer-wallets/:id/deactivate` | Relayer 해제 | RelayerManagementController |
| 71 | GET | `/api/admin/relayer-wallets/live` | 실시간 Relayer 목록 | RelayerManagementController |
| 72 | GET | `/api/admin/relayer-wallets/health` | Relayer 헬스 집계 | RelayerManagementController |
| 73 | GET | `/api/admin/wallet-approvals` | Approve 목록 | WalletApprovalController |
| 74 | POST | `/api/admin/wallet-approvals/:id/retry` | Approve 재시도 | WalletApprovalController |
| 75 | GET | `/api/admin/nonce-trackers` | 논스 목록 | NonceTrackerController |
| 76 | POST | `/api/admin/nonce-trackers/:id/sync` | 온체인 동기화 | NonceTrackerController |
| 77 | POST | `/api/admin/nonce-trackers/:id/unlock` | 강제 락 해제 | NonceTrackerController |
| 78 | GET | `/api/admin/wallets` | 전체 지갑 목록 (잔액 포함) | WalletManagementController |
| 79 | GET | `/api/admin/wallets/:id` | 지갑 상세 | WalletManagementController |
| 80 | GET | `/api/admin/wallets/:id/balances` | 지갑 잔액 목록 | WalletManagementController |
| 81 | POST | `/api/admin/wallets/sync-balances` | 잔액 일괄 동기화 | WalletManagementController |
| 82 | GET | `/api/admin/tx/status/{txHash}` | TX 온체인 상태 조회 | WalletManagementController |
| 83 | GET | `/api/admin/contracts` | 컨트랙트 목록 | ContractManagementController |
| 84 | GET | `/api/admin/contracts/{networkId}/status` | 컨트랙트 상태 조회 | ContractManagementController |
| 85 | POST | `/api/admin/contracts/register` | 컨트랙트 등록 | ContractManagementController |
| 86 | POST | `/api/admin/contracts/add-relayer` | Relayer 추가 | ContractManagementController |
| 87 | POST | `/api/admin/contracts/remove-relayer` | Relayer 제거 | ContractManagementController |
| 88 | POST | `/api/admin/contracts/pause` | 컨트랙트 정지 | ContractManagementController |
| 89 | POST | `/api/admin/contracts/{networkId}/unpause` | 컨트랙트 정지 해제 | ContractManagementController |

### 6. 정산 관리 (6개) — 3차 확장

| # | Method | Endpoint | 설명 | 컨트롤러 |
|---|--------|----------|------|---------|
| 90 | GET | `/api/admin/settlements/daily-fees` | 일별 수수료 집계 | SettlementController |
| 91 | GET | `/api/admin/settlements/daily-fees/summary` | 기간별 요약 합계 | SettlementController |
| 92 | GET | `/api/admin/settlements/realizations` | 실현 목록 | SettlementController |
| 93 | GET | `/api/admin/settlements/realizations/:id` | 실현 상세 | SettlementController |
| 94 | GET | `/api/admin/settlements/balances` | 참여자별 잔액 | SettlementController |
| 95 | POST | `/api/admin/settlements/withdraw` | 시스템 쉐어 출금 | SettlementController |

### 7. 가스비/원장 (12개) — 3차 확장

| # | Method | Endpoint | 설명 | 컨트롤러 |
|---|--------|----------|------|---------|
| 96 | GET | `/api/admin/gas-costs` | 가스비 기록 목록 | GasCostController |
| 97 | GET | `/api/admin/gas-costs/:id` | 가스비 상세 | GasCostController |
| 98 | PATCH | `/api/admin/gas-costs/:id/waive` | 가스비 면제 | GasCostController |
| 99 | GET | `/api/admin/gas-invoices` | 인보이스 목록 | GasInvoiceController |
| 100 | GET | `/api/admin/gas-invoices/:id` | 인보이스 상세 | GasInvoiceController |
| 101 | POST | `/api/admin/gas-invoices/generate` | 월별 일괄 발행 | GasInvoiceController |
| 102 | POST | `/api/admin/gas-invoices/:id/confirm-payment` | 입금 확인 | GasInvoiceController |
| 103 | PATCH | `/api/admin/gas-invoices/:id/overdue` | 연체 처리 | GasInvoiceController |
| 104 | GET | `/api/admin/ledgers` | 원장 목록 | LedgerController |
| 105 | GET | `/api/admin/ledgers/balance` | 파트너 잔액 조회 | LedgerController |
| 106 | GET | `/api/admin/prices/current` | 현재 환율 | PriceController |
| 107 | GET | `/api/admin/prices/history` | 가격 이력 | PriceController |

### 8. 시스템 설정 (7개) — 4차 확장

| # | Method | Endpoint | 설명 | 컨트롤러 |
|---|--------|----------|------|---------|
| 108 | GET | `/api/admin/settings` | 전체 설정 조회 | SystemSettingsController |
| 109 | PUT | `/api/admin/settings/:key` | 설정값 수정 | SystemSettingsController |
| 110 | GET | `/api/admin/audit-logs` | 감사 로그 목록 (action: AuditAction enum 47개) | AuditLogController |
| 111 | GET | `/api/admin/audit-logs/:id` | 로그 상세 (details: JSON 구조화) | AuditLogController |
| 112 | POST | `/api/admin/maintenance/enable` | 유지보수 ON | MaintenanceController |
| 113 | POST | `/api/admin/maintenance/disable` | 유지보수 OFF | MaintenanceController |
| ★ | GET | `/api/admin/audit-logs` | 파트너 활동 로그 (targetType/Id 필터) | AuditLogController |

### 9. 관리자 계정 (8개) — 4차 확장

| # | Method | Endpoint | 설명 | 컨트롤러 |
|---|--------|----------|------|---------|
| 114 | GET | `/api/admin/admins` | 관리자 목록 | AdminManagementController |
| 115 | POST | `/api/admin/admins` | 관리자 등록 | AdminManagementController |
| 116 | GET | `/api/admin/admins/:id` | 관리자 상세 | AdminManagementController |
| 117 | PUT | `/api/admin/admins/:id` | 관리자 정보 수정 | AdminManagementController |
| 118 | PATCH | `/api/admin/admins/:id/status` | 상태 변경 | AdminManagementController |
| 119 | POST | `/api/admin/admins/:id/2fa/reset` | 2FA 리셋 | AdminManagementController |
| 120 | POST | `/api/admin/admins/me/2fa/setup` | 본인 2FA 설정 | AdminManagementController |
| 121 | POST | `/api/admin/admins/me/2fa/verify` | 본인 2FA 검증 | AdminManagementController |

---

## Part 3: 기존 vs 신규 비교

### 유지 (수정 필요) — 기존 엔드포인트 중 v2 스펙에 매핑되는 것

| 기존 | v2 스펙 | 변경 사항 |
|------|---------|----------|
| `GET /api/admin/partners` | #8 | 검색 파라미터 확장 (partnerType, parentPartnerId, email 추가) |
| `POST /api/admin/partners` | #9 | 수수료 체계 확장 (parentFeeRate, minFeeRate, maxFeeCap, loginEmail, password) |
| `GET /api/admin/partners/:id` | #10 | Response 확장 (수수료, 계정, 연동 정보) |
| `PUT /api/admin/partners/:id` | #11 | 기본 정보만 수정 (수수료는 별도 API) |
| `PATCH /api/admin/partners/:id/status` | #12 | 상태 전환 규칙 강화 (PENDING→ACTIVE, TERMINATED 추가) |
| `GET /chain-configs` | #14 | 유지 |
| `PUT /chain-configs` | #15 | 유지 |
| `GET /withdrawal-policy` | #16 | 유지 |
| `PUT /withdrawal-policy` | #17 | PATCH→PUT 변경 |
| `GET /axim` | #24 | 유지 |
| `PUT /axim` | #25 | PATCH→PUT 변경 |
| `GET /api/admin/deposits` | #29 | 검색 파라미터 확장 |
| `GET /api/admin/deposits/:id` | #30 | Response 확장 (세션/집금/이력 포함) |
| `GET /api/admin/deposit-sessions` | #32 | 유지 |
| `GET /api/admin/collections` | #33 | 유지 |
| `GET /api/admin/withdrawals` | #38 | 검색 파라미터 확장 |
| `GET /api/admin/withdrawals/pending-approval` | #41 | Response 확장 (autoApprove, whitelist) |
| `POST /approve` | #42 | 유지 |
| `POST /reject` | #43 | 유지 |
| `POST /api/admin/auth/login` | #1 | 2FA 대응 추가 |
| `POST /api/admin/auth/logout` | #3 | 유지 |
| `GET /api/admin/admins` | #101 | 유지 |
| `POST /api/admin/admins` | #102 | 유지 |
| `PUT /api/admin/admins/:id` | #104 | 유지 |
| `PATCH /api/admin/admins/:id/status` | #105 | toggle→상태 전환으로 변경 |
| `GET /api/admin/audit-logs` | #97 | targetType/targetId 필터 추가 |
| `GET /api/admin/system-settings` | #95 | URL 변경 `/system-settings` → `/settings` |
| `PUT /api/admin/system-settings/:key` | #96 | URL 변경 |
| `GET /api/admin/prices/current` | #93 | 유지 |
| `GET /api/admin/blockchain-networks` | #50 | URL 변경 `/blockchain-networks` → `/networks` |
| `PUT /api/admin/blockchain-networks/:id` | #52 | URL 변경 |

### 신규 생성 필요

| # | Endpoint | 설명 | 컨트롤러 (신규) |
|---|----------|------|----------------|
| 2 | `POST /auth/2fa/verify` | 2FA 검증 | AuthController |
| 4-7 | `GET /dashboard/*` | 대시보드 4개 | **DashboardController** (신규) |
| 13 | `PUT /partners/:id/fees` | 수수료 수정 (cascade) | PartnerManagementController |
| 18-20 | `/partners/:id/whitelist*` | 화이트리스트 3개 | PartnerManagementController |
| 21-23 | `/partners/:id/telegram*` | Telegram 3개 | PartnerManagementController |
| 26 | `POST /partners/:id/api-key/regenerate` | API Key 재발급 | PartnerManagementController |
| 27 | `POST /partners/:id/2fa/reset` | 파트너 2FA 리셋 | PartnerManagementController |
| 28 | `GET /partners/:id/webhook-logs` | Webhook 로그 | PartnerManagementController |
| 31 | `GET /deposits/:id/history` | 입금 상태 이력 | DepositManagementController |
| 34 | `GET /collections/:id` | 집금 상세 | **CollectionManagementController** (신규) |
| 35-36 | `POST /collections/:id/retry\|cancel` | 집금 재시도/취소 | **CollectionManagementController** (신규) |
| 37 | `GET /payment-links` | 결제 링크 | **PaymentLinkController** (신규) |
| 40 | `GET /withdrawals/:id/history` | 출금 상태 이력 | WithdrawalManagementController |
| 44-45 | `POST /withdrawals/batch-*` | 일괄 승인/거부 | WithdrawalManagementController |
| 46-49 | `/cs/*` | CS 도구 4개 | **CsToolController** (신규) |
| 51 | `POST /networks` | 네트워크 추가 | NetworkManagementController |
| 53-58 | `/currencies*` | 통화 관리 6개 | **CurrencyManagementController** (신규) |
| 59-61 | `/hd-wallets*`, `/wallet-index` | HD Wallet 3개 | WalletManagementController |
| 62-64 | `/infra-wallets*` | 인프라 지갑 3개 | **InfraWalletController** (신규) |
| 65-67 | `/relayer-wallets*` | Relayer 3개 (URL 변경) | RelayerManagementController |
| 68-69 | `/wallet-approvals*` | Approve 2개 (URL 변경) | WalletApprovalController |
| 70-72 | `/nonce-trackers*` | 논스 3개 (URL 변경) | NonceTrackerController |
| 73-76 | `/wallets*` 확장 | 잔액 동기화 등 | WalletManagementController |
| 77-82 | `/settlements/*` | 정산 6개 | **SettlementController** (신규) |
| 83-85 | `/gas-costs*` | 가스비 3개 | **GasCostController** (재구성) |
| 86-90 | `/gas-invoices*` | 인보이스 5개 | **GasInvoiceController** (신규) |
| 91-92 | `/ledgers*` | 원장 2개 | **LedgerController** (분리) |
| 94 | `GET /prices/history` | 가격 이력 | PriceController |
| 99-100 | `/maintenance/*` | 유지보수 2개 | **MaintenanceController** (신규) |
| 106 | `POST /admins/:id/2fa/reset` | 2FA 리셋 | AdminManagementController |
| 107-108 | `POST /admins/me/2fa/*` | 본인 2FA 2개 | AdminManagementController |

### 삭제/이동 대상 (기존에 있으나 v2 스펙에 없는 것)

| 기존 Endpoint | 처리 |
|--------------|------|
| `GET /api/admin/statistics/overview` | → `GET /dashboard/summary` 로 대체 |
| `GET /api/admin/statistics/transactions-realtime` | → 삭제 (대시보드로 통합) |
| `GET /api/admin/gas-costs/fee-wallets` | → `GET /infra-wallets?type=FEE` 로 대체 |
| `GET /api/admin/gas-costs/invoices` | → `GET /gas-invoices` 로 분리 |
| `POST /withdrawals/:code/cancel` | → 삭제 (v2에서 cancel 미지원) |
| `POST /withdrawals/:code/retry` | → `POST /:id/retry` (path variable 변경: code→id) |
| `GET /withdrawals/balance-pending` | → 삭제 (v2 스펙에 없음) |
| `GET /wallets/assignments` | → `GET /wallets` 통합 (assignments 분리 불필요) |
| `POST /nonce-tracker/:id/reset` | → `POST /nonce-trackers/:id/sync` (이름+경로 변경) |
| `GET /relayers/health` | → 삭제 (별도 health 없음) |
| `GET /pool-addresses` | → 삭제 (인프라 지갑으로 통합) |
| `GET /pool-addresses/health` | → 삭제 |
| `PATCH /partners/:id/pool-address-limit` | → 삭제 |
| `GET /transactions/retry/*` | → 삭제 (v2에서 별도 재시도 관리 없음) |
| `POST /transactions/retry/:id/force` | → 삭제 |
| `POST /transactions/retry/:id/cancel` | → 삭제 |
| `GET /api/admin/auth/session` | → 삭제 (login 응답에 세션 정보 포함) |
| `GET /api/admin/ledger-entries` | → `GET /ledgers` (URL 변경) |

---

## Part 4: 컨트롤러 구성 (v2 — ✅ 전체 구현 완료)

### 전체 컨트롤러 목록 (25개)
| 컨트롤러 | API 수 | 구현 단계 | 비고 |
|---------|--------|---------|------|
| AuthController | 3 | 1차 | 2FA tempToken 방식 |
| PartnerManagementController | 21 | 1차 | 체인설정/수수료/텔레그램/Axim/화이트리스트 |
| DepositManagementController | 4 | 1차 | 입금+세션 목록/상세/이력 |
| WithdrawalManagementController | 10 | 1차 | 출금+승인+일괄처리 |
| CollectionManagementController | 4 | 1차 | 집금 목록/상세/재시도/취소 |
| PaymentLinkController | 1 | 1차 | 결제 링크 목록 |
| CsToolController | 4 | 1차 | 미식별 매칭/환불, TX 검색 |
| AdminManagementController | 8 | 1차 | 2FA 포함 |
| DashboardController | 4 | 2차 | 요약/알림/미식별/정산 |
| NetworkManagementController | 3 | 2차 | (구 BlockchainNetworkManagementController) |
| CurrencyManagementController | 6 | 2차 | 통화+네트워크 매핑 |
| WalletManagementController | 8 | 2차 | 지갑+HD Wallet+인덱스+TX 상태 조회 |
| InfraWalletController | 4 | 2차 | ADMIN/GAS/SETTLEMENT 지갑 |
| RelayerManagementController | 7 | 2차 | Relayer CRUD + 상세/해제/실시간/헬스 |
| WalletApprovalController | 2 | 2차 | Approve 목록/재시도 |
| NonceTrackerController | 3 | 2차 | 목록/sync/unlock |
| ContractManagementController | 7 | 2차 | 컨트랙트 목록/상태/등록/Relayer 관리/정지 |
| SettlementController | 6 | 3차 | 정산 관리 |
| GasCostController | 3 | 3차 | 가스비 기록 |
| GasInvoiceController | 5 | 3차 | 가스비 인보이스 |
| LedgerController | 2 | 3차 | 원장 |
| PriceController | 2 | 3차 | 현재 환율/이력 |
| SystemManagementController | 4 | 4차 | 설정 + 감사로그 |
| MaintenanceController | 2 | 4차 | 유지보수 모드 |
| PingController | 1 | - | 헬스체크 |

### 삭제된 구 컨트롤러 (v1 → v2)
| 구 컨트롤러 | 처리 |
|-----------|------|
| StatisticsController | → DashboardController로 대체 |
| PoolAddressManagementController | → InfraWalletController로 통합 |
| TransactionRetryController | → v2에서 제거 |
| BlockchainNetworkManagementController | → NetworkManagementController로 이름 변경 |

---

## Part 5: 구현 우선순위 및 진행 현황

### ✅ 1차 완료 (파트너/거래/CS — 53개 API)
```
인증                       — 3개 API  ✅
메뉴 2: 파트너 관리        — 21개 API ✅ (SCR-2100~2200)
메뉴 3: 거래 관리           — 17개 API ✅ (SCR-3100~3300)
메뉴 4: CS 도구             — 4개 API  ✅ (SCR-4100~4200)
메뉴 9: 관리자 계정         — 8개 API  ✅
```

### ✅ 2차 완료 (대시보드 + 인프라 — 41개 API)
```
대시보드                   — 4개 API  ✅ (SCR-1000)
인프라 관리 (네트워크)      — 3개 API  ✅ (SCR-5100)
인프라 관리 (통화)          — 6개 API  ✅ (SCR-5200)
인프라 관리 (지갑)          — 8개 API  ✅ (SCR-5300)
인프라 관리 (인프라 지갑)   — 4개 API  ✅ (SCR-5400)
인프라 관리 (Relayer)       — 7개 API  ✅ (SCR-5500)
인프라 관리 (Approval)      — 2개 API  ✅ (SCR-5600)
인프라 관리 (Nonce)         — 3개 API  ✅ (SCR-5700)
인프라 관리 (TX 상태)       — 1개 API  ✅ (SCR-5300)
인프라 관리 (컨트랙트)      — 7개 API  ✅ (SCR-5800)
```

### 3차 확장 (정산 + 가스비 — 18개 API)
```
정산 관리                  — 6개 API
가스비/원장                — 12개 API
```
- SettlementController, GasCostController, GasInvoiceController, LedgerController, PriceController 구현체 존재 (서비스 로직 TODO)

### 4차 확장 (시스템 + 유지보수 — 9개 API)
```
시스템 설정                — 4개 API
유지보수 모드              — 2개 API
```
- SystemManagementController, MaintenanceController 구현체 존재 (서비스 로직 TODO)

---

## Part 6: 에러 코드 전체 목록

| 코드 | i18n 키 | HTTP | 설명 |
|------|---------|------|------|
| 2001 | partner.error.duplicate-code | 409 | 파트너 코드 중복 |
| 2002 | partner.error.duplicate-email | 409 | 파트너 이메일 중복 |
| 2003 | partner.error.fee-below-min | 400 | deposit_fee_rate < min_fee_rate |
| 2004 | partner.error.fee-above-cap | 400 | deposit_fee_rate > max_fee_cap |
| 2005 | partner.error.cap-above-parent | 400 | max_fee_cap > 부모 max_fee_cap |
| 2006 | partner.error.invalid-status-transition | 400 | 불가능한 상태 전환 |
| 2007 | partner.error.terminated | 400 | 해지된 파트너 |
| 3001 | withdrawal.error.exceed-daily-limit | 400 | 일일 출금 한도 초과 |
| 3002 | withdrawal.error.exceed-single-limit | 400 | 건당 출금 한도 초과 |
| 3003 | withdrawal.error.address-not-whitelisted | 400 | 화이트리스트 미등록 주소 |
| 3004 | withdrawal.error.insufficient-balance | 400 | 잔액 부족 |
| 3005 | withdrawal.error.already-processed | 400 | 이미 처리된 출금 |
| 4001 | cs.error.already-matched | 409 | 이미 매칭된 입금 |
| 4002 | cs.error.invalid-deposit-for-refund | 400 | 환불 불가 상태 |
| 5001 | infra.error.nonce-sync-failed | 500 | 논스 동기화 실패 |
| 5002 | infra.error.wallet-creation-failed | 500 | 지갑 생성 실패 |
| 6001 | settlement.error.insufficient-realized | 400 | 실현 잔액 부족 |
| 6002 | settlement.error.realization-in-progress | 409 | 실현 진행 중 |
| 7001 | gas.error.invoice-already-exists | 409 | 해당 월 인보이스 이미 존재 |
| 7002 | gas.error.invoice-already-paid | 400 | 이미 입금 확인된 인보이스 |
| 8001 | settings.error.invalid-value-type | 400 | 설정값 타입 불일치 |
| 9001 | admin.error.duplicate-email | 409 | 관리자 이메일 중복 |
| 9002 | admin.error.cannot-deactivate-self | 400 | 본인 비활성화 불가 |
