# UPBIT 서버 설정 가이드 (2026.03.15)

## 📁 프로젝트 구조

```
C:\laragon\www\site_user/
├── api/             # 백엔드 API 엔드포인트
├── includes/        # PHP 핵심 로직 (Betting.php, Auth.php 등)
├── assets/          # 정적 파일 (CSS, JS, 이미지)
├── auth/            # 로그인/회원가입
├── btc/             # 차트 iframe 페이지
├── mypage/          # 사용자 마이페이지
├── socket/          # Socket 서버 (포트 8081, 3001)
├── btc-server/      # BTC Chart 서버 (포트 9090)
├── frontend/        # Nuxt 프론트엔드 (포트 3000)
├── main.php         # 메인 게임 페이지 (PHP 버전)
└── index.php        # 인트로 페이지
```

## 🖥️ 서버 아키텍처

### 서버 구성
1. **BTC Chart Server** (포트 9090) - `btc-server/server.js`
   - Binance WebSocket에서 실시간 가격 수신
   - 라운드 생성/종료 관리 (권한 서버)
   - `chart_rounds` 테이블 사용

2. **Socket Server** (포트 3001, 8081) - `socket/server.js`
   - Socket.io로 클라이언트와 실시간 통신
   - 채팅, 배팅, 잔액 업데이트
   - BTC Chart Server에서 라운드 정보 수신
   - `game_rounds`, `betting_history` 테이블 사용

3. **Nuxt Frontend** (포트 3000) - `frontend/.output/server/index.mjs`
   - SSR 프론트엔드 메인 페이지
   - 프로덕션 빌드 실행

4. **Apache** (포트 80, 443)
   - 백엔드 PHP 처리
   - WebSocket 프록시
   - 정적 파일 서빙

## 🚀 서버 실행 방법

### 개발 모드
```bash
cd C:\laragon\www\site_user
start-all.bat
```

### 프로덕션 모드
```bash
cd C:\laragon\www\site_user
start-production.bat
```
- Frontend 빌드 자동 확인 및 실행
- 모든 서버를 프로덕션 모드로 시작

### Nuxt만 재빌드 및 재시작
```bash
cd C:\laragon\www\site_user
nuxt-rebuild.bat
```
- 기존 Nuxt 프로세스 자동 종료
- Frontend 빌드 후 프로덕션 실행
- 다른 서버(Socket, BTC Chart)는 유지

### 서버 종료
```bash
cd C:\laragon\www\site_user
stop-all.bat
```

### 개별 서버 실행
```bash
# BTC Chart Server
cd btc-server
node server.js

# Socket Server
cd socket
node server.js

# Nuxt Frontend (개발)
cd frontend
npm run dev

# Nuxt Frontend (프로덕션)
cd frontend
npm run build
node .output/server/index.mjs
```

## ⚙️ Apache 설정 (bitupgo.conf)

### 파일 위치
```
C:\laragon\etc\apache2\sites-enabled\bitupgo.conf
```

### 핵심 설정
```apache
<VirtualHost *:443>
    ServerName bitupgo.com
    ServerAlias www.bitupgo.com

    SSLEngine on
    SSLCertificateFile "C:/laragon/etc/ssl/laragon.crt"
    SSLCertificateKeyFile "C:/laragon/etc/ssl/laragon.key"

    # 백엔드 PHP 디렉토리 설정
    DocumentRoot "C:/laragon/www/site_user"
    <Directory "C:/laragon/www/site_user">
        AllowOverride All
        Require all granted
        Options -Indexes +FollowSymLinks
        DirectoryIndex disabled
    </Directory>

    # WebSocket Proxy Configuration
    ProxyRequests Off
    ProxyPreserveHost On
    ProxyTimeout 3600

    # Static assets은 직접 서빙
    ProxyPass /assets !

    # API 경로는 PHP로 처리 (ProxyPass 제외)
    ProxyPass /api !
    ProxyPass /auth !
    ProxyPass /mypage !
    ProxyPass /includes !
    ProxyPass /btc !

    # WebSocket 프록시
    RewriteEngine On

    # WebSocket 전용 경로는 일반 HTTP 요청 거부 (Vue Router 경고 방지)
    RewriteCond %{HTTP:Upgrade} !websocket [NC]
    RewriteRule ^/price-ws - [R=404,L]
    RewriteCond %{HTTP:Upgrade} !websocket [NC]
    RewriteRule ^/btc-chart - [R=404,L]

    # Socket.io (포트 3001) - WebSocket 지원
    RewriteCond %{HTTP:Upgrade} websocket [NC]
    RewriteCond %{HTTP:Connection} upgrade [NC]
    RewriteRule ^/socket.io/(.*)$ "ws://127.0.0.1:3001/socket.io/$1" [P,L]

    ProxyPass /socket.io/ http://127.0.0.1:3001/socket.io/ upgrade=websocket
    ProxyPassReverse /socket.io/ http://127.0.0.1:3001/socket.io/

    # Price WebSocket (포트 9090) - BTC Chart Server
    RewriteCond %{HTTP:Upgrade} websocket [NC]
    RewriteCond %{HTTP:Connection} upgrade [NC]
    RewriteRule ^/price-ws/?(.*)$ "ws://127.0.0.1:9090/$1" [P,L]

    ProxyPass /price-ws http://127.0.0.1:9090/ upgrade=websocket
    ProxyPassReverse /price-ws http://127.0.0.1:9090/

    # 나머지 요청은 Nuxt Frontend(3000)로 프록시
    ProxyPass / http://127.0.0.1:3000/
    ProxyPassReverse / http://127.0.0.1:3000/
</VirtualHost>
```

### 중요 포인트
1. **DirectoryIndex disabled** - index.php 자동 실행 방지 (Nuxt가 메인)
2. **ProxyPass 순서 중요** - 구체적인 경로가 먼저 와야 함
3. **upgrade=websocket** 옵션 필수
4. **RewriteCond로 Connection: upgrade 체크** 필요

## 🌐 Hosts 파일 설정

### 파일 위치
```
C:\Windows\System32\drivers\etc\hosts
```

### 추가할 내용
```
127.0.0.1      bitupgo.com
127.0.0.1      www.bitupgo.com
```

## 🗄️ 데이터베이스 테이블명

### Socket Server (socket/server.js)에서 사용하는 테이블
- `betting_history` (NOT `bets`)
- `game_rounds` (NOT `rounds`)
- `users`
- `chat_messages`
- `online_users`

### 테이블 구조 주요 차이점
**betting_history:**
- `result` 컬럼: `enum('pending','win','lose')` - `status` 컬럼 없음
- `profit` 컬럼: 수익/손실 금액
- `settled_at`: 정산 시간

**game_rounds:**
- `status`: `enum('waiting','betting','locked','settled')`
- `result`: `enum('UP','DOWN','DRAW')`
- `btc_round_id`: BTC Chart Server 라운드 ID 매핑

## 🔧 주요 수정 사항 (2026.03.15)

### 1. Console.log 제거
- `btc/js/script.js` - 앱 생명주기 로그 제거
- `main.php` - 31개 console.log 주석 처리
- `frontend/components/main/ChartSection.vue:646` - "[Socket] Bets update" 로그 제거

### 2. Socket Server 테이블명 수정
**파일:** `socket/server.js`

**변경:**
```javascript
// 기존
FROM bets b
INNER JOIN rounds r

// 수정
FROM betting_history b
INNER JOIN game_rounds r

// 기존
WHERE b.status = 'pending'

// 수정
WHERE b.result = 'pending'

// 기존
UPDATE bets SET status = 'settled', result = ?, payout = ?, profit = ?

// 수정
UPDATE betting_history SET result = ?, profit = ?
```

### 3. WebSocket 프록시 포트 수정
**문제:** `/price-ws`가 8081 포트(Socket Server)로 연결되어 있었음

**해결:** 9090 포트(BTC Chart Server)로 변경
- `/price-ws` → 9090 포트
- `upgrade=websocket` 옵션 추가
- `RewriteCond %{HTTP:Connection} upgrade` 조건 추가

### 4. 충전/입출금 UI 주석처리
**파일:**
- `frontend/components/layout/Header.vue`
  - 상단 충전 버튼 주석처리 (1026번 줄)
  - 사이드바 입/출금 메뉴 주석처리 (1152-1154번 줄)
- `frontend/pages/mypage/billing.vue`
  - 출금 영역 주석처리 (206-228번 줄)
  - 입/출금 내역 테이블 주석처리 (230-367번 줄)

**주의:** HTML 주석 중첩 불가 - 주석 안의 HTML 주석은 일반 텍스트로 변경

### 5. Vue Router 경고 수정
**문제:** `/price-ws`, `/btc-chart` 경로에 일반 HTTP 요청이 와서 Vue Router 경고 발생

**해결:** Apache RewriteRule로 WebSocket이 아닌 요청은 404 반환
```apache
RewriteCond %{HTTP:Upgrade} !websocket [NC]
RewriteRule ^/price-ws - [R=404,L]
RewriteCond %{HTTP:Upgrade} !websocket [NC]
RewriteRule ^/btc-chart - [R=404,L]
```

## 📌 트러블슈팅

### 차트가 "로딩중"에서 멈춤
**원인:** WebSocket 연결 실패

**해결:**
1. 서버 실행 확인
   ```bash
   netstat -ano | findstr ":9090"
   ```
2. Apache 프록시 설정 확인 (`upgrade=websocket` 옵션)
3. hosts 파일에 도메인 추가 확인

### Apache 재시작 방법
1. Laragon 열기
2. "Stop All" 클릭
3. "Start All" 클릭

### Node.js 프로세스 전체 종료
```bash
taskkill /F /IM node.exe
```

## 🔗 접속 URL

- **Frontend (Nuxt)**: https://bitupgo.com
- **BTC Chart**: https://bitupgo.com/btc/index.php
- **API**: https://bitupgo.com/api/
- **Admin**: https://ad.bitupgo.com
- **Partner**: https://pt.bitupgo.com

## 📝 참고사항

1. **관리자/파트너 페이지는 별도 관리** - site_user와 분리
2. **BTC Chart Server가 권한 서버** - 라운드 생성/종료 권한 보유
3. **Socket Server는 슬레이브** - BTC Chart에서 정보 수신
4. **Nuxt는 독립 서버** - Apache가 프록시만 함 (DocumentRoot에서 실행 안 됨)
5. **DirectoryIndex disabled** - 루트 경로(/)가 Nuxt로 프록시되도록 설정

## 🎯 배포 체크리스트

- [ ] Frontend 빌드 완료 (`npm run build`)
- [ ] 모든 Node.js 서버 실행 확인 (3000, 3001, 8081, 9090)
- [ ] Apache 재시작 완료
- [ ] hosts 파일에 도메인 추가 확인
- [ ] /btc/index.php 차트 정상 로딩 확인
- [ ] WebSocket 연결 확인 (F12 > Network > WS 탭)
- [ ] Console 에러 없는지 확인

---

# 📐 UPBIT 전체 시스템 구조 분석

## 1. 프로젝트 개요

UPBIT는 암호화폐 가격 움직임(UP/DOWN)을 예측하는 바이너리 옵션 게임 플랫폼입니다.

**핵심 특징:**
- 30초 주기 실시간 게임 (하루 2,880 라운드)
- 다층 파트너 계층 시스템 (수수료/롤링)
- 이원 월렛 시스템 (로컬 월렛 + 심리스 월렛)
- 실시간 WebSocket 통신
- Binance API 연동

**주요 구성:**
- **사용자 페이지** (`site_user`) - 게임 플레이, 마이페이지
- **관리자 페이지** (`site_adm`) - 사용자/파트너 관리, 통계
- **파트너 페이지** (`site_partner`) - 하위 회원 관리, 수수료 조회

## 2. 전체 디렉토리 구조

### 2.1 site_user (사용자 페이지)
```
C:\laragon\www\site_user/
├── api/                      # REST API 엔드포인트
│   ├── auth.php             # 인증 API
│   ├── bet.php              # 배팅 API
│   ├── user.php             # 사용자 정보
│   ├── game.php             # 게임 데이터
│   ├── chat.php             # 채팅
│   └── notifications.php    # 알림
├── includes/                 # 핵심 PHP 로직
│   ├── config.php           # 전역 설정
│   ├── database.php         # PDO DB 연결 + 헬퍼 함수
│   ├── Betting.php          # 배팅 시스템 핵심 클래스
│   ├── callback.php         # 심리스 월렛 콜백
│   ├── NotificationHelper.php # 알림 헬퍼
│   └── partner.php          # 파트너 계층 관리
├── socket/                   # Node.js WebSocket 서버
│   ├── server.js            # Socket.io 메인 (포트 3001, 8081)
│   └── binance-relay-server.js # (사용 안 함)
├── btc-server/              # BTC Chart 서버
│   └── server.js            # 차트 서버 (포트 9090)
├── frontend/                 # Nuxt 3 프론트엔드
│   ├── components/          # Vue 컴포넌트
│   ├── composables/         # Composables
│   ├── pages/               # Nuxt 페이지
│   └── layouts/             # 레이아웃
├── auth/                     # 인증 페이지 (PHP)
├── mypage/                   # 마이페이지 (PHP)
└── btc/                      # 차트 iframe (PHP)
```

### 2.2 site_adm (관리자 페이지)
```
C:\laragon\www\site_adm/
├── pages/
│   ├── members.php          # 사용자 관리
│   ├── partners.php         # 파트너 관리
│   ├── commission.php       # 커미션 관리
│   └── game_history.php     # 게임 히스토리
├── data/
│   ├── config.php          # 관리자 설정
│   └── connect.php         # DB 연결
└── index.php               # 대시보드
```

### 2.3 site_partner (파트너 페이지)
```
C:\laragon\www\site_partner/
├── pages/
│   ├── members.php         # 하위 회원 관리
│   ├── commission.php      # 수수료 현황
│   ├── callback.php        # 콜백 URL 설정
│   └── callback_logs.php   # 콜백 로그
├── data/
│   └── config.php
└── index.php               # 파트너 대시보드
```

## 3. 백엔드 핵심 구조

### 3.1 주요 API 엔드포인트 (api/)

| 파일 | 메서드 | 기능 |
|------|--------|------|
| `auth.php` | GET/POST | 인증 상태 확인 |
| `login.php` | POST | 로그인 |
| `bet.php` | POST | 배팅 요청 |
| `user.php` | GET/POST | 사용자 정보 |
| `game.php` | GET | 게임 데이터 조회 |
| `chat.php` | GET/POST | 채팅 메시지 |
| `notifications.php` | GET | 알림 조회 |

### 3.2 includes/ 핵심 클래스

**config.php - 전역 설정**
```php
SITE_NAME = 'BITUP'
SITE_URL = 동적 URL
SOCKET_URL = WebSocket 서버 URL
DB_HOST, DB_NAME, DB_USER, DB_PASS
```

**database.php - PDO 연결 + 헬퍼**
```php
// Singleton 패턴
Database::getInstance()
getDB() // PDO 연결

// 사용자 함수
getUserByUsername($username)
createUser(...)
updateUserBalance($userId, $amount)

// 배팅 함수
createBet(...)
settleBet(...)
getUserBettingHistory(...)

// 채팅, 알림, 온라인 사용자 등
```

**Betting.php - 배팅 시스템 핵심**
```php
class Betting {
    calculateRoundId($timestamp)      // 라운드 ID 계산
    getCurrentRound($autoCreate)      // 현재 라운드
    placeBet($userId, $betType, ...)  // 배팅
    lockRound($roundId, ...)          // 라운드 마감
    settleRound($roundId, ...)        // 정산
}
```

**callback.php - 심리스 월렛**
```php
class PartnerCallback {
    getBalance()                      // 잔액 조회
    debit($roundId, $amount, ...)     // 배팅 차감
    credit($roundId, $amount, ...)    // 당첨금 지급
}
```

## 4. 데이터베이스 구조

### 4.1 주요 테이블

**users** - 사용자 정보
```
id, username, password, email, nickname, avatar
balance (잔액)
parent_id (상위 파트너)
partner_level (계층)
is_partner
```

**game_rounds** - 게임 라운드
```
id, round_id (YYYYMMDDNNNN)
status (betting/locked/settled)
start_price, end_price
total_up_bet, total_down_bet
approved_up_bet, approved_down_bet
result (UP/DOWN/DRAW)
payout_rate (배당률)
```

**bet_attempts** - 배팅 기록
```
id, round_id, user_id
bet_type (UP/DOWN)
original_amount (요청 금액)
approved_amount (승인 금액)
returned_amount (반환 금액)
payout_amount (지급액)
result (win/lose)
status (pending/settled)
is_seamless (심리스 월렛 여부)
```

**user_hierarchy** - 계층 구조 (Closure Table)
```
ancestor_id (상위)
descendant_id (하위)
depth (0=본인, 1=직상위...)
```

**user_partner_settings** - 파트너 설정
```
user_id
partner_code (추천인 코드)
rolling_rate, commission_rate
callback_enabled
callback_balance_url
callback_debit_url
callback_credit_url
```

## 5. 배팅 시스템 플로우

### 5.1 전체 프로세스
```
1. placeBet() - 배팅 요청
   ├─ 로컬 월렛 (Admin 직하부)
   │  └─ 즉시 잔액 차감 → bet_attempts 기록
   └─ 심리스 월렛 (파트너 하부)
      └─ balance 콜백으로 잔액 확인
         → bet_attempts만 기록 (차감 나중)

2. lockRound() - 라운드 마감 (T+25초)
   ├─ UP/DOWN 총액 비교
   ├─ 매칭 금액 계산
   ├─ 초과분 반환 처리
   │  ├─ 로컬: 즉시 반환
   │  └─ 심리스: debit 콜백
   └─ status: betting → locked

3. settleRound() - 최종 정산 (T+30초)
   ├─ 승패 판정
   ├─ 당첨금 지급
   │  ├─ 로컬: 잔액 업데이트
   │  └─ 심리스: credit 콜백
   ├─ processCommission() - 수수료
   ├─ processRolling() - 롤링
   └─ status: locked → settled
```

### 5.2 라운드 ID 체계
```
형식: YYYYMMDDNNNN
예: 202603151234
    2026년 3월 15일 1234번째 라운드

계산: floor(시간_초 / 30) % 2880
하루 2,880개 라운드 (24시간 * 60분 * 2)
```

## 6. 이원 월렛 시스템

### 6.1 로컬 월렛
- **대상:** Admin 직하부 사용자
- **특징:** DB에서 직접 잔액 관리
- **플로우:**
  1. 배팅 시 즉시 차감
  2. 마감 시 초과분 반환
  3. 정산 시 당첨금 지급

### 6.2 심리스 월렛
- **대상:** 파트너 하부 사용자
- **특징:** 파트너 시스템이 잔액 관리, HTTP 콜백으로 통신
- **필요한 콜백 URL:**
  - `callback_balance_url` - 잔액 조회
  - `callback_debit_url` - 차감
  - `callback_credit_url` - 지급
  - `callback_cancel_url` - 취소

**콜백 요청 예시:**
```php
// debit (배팅 차감)
POST callback_debit_url
Body: {
  user_id, round_id, amount, tx_id
}
Response: {
  success: true,
  balance: 새로운_잔액
}
```

## 7. 서버 구조 및 통신

### 7.1 서버 구성
```
┌─────────────────────────────┐
│   Binance API (BTCUSDT)     │
└──────────────┬──────────────┘
               │
    ┌──────────▼────────────┐
    │  BTC Chart Server     │ (포트 9090)
    │  - 가격 수신/저장     │
    │  - 라운드 관리        │
    └──────────┬────────────┘
               │ HTTP API
    ┌──────────▼────────────┐
    │  Socket.io Server     │ (포트 3001, 8081)
    │  - 실시간 이벤트      │
    │  - 라운드 자동화      │
    │  - 채팅               │
    └──────────┬────────────┘
               │ WebSocket
       ┌───────┴───────┐
   ┌───▼───┐      ┌────▼─────┐
   │ Nuxt  │      │  PHP     │
   │(3000) │      │ Backend  │
   └───────┘      └──────────┘
```

### 7.2 Socket.io 서버 주요 이벤트
```javascript
// 브로드캐스트
'price:update'      // 가격 업데이트 (100ms 스로틀)
'round:update'      // 라운드 정보
'round:tick'        // 타이머
'balance:update'    // 잔액
'results:update'    // 최근 결과
'chat:message'      // 채팅
'bets:update'       // 배팅 현황
```

## 8. 수수료 및 롤링 시스템

### 8.1 수수료 (Commission)
```
실제 수수료 = 나의 수수료율 - 하위의 수수료율

예시:
Admin: 30%
  └─ Partner A: 20%
      └─ User B: 10%

Admin 수수료: 30% - 20% = 10%
Partner A 수수료: 20% - 10% = 10%
User B 수수료: 10% - 0% = 10%
```

**처리:** `settleRound()` → `processCommission()`

### 8.2 롤링 (Rolling)
- **정의:** 배팅액에 대한 보너스
- **처리:** `settleRound()` → `processRolling()`
- **대상:** 배팅 사용자

## 9. 관리자/파트너 페이지 기능

### 9.1 관리자 페이지 (site_adm)
- 사용자 생성/수정/정지
- 파트너 설정 (수수료율, 콜백 URL)
- 게임 히스토리 조회
- 통계 및 대시보드
- 공지사항 발송

### 9.2 파트너 페이지 (site_partner)
- 하위 회원 조회/통계
- 초대 코드 생성
- 수수료/롤링 현황
- 콜백 URL 설정
- 콜백 로그 확인

## 10. 프론트엔드 구조 (Nuxt 3)

### 10.1 주요 Composables
```typescript
useAuth()       // 인증
useSocket()     // WebSocket
useGame()       // 게임 데이터
useBalance()    // 잔액
useChat()       // 채팅
```

### 10.2 주요 컴포넌트
```
components/
├── layout/
│   ├── Header.vue          // 상단바 (잔액, 알림)
│   └── Sidebar.vue         // 사이드바 (채팅, 메뉴)
├── main/
│   ├── GameBoard.vue       // 게임판
│   ├── BettingPanel.vue    // 배팅 버튼
│   ├── ChartSection.vue    // 차트
│   └── ResultHistory.vue   // 결과 히스토리
└── common/
    └── Modal.vue           // 공통 모달
```

## 11. 보안 및 검증

### 11.1 보안 조치
- PDO 프리페어드 스테이트먼트 (SQL 인젝션 방지)
- 세션 기반 인증 (Secure, HttpOnly)
- CORS 화이트리스트
- password_hash/verify (비밀번호)
- 트랜잭션으로 데이터 일관성 보장

### 11.2 배팅 검증
```php
// placeBet() 내부 검증
- 라운드 상태 확인 (betting만 허용)
- 잔액 확인
- 최소/최대 배팅액 검증
- 중복 배팅 방지
```

## 12. 파일 경로 참조

**핵심 파일:**
- `C:\laragon\www\site_user\includes\Betting.php` - 배팅 로직
- `C:\laragon\www\site_user\includes\database.php` - DB 헬퍼
- `C:\laragon\www\site_user\socket\server.js` - WebSocket 서버
- `C:\laragon\www\site_user\btc-server\server.js` - 차트 서버
- `C:\laragon\www\site_adm\pages\members.php` - 관리자 페이지
- `C:\laragon\www\site_partner\pages\callback.php` - 파트너 콜백

---

**다음 작업을 위한 주요 포인트:**
- 배팅 시스템은 `Betting.php` 클래스에 집중
- WebSocket 이벤트는 `socket/server.js`에서 관리
- 심리스 월렛은 `includes/callback.php` 참조
- 계층 구조는 `user_hierarchy` 테이블 (Closure Table 패턴)
