# 파트너 자동 회원가입 기능 (2026-03-15 추가)

## ✅ 수정 완료

**파일:** `api/partner.php` (login 액션)

**기능:** 로그인 시 사용자가 없으면 **자동으로 회원가입 후 토큰 반환**

---

## 🔄 작동 방식

### **기존 (수정 전):**
```
파트너 → login API 호출
    ↓
사용자 없음?
    ↓
❌ "Invalid credentials" 에러
```

### **현재 (수정 후):**
```
파트너 → login API 호출
    ↓
사용자 없음?
    ↓
✅ 자동 회원가입 (파트너 하부로)
    ↓
✅ 토큰 생성 및 반환
    ↓
파트너 → iframe에 login_url 삽입
```

---

## 📡 API 사용법

### **엔드포인트:**
```
POST /api/partner.php?action=login
```

### **Request Headers:**
```
Content-Type: application/json
X-Partner-Key: {YOUR_SECRET_KEY}
```

### **Request Body:**
```json
{
  "user_id": "player001",
  "user_pw": "password123",
  "nickname": "플레이어001"
}
```

| 파라미터 | 타입 | 필수 | 설명 |
|---------|------|------|------|
| user_id | string | ✅ | 사용자 아이디 (4~20자, 영문/숫자/밑줄) |
| user_pw | string | ✅ | 비밀번호 (6자 이상) |
| nickname | string | ⬜ | 게임 닉네임 (없으면 user_id 사용) |

### **Response:**
```json
{
  "success": true,
  "login_url": "https://bitupgo.com/auth/token_login.php?token=abc123...",
  "expires_in": 60
}
```

---

## 🎯 플로우 상세

### **Case 1: 신규 사용자 (자동 가입)**

```
1. 파트너 서버에서 login API 호출
   POST /api/partner.php?action=login
   Body: { user_id: "newuser", user_pw: "pass123" }

2. UPBIT 시스템 처리:
   - users 테이블에서 "newuser" 검색
   - ❌ 없음
   - ✅ register() 함수 호출
   - 파트너 코드로 자동 가입
   - parent_id = 파트너 ID
   - 초기 잔액 100,000원 지급
   - user_hierarchy에 추가

3. 토큰 생성:
   - login_tokens 테이블에 저장
   - 60초 유효

4. 응답:
   { "success": true, "login_url": "..." }
```

### **Case 2: 기존 사용자 (로그인)**

```
1. 파트너 서버에서 login API 호출
   POST /api/partner.php?action=login
   Body: { user_id: "existinguser", user_pw: "pass123" }

2. UPBIT 시스템 처리:
   - users 테이블에서 "existinguser" 검색
   - ✅ 있음
   - 비밀번호 확인 (password_verify)
   - ✅ 일치

3. 토큰 생성 및 반환
```

### **Case 3: 비밀번호 오류**

```
1. 파트너 서버에서 login API 호출
   POST /api/partner.php?action=login
   Body: { user_id: "existinguser", user_pw: "wrongpass" }

2. UPBIT 시스템 처리:
   - users 테이블에서 "existinguser" 검색
   - ✅ 있음
   - 비밀번호 확인
   - ❌ 불일치

3. 에러 응답:
   { "success": false, "error": "Invalid password" }
```

---

## 💻 파트너 서버 구현 예제

### **PHP 예제:**

```php
<?php
// 파트너 서버: partner.com/launch_upbit_game.php

$partnerKey = 'your_secret_key_from_upbit';
$userId = $_SESSION['user_id'];      // 파트너 사이트 로그인 사용자
$nickname = $_SESSION['nickname'];

// UPBIT login API 호출
$ch = curl_init('https://bitupgo.com/api/partner.php?action=login');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => json_encode([
        'user_id' => $userId,
        'user_pw' => hash('sha256', $userId . 'secret_salt'), // 일관된 비밀번호
        'nickname' => $nickname
    ]),
    CURLOPT_HTTPHEADER => [
        'Content-Type: application/json',
        'X-Partner-Key: ' . $partnerKey
    ],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_SSL_VERIFYPEER => false
]);

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

$result = json_decode($response, true);

if ($result['success']) {
    // 성공: iframe으로 게임 론칭
    $loginUrl = $result['login_url'];
    ?>
    <iframe src="<?= htmlspecialchars($loginUrl) ?>"
            width="100%"
            height="800"
            frameborder="0"></iframe>
    <?php
} else {
    echo "게임 론칭 실패: " . $result['error'];
}
?>
```

### **JavaScript 예제:**

```javascript
// 파트너 서버: partner.com/static/js/upbit-launcher.js

async function launchUpbitGame(userId, nickname) {
    const partnerKey = 'your_secret_key_from_upbit';

    try {
        const response = await fetch('https://bitupgo.com/api/partner.php?action=login', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'X-Partner-Key': partnerKey
            },
            body: JSON.stringify({
                user_id: userId,
                user_pw: hashPassword(userId), // 일관된 비밀번호 생성
                nickname: nickname
            })
        });

        const result = await response.json();

        if (result.success) {
            // 새 창으로 게임 론칭
            window.open(result.login_url, 'upbit_game', 'width=1200,height=800');
        } else {
            alert('게임 론칭 실패: ' + result.error);
        }
    } catch (error) {
        console.error('UPBIT API Error:', error);
        alert('네트워크 오류가 발생했습니다.');
    }
}

function hashPassword(userId) {
    // 일관된 비밀번호 생성 (예: SHA256)
    return CryptoJS.SHA256(userId + 'secret_salt').toString();
}

// 사용 예
document.getElementById('playUpbitBtn').addEventListener('click', () => {
    launchUpbitGame('player001', '플레이어001');
});
```

---

## 🔒 비밀번호 관리 전략

### **방법 1: 사용자 ID 기반 해시 (권장)**

```php
// 파트너 서버
$password = hash('sha256', $userId . 'your_secret_salt');

// 장점: 일관성 있음, 간단함
// 단점: 같은 userId면 항상 같은 비밀번호
```

### **방법 2: 파트너 DB에 저장**

```sql
-- 파트너 서버 DB
CREATE TABLE upbit_users (
    local_user_id INT,
    upbit_user_id VARCHAR(50),
    upbit_password VARCHAR(255),
    created_at TIMESTAMP
);

-- 첫 생성 시 랜덤 비밀번호 저장
-- 이후 사용 시 조회
```

### **방법 3: 토큰 기반 (비밀번호 불필요)**

현재는 `user_pw` 필수지만, 추후 토큰만으로 인증하도록 확장 가능

---

## 🎮 전체 시나리오 예제

### **파트너 사이트: 온라인 카지노**

```
1. 사용자가 카지노 로그인 (casino.com)
   - 로컬 ID: user_12345
   - 닉네임: "럭키777"

2. 카지노 메인 페이지에서 "UPBIT 게임" 버튼 클릭

3. 카지노 서버:
   POST https://bitupgo.com/api/partner.php?action=login
   {
     "user_id": "casino_user_12345",  // prefix로 충돌 방지
     "user_pw": "sha256(...)",
     "nickname": "럭키777"
   }

4. UPBIT:
   - "casino_user_12345" 없음
   - 자동 회원가입
   - 카지노 파트너 하부로 등록
   - 토큰 생성: "abc123..."

5. UPBIT 응답:
   {
     "success": true,
     "login_url": "https://bitupgo.com/auth/token_login.php?token=abc123..."
   }

6. 카지노 프론트엔드:
   <iframe src="https://bitupgo.com/auth/token_login.php?token=abc123..."></iframe>

7. 사용자는 자동 로그인되어 UPBIT 게임 플레이

8. 배팅 시:
   UPBIT → 카지노 서버 debit 콜백
   카지노 잔액 차감

9. 당첨 시:
   UPBIT → 카지노 서버 credit 콜백
   카지노 잔액 증가
```

---

## 📊 자동 생성된 사용자 정보

### **users 테이블:**
```sql
username:       "casino_user_12345"
password:       (bcrypt hash)
nickname:       "럭키777"
avatar:         "03" (랜덤 01~06)
balance:        100000 (초기 잔액)
parent_id:      {파트너 ID}
partner_level:  {파트너 레벨 + 1}
is_partner:     0
is_active:      1
```

### **user_hierarchy 테이블:**
```sql
-- 자기 자신
ancestor_id:    {user_id}
descendant_id:  {user_id}
depth:          0

-- 파트너 연결
ancestor_id:    {partner_id}
descendant_id:  {user_id}
depth:          1

-- Admin 연결
ancestor_id:    {admin_id}
descendant_id:  {user_id}
depth:          2
```

### **user_partner_settings 테이블:**
```sql
user_id:            {user_id}
rolling_rate:       {파트너의 default_sub_rolling}
commission_rate:    {파트너의 default_sub_commission}
can_invite:         0 (초대 불가)
partner_code:       "CASINO_USER_12345" (대문자 변환)
```

---

## ⚠️ 주의사항

### **1. 사용자 ID 충돌 방지**

여러 파트너가 같은 user_id 사용 시 충돌 가능

**해결책:**
```javascript
// 파트너별 prefix 사용
const userId = `partner_${partnerId}_${localUserId}`;

// 예:
"casino_user_12345"
"sports_user_67890"
```

### **2. 비밀번호 일관성**

같은 사용자가 여러 번 호출 시 **같은 비밀번호** 사용해야 함

**해결책:**
```php
// 일관된 해시 사용
$password = hash('sha256', $userId . 'fixed_salt');
```

### **3. 토큰 만료 시간**

토큰은 **60초 유효**

**해결책:**
```javascript
// 즉시 iframe 생성
if (result.success) {
    window.open(result.login_url);  // 바로 열기
}
```

### **4. X-Partner-Key 보안**

Secret Key가 노출되면 누구나 회원 생성 가능

**해결책:**
- 서버 사이드에서만 호출
- HTTPS 필수
- Key 주기적 갱신

---

## 🧪 테스트 방법

### **1. 파트너 계정 생성**

```sql
-- 관리자 DB에서
INSERT INTO users (username, password, nickname, is_partner)
VALUES ('test_partner', '$2y$10$...', 'Test Partner', 1);

INSERT INTO user_partner_settings (user_id, partner_code, can_invite, callback_secret_key)
VALUES (LAST_INSERT_ID(), 'TESTPARTNER', 1, 'test_secret_key_12345');
```

### **2. curl로 테스트**

```bash
curl -X POST https://bitupgo.com/api/partner.php?action=login \
  -H "Content-Type: application/json" \
  -H "X-Partner-Key: test_secret_key_12345" \
  -d '{
    "user_id": "testuser001",
    "user_pw": "password123",
    "nickname": "테스트유저"
  }'
```

**예상 응답:**
```json
{
  "success": true,
  "login_url": "https://bitupgo.com/auth/token_login.php?token=abcdef123456...",
  "expires_in": 60
}
```

### **3. 브라우저에서 확인**

```
1. 응답의 login_url 복사
2. 새 브라우저 탭에서 열기
3. 자동 로그인 → main.php로 리다이렉트
4. 잔액 100,000원 확인
```

### **4. DB 확인**

```sql
-- 사용자 생성 확인
SELECT * FROM users WHERE username = 'testuser001';

-- 계층 구조 확인
SELECT * FROM user_hierarchy WHERE descendant_id = (
    SELECT id FROM users WHERE username = 'testuser001'
);

-- 파트너 설정 확인
SELECT * FROM user_partner_settings WHERE user_id = (
    SELECT id FROM users WHERE username = 'testuser001'
);
```

---

## 📈 API 문서 업데이트

**파일:** `UPBIT_API_Documentation_v2.0_2026-03-15.md`

**7.1 Get Login Token** 섹션에 추가:

```markdown
### 자동 회원가입

사용자가 UPBIT에 없으면 **자동으로 회원가입 후 토큰 반환**

**플로우:**
1. 파트너 하부로 사용자 생성
2. 초기 잔액 100,000원 지급
3. 토큰 생성 및 반환

**Request Body (추가 파라미터):**
- `nickname`: 선택적, 없으면 user_id 사용

**초기 설정:**
- 아바타: 랜덤 (01~06)
- 잔액: 100,000원
- 수수료율: 파트너의 default_sub_rolling/commission
```

---

## ✅ 완료 체크리스트

- [x] `api/partner.php` login 액션 수정
- [x] 자동 회원가입 로직 추가
- [x] nickname 파라미터 추가
- [x] 에러 처리 강화
- [x] 가이드 문서 작성
- [ ] API 문서 업데이트 (필요 시)
- [ ] 프로덕션 테스트

---

**수정일:** 2026-03-15
**수정 파일:** `api/partner.php`
**추가 기능:** 자동 회원가입 (없으면 생성)
