# @XSample 적용 지침서 — open-api DTO

> **작성일**: 2026-04-02
> **대상**: `open-api/src/main/java/com/cryptoments/openapi/dto/`
> **의존성**: `com.github.Axim-one:gradle-restdoc-generator:2.1.5`

---

## 적용 규칙

1. **import 추가**: `import one.axim.framework.rest.annotation.XSample;`
2. **모든 필드에 필수는 아님** — Generator가 타입/패턴 폴백으로 자동 생성
3. **우선 적용 대상**: 자동 추론이 어렵거나 비즈니스 의미가 중요한 필드
4. **BigDecimal**: Jackson `ToStringSerializer` 사용 시 문자열 값으로 지정 (예: `"1450.50"`)
5. **LocalDateTime**: `yyyy-MM-dd HH:mm:ss` 형식 (예: `"2026-04-02 14:30:00"`)

---

## Request DTOs

### WithdrawalRequest.java

```java
@XSample("user-001")
private String partnerUserId;

@XSample("BSC")
private String chainType;

@XSample("USDT")
private String currencyType;

@XSample("0x1234567890abcdef1234567890abcdef12345678")
private String toAddress;

@XSample("100.00")
private String amount;

@XSample("출금 요청 메모")
private String memo;
```

### DepositAddressRequest.java

```java
@XSample("user-001")
private String partnerUserId;

@XSample("ETHEREUM")
private String chainType;

@XSample("USDT")
private String currencyType;
```

### DepositReservationRequest.java

```java
@XSample("user-001")
private String userId;

@XSample("USDT")
private String currencyType;

@XSample("BSC")
private String chainType;

@XSample("50000")
private BigDecimal amountKrw;

@XSample("35.50")
private BigDecimal amountCrypto;

@XSample("1408.45")
private BigDecimal exchangeRate;

@XSample("LINK-001")
private String linkId;
```

### DepositReservationCompleteRequest.java

```java
@XSample("12345")
private String reservationId;

@XSample("0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890")
private String transactionHash;
```

### DepositCompletionRequest.java

```java
@XSample("12345")
private Long reservationId;

@XSample("35.50")
private BigDecimal actualAmountCrypto;

@XSample("50000")
private BigDecimal actualAmountKrw;

@XSample("0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890")
private String transactionHash;

@XSample("67890")
private Long transactionId;
```

### WidgetTokenRequest.java

```java
@XSample("user-001")
private String partnerUserId;
```

> `permissions` (Set<String>) — 폴백으로 `[]` 생성됨. 필요시 별도 처리.

### TransactionSearchRequest.java

```java
@XSample("1")
private Long partnerId;

@XSample("DEPOSIT")
private String type;
```

### AximPaymentRequest.java

```java
@XSample("user-001")
private String partnerUserId;

@XSample("50000")
private BigDecimal priceKrw;

@XSample("35.50")
private BigDecimal amount;

@XSample("BSC")
private String chainType;

@XSample("1.00")
private BigDecimal feeAmount;

@XSample("ORDER-20260402-001")
private String orderId;
```

### CreateDepositWalletRequest.java

```java
@XSample("user-001")
private String partnerUserId;

@XSample("ETHEREUM")
private String chainType;

@XSample("USDT")
private String currencyType;
```

### UserWithdrawalRequest.java

```java
@XSample("user-001")
private String partnerUserId;

@XSample("100.00")
private BigDecimal amount;

@XSample("USDT")
private String currencyType;

@XSample("BSC")
private String chainType;

@XSample("0x1234567890abcdef1234567890abcdef12345678")
private String toAddress;

@XSample("CRYPTO")
private String amountUnit;

@XSample("140000")
private BigDecimal krwAmount;
```

### ConfirmDepositsRequest.java

> `transactionIds` (List<Long>) — 폴백으로 `[]` 생성됨. 필요시 별도 처리.

### CallbackTestRequest.java

```java
@XSample("https://partner.example.com/webhook/callback")
private String callbackUrl;

@XSample("DEPOSIT")
private String type;
```

### PaymentLinkActivateRequest.java

```java
@XSample("user-001")
private String userIdentifier;

@XSample("203.0.113.1")
private String ipAddress;

@XSample("Mozilla/5.0")
private String userAgent;
```

### AuthRequest.java

> 인증 요청은 내부용. @XSample 생략 가능.

---

## Response DTOs

### TokenResponse.java

```java
@XSample("BSC")
private String chainType;

@XSample("USDT")
private String currencyType;

@XSample("USDT")
private String symbol;

@XSample("Tether USD")
private String name;

@XSample("0xdAC17F958D2ee523a2206206994597C13D831ec7")
private String contractAddress;

@XSample("18")
private Integer decimals;

@XSample("10.00")
private BigDecimal minWithdrawalAmount;

@XSample("100000.00")
private BigDecimal maxWithdrawalAmount;

@XSample("1.00")
private BigDecimal withdrawalFee;

@XSample("true")
private Boolean isActive;

@XSample("true")
private Boolean withdrawalEnabled;

@XSample("true")
private Boolean depositEnabled;
```

### ChainResponse.java

```java
@XSample("BSC")
private String chainType;

@XSample("BNB Smart Chain")
private String name;

@XSample("BNB")
private String symbol;

@XSample("true")
private Boolean isActive;
```

### BalanceResponse.java

```java
@XSample("BSC")
private String chainType;

@XSample("USDT")
private String currencyType;

@XSample("1500.00")
private String balance;

@XSample("200.00")
private String lockedBalance;

@XSample("1300.00")
private String availableBalance;
```

### DepositAddressResponse.java

```java
@XSample("0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18")
private String address;

@XSample("BSC")
private String chainType;

@XSample("USDT")
private String currencyType;

@XSample("1.00")
private String minDepositAmount;

@XSample("0x55d398326f99059fF775485246999027B3197955")
private String contractAddress;

@XSample("18")
private Integer decimals;
```

### DepositReservationResponse.java

```java
@XSample("12345")
private Long id;

@XSample("1")
private Long partnerId;

@XSample("user-001")
private String userId;

@XSample("USDT")
private String currencyType;

@XSample("BSC")
private String chainType;

@XSample("50000")
private BigDecimal amountKrw;

@XSample("35.50")
private BigDecimal amountCrypto;

@XSample("1408.45")
private BigDecimal exchangeRate;

@XSample("PENDING")
private String status;

@XSample("2026-04-02 15:30:00")
private LocalDateTime expiresAt;

@XSample("2026-04-02 14:30:00")
private LocalDateTime createdAt;

@XSample("35.50")
private BigDecimal actualAmountCrypto;

@XSample("50000")
private BigDecimal actualAmountKrw;

@XSample("0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890")
private String transactionHash;

@XSample("2026-04-02 14:35:00")
private LocalDateTime depositCompletedAt;
```

### DepositCompleteResponse.java

```java
@XSample("12345")
private String reservationId;

@XSample("0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890")
private String transactionHash;

@XSample("COMPLETED")
private String status;
```

### DepositWalletResponse.java

```java
@XSample("1001")
private Long id;

@XSample("0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18")
private String address;

@XSample("ETHEREUM")
private String chainType;

@XSample("USDT")
private String currencyType;

@XSample("ACTIVE")
private String status;

@XSample("2026-04-02 14:30:00")
private LocalDateTime createdAt;
```

### WithdrawalResponse.java

```java
@XSample("WD-20260402-001")
private String transactionId;

@XSample("100.00")
private String amount;

@XSample("BSC")
private String chainType;

@XSample("USDT")
private String currencyType;

@XSample("0x1234567890abcdef1234567890abcdef12345678")
private String toAddress;

@XSample("REQUESTED")
private String status;

@XSample("약 3~5분")
private String estimatedConfirmTime;
```

### WithdrawalResponseV1.java

```java
@XSample("67890")
private Long transactionId;

@XSample("0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890")
private String transactionHash;

@XSample("CONFIRMED")
private String status;

@XSample("100.00")
private BigDecimal tokenAmount;

@XSample("140845")
private BigDecimal krwAmount;

@XSample("1408.45")
private BigDecimal tokenKrwPrice;

@XSample("2026-04-02 14:30:00")
private LocalDateTime createdAt;
```

### WithdrawalFeeResponse.java

```java
@XSample("BSC")
private String chainType;

@XSample("USDT")
private String currencyType;

@XSample("1.00")
private String fee;

@XSample("10.00")
private String minAmount;
```

### WithdrawalLimitResponse.java

```java
@XSample("10.00")
private String minAmount;

@XSample("100000.00")
private String maxAmount;

@XSample("50000.00")
private String dailyLimit;

@XSample("15000.00")
private String dailyUsed;

@XSample("35000.00")
private String dailyRemaining;

@XSample("BSC")
private String chainType;

@XSample("USDT")
private String currencyType;
```

### TransactionResponse.java

```java
@XSample("DEP-20260402-001")
private String transactionId;

@XSample("DEPOSIT")
private String type;

@XSample("BSC")
private String chainType;

@XSample("USDT")
private String currencyType;

@XSample("100.00")
private String amount;

@XSample("CONFIRMED")
private String status;

@XSample("0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890")
private String txHash;

@XSample("0x9876543210fedcba9876543210fedcba98765432")
private String fromAddress;

@XSample("0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18")
private String toAddress;

@XSample("2026-04-02 14:30:00")
private String createdAt;

@XSample("2026-04-02 14:35:00")
private String confirmedAt;
```

### TransactionHistoryResponse.java

```java
@XSample("67890")
private Long transactionId;

@XSample("PT-20260402-001")
private String partnerTransactionId;

@XSample("DEPOSIT")
private String transactionType;

@XSample("BSC")
private String chainType;

@XSample("USDT")
private String currencyType;

@XSample("0x9876543210fedcba9876543210fedcba98765432")
private String fromAddress;

@XSample("0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18")
private String toAddress;

@XSample("100.00")
private BigDecimal amount;

@XSample("1408.45")
private BigDecimal priceKrw;

@XSample("1.00")
private BigDecimal priceUsd;

@XSample("0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890")
private String txHash;

@XSample("45678901")
private Long blockNumber;

@XSample("CONFIRMED")
private String status;

@XSample("true")
private Boolean partnerConfirmed;

@XSample("2026-04-02 14:35:00")
private LocalDateTime partnerConfirmedAt;

@XSample("user-001")
private String partnerUserId;

@XSample("0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18")
private String walletAddress;

@XSample("2026-04-02 14:30:00")
private LocalDateTime createdAt;

@XSample("2026-04-02 14:35:00")
private LocalDateTime confirmedAt;
```

### CurrencyPriceResponseV1.java

```java
@XSample("USDT")
private String currencyType;

@XSample("1408.45")
private BigDecimal priceKrw;

@XSample("1.0001")
private BigDecimal priceUsd;

@XSample("2026-04-02 14:30:00")
private LocalDateTime lastUpdated;
```

### CurrencyConversionResponse.java

```java
@XSample("KRW")
private String fromCurrency;

@XSample("USDT")
private String toCurrency;

@XSample("50000")
private BigDecimal fromAmount;

@XSample("35.50")
private BigDecimal toAmount;

@XSample("1408.45")
private BigDecimal exchangeRate;

@XSample("2026-04-02 14:30:00")
private LocalDateTime convertedAt;
```

### ExchangeRateResponse.java

```java
@XSample("USD")
private String baseCurrency;

@XSample("1714539600")
private long lastUpdated;
```

#### ExchangeRateResponse.RateInfo

```java
@XSample("1408.45")
private BigDecimal usdKrw;

@XSample("0.000710")
private BigDecimal krwUsd;
```

### WidgetTokenResponse.java

```java
@XSample("eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c2VyLTAwMSJ9.abc123")
private String accessToken;

@XSample("eyJhbGciOiJIUzI1NiJ9.eyJyZWYiOiJ1c2VyLTAwMSJ9.def456")
private String refreshToken;

@XSample("Bearer")
private String tokenType;

@XSample("7776000")
private Long expiresIn;

@XSample("DEPOSIT,WITHDRAWAL,BALANCE")
private String scope;
```

### WidgetConfigResponse.java

```java
@XSample("50000")
private BigDecimal presetAmount;

@XSample("1000")
private BigDecimal minAmount;

@XSample("10000000")
private BigDecimal maxAmount;

@XSample("50000000")
private BigDecimal dailyLimit;

@XSample("true")
private Boolean showBalance;

@XSample("ON_CHAIN")
private String balanceSource;

@XSample("false")
private Boolean usePartnerExchangeRate;

@XSample("true")
private Boolean allowAmountEdit;
```

### AuthResponse.java

```java
@XSample("true")
private boolean success;

@XSample("1")
private Long partnerId;

@XSample("파트너사")
private String partnerName;

@XSample("ACTIVE")
private String partnerStatus;

@XSample("2026-04-02 14:30:00")
private LocalDateTime authenticatedAt;

@XSample("2026-07-01 14:30:00")
private LocalDateTime expiresAt;
```

> `errorMessage` — 성공 응답 기준이므로 생략 (NON_NULL로 미출력)

### CallbackTestResponse.java

```java
@XSample("true")
private boolean success;

@XSample("200")
private Integer responseCode;

@XSample("OK")
private String responseMessage;

@XSample("2026-04-02 14:30:00")
private LocalDateTime sentAt;
```

### ChainActivationResponse.java

```java
@XSample("ETHEREUM")
private String chainType;

@XSample("Ethereum Mainnet")
private String chainName;

@XSample("true")
private Boolean isActive;

@XSample("2026-01-15 10:00:00")
private LocalDateTime activatedAt;
```

### SupportedChainResponse.java

```java
@XSample("BSC")
private String chainType;

@XSample("BNB Smart Chain")
private String name;

@XSample("BNB")
private String symbol;
```

> `tokens` (List<SupportedTokenInfo>) — 중첩 객체. 폴백으로 `[]` 생성.

#### SupportedChainResponse.SupportedTokenInfo

```java
@XSample("USDT")
private String currencyType;

@XSample("USDT")
private String symbol;

@XSample("0x55d398326f99059fF775485246999027B3197955")
private String contractAddress;

@XSample("18")
private Integer decimals;
```

### AximConnectionResponse.java

```java
@XSample("CONN-20260402-001")
private String connectId;

@XSample("cwt_abc123def456")
private String connectWalletToken;

@XSample("[{\"chainType\":\"BSC\",\"address\":\"0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18\"}]")
private String walletAddresses;

@XSample("CONNECTED")
private String status;

@XSample("2026-04-02 14:30:00")
private String createdAt;
```

### AximPaymentResponse.java

```java
@XSample("1001")
private Long paymentId;

@XSample("PAY-20260402-001")
private String paymentCode;

@XSample("5001")
private Long aximPaymentId;

@XSample("35.50")
private BigDecimal amount;

@XSample("50000")
private BigDecimal priceKrw;

@XSample("PENDING")
private String status;

@XSample("BSC")
private String chainType;

@XSample("0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18")
private String walletAddress;

@XSample("ORDER-20260402-001")
private String orderId;
```

### AximPaymentStatusResponse.java

```java
@XSample("1001")
private Long paymentId;

@XSample("COMPLETED")
private String status;
```

### AximInitInfoResponse.java

```java
@XSample("true")
private boolean enabled;

@XSample("SITE-001")
private String siteId;

@XSample("CONN-20260402-001")
private String connectId;

@XSample("파트너사")
private String partnerName;

@XSample("ak_live_abc123def456")
private String apiKey;

@XSample("ACTIVE")
private String status;

@XSample("1001")
private Long pendingPaymentId;
```

### CancelResponse.java

```java
@XSample("true")
private boolean success;
```

### PaymentLinkInfoResponse.java

```java
@XSample("LINK-20260402-001")
private String linkId;

@XSample("결제 요청")
private String title;

@XSample("35.50")
private BigDecimal amountCrypto;

@XSample("USDT")
private String currencyType;

@XSample("BSC")
private String chainType;

@XSample("1408.45")
private BigDecimal priceKrw;

@XSample("50000")
private BigDecimal calculatedKrwAmount;

@XSample("ACTIVE")
private String status;

@XSample("true")
private Boolean isUsable;

@XSample("eyJhbGciOiJIUzI1NiJ9.abc123")
private String accessToken;

@XSample("true")
private Boolean aximEnabled;

@XSample("true")
private Boolean aximConnected;

@XSample("SITE-001")
private String aximSiteId;
```

### WalletResponseV1.java

```java
@XSample("1001")
private Long id;

@XSample("0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18")
private String address;

@XSample("BSC")
private String chainType;

@XSample("HOT")
private String walletType;

@XSample("ACTIVE")
private String status;

@XSample("2026-04-02 14:30:00")
private LocalDateTime createdAt;
```

> `balances` (Map<String, String>) — 폴백으로 `{}` 생성.

---

## 적용 제외 DTO

| DTO | 사유 |
|-----|------|
| `AuthRequest` | 내부 인증용, 가이드 미노출 |
| `AximWebhookEvent` | Webhook 수신용, 파트너 API 아님 |
| `PaymentEventData` | Webhook 내부 데이터 |
| `ConnectionEventData` | Webhook 내부 데이터 |

---

## 적용 후 확인

1. `./gradlew :open-api:compileJava` — 컴파일 확인 (import 누락 체크)
2. Generator 실행하여 spec-bundle.json 재생성
3. spec-bundle.json에서 `requestSample`, `responseSample` 필드 확인
4. api.html 열어서 JSON 예시 렌더링 확인
