# TanSparks Trade — PHP Backend Documentation

> **Version:** 1.0.0  
> **Stack:** PHP 8.1+ · MySQL 8.0+ · Apache/Nginx  
> **Auth:** JWT Bearer tokens (HS256, 24 h expiry)

---

## Table of Contents

1. [Server Requirements](#1-server-requirements)
2. [Installation](#2-installation)
3. [Configuration](#3-configuration)
4. [Directory Structure](#4-directory-structure)
5. [Authentication](#5-authentication)
6. [API Reference](#6-api-reference)
   - [Auth](#61-auth)
   - [Wallets](#62-wallets)
   - [Trades](#63-trades)
   - [Transactions](#64-transactions)
   - [Profiles](#65-profiles)
   - [Notifications](#66-notifications)
   - [Support Tickets & Messages](#67-support-tickets--messages)
   - [Levels & Claims](#68-levels--claims)
   - [Announcements](#69-announcements)
   - [Deposit Coins & Chains](#610-deposit-coins--chains)
   - [Currencies](#611-currencies)
   - [Trading Pairs](#612-trading-pairs)
   - [Platform Settings](#613-platform-settings)
   - [Admin](#614-admin)
   - [Login Activity](#615-login-activity)
   - [File Uploads](#616-file-uploads)
   - [Telegram Notifications](#617-telegram-notifications)
   - [Binance Proxy](#618-binance-proxy)
   - [Server-Sent Events (SSE)](#619-server-sent-events-sse)
7. [Database Schema](#7-database-schema)
8. [CORS](#8-cors)
9. [Error Handling](#9-error-handling)
10. [Frontend Integration](#10-frontend-integration)

---

## 1. Server Requirements

| Requirement | Minimum |
|---|---|
| PHP | 8.1+ |
| MySQL | 8.0+ (or MariaDB 10.6+) |
| Web Server | Apache 2.4+ with `mod_rewrite` **or** Nginx |
| PHP Extensions | `pdo`, `pdo_mysql`, `curl`, `fileinfo`, `mbstring`, `json` |
| Disk space | 100 MB + uploads |

---

## 2. Installation

### Step 1 — Clone or upload files

Upload the `php-backend/` directory to your web server's document root (e.g. `/var/www/html/api/`).

### Step 2 — Create the database

```bash
mysql -u root -p < database/schema.sql
```

Or open **phpMyAdmin → Import** and upload `database/schema.sql`. This creates:

- The `tradex_db` database
- All 16 tables
- Default platform settings

### Step 3 — Configure database credentials

Edit **`config/database.php`**:

```php
private $host     = "localhost";       // DB host
private $db_name  = "tradex_db";       // DB name
private $username = "your_db_user";    // DB user
private $password = "your_db_pass";    // DB password
```

### Step 4 — Set JWT secret

Edit **`config/jwt.php`**:

```php
define('JWT_SECRET', 'a-strong-random-secret-at-least-32-chars');
```

> ⚠️ **Change this in production!** Use `openssl rand -hex 32` to generate a strong secret.

### Step 5 — Set directory permissions

```bash
chmod -R 755 php-backend/
chmod -R 777 php-backend/uploads/
chmod -R 777 php-backend/cache/
```

### Step 6 — Apache virtual host (recommended)

```apache
<VirtualHost *:443>
    ServerName api.yourdomain.com
    DocumentRoot /var/www/html/php-backend

    <Directory /var/www/html/php-backend>
        AllowOverride All
        Require all granted
    </Directory>
</VirtualHost>
```

### Step 7 — Nginx config (alternative)

```nginx
server {
    listen 443 ssl;
    server_name api.yourdomain.com;
    root /var/www/html/php-backend;
    index index.php;

    location / {
        try_files $uri $uri/ =404;
    }

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass unix:/run/php/php8.1-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

    location /uploads/ {
        expires 30d;
        add_header Cache-Control "public, immutable";
    }
}
```

### Step 8 — Update the frontend

Set the `VITE_API_URL` environment variable (or update `.env`):

```
VITE_API_URL=https://api.yourdomain.com/api
```

### Step 9 — Create the first admin

1. Register a normal account via the API
2. In MySQL, update the role:

```sql
UPDATE user_roles SET role = 'admin' WHERE user_id = '<your-user-id>';
```

---

## 3. Configuration

### config/database.php

- Sets CORS headers globally (`Access-Control-Allow-Origin: *`)
- Provides a `Database` class with `getConnection()` → returns PDO instance
- PDO is configured with `ERRMODE_EXCEPTION` and UTF-8

### config/jwt.php

| Function | Description |
|---|---|
| `generateJWT($user_id, $email, $role)` | Creates a signed JWT (24 h expiry) |
| `verifyJWT($token)` | Verifies signature & expiry, returns payload or `null` |
| `getAuthUser()` | Extracts JWT from `Authorization: Bearer <token>` header |
| `requireAuth()` | Returns user payload or aborts with `401` |
| `requireAdmin()` | Returns admin payload or aborts with `403` |

### JWT Payload Structure

```json
{
  "user_id": "abc123...",
  "email": "user@example.com",
  "role": "user",
  "iat": 1700000000,
  "exp": 1700086400
}
```

---

## 4. Directory Structure

```
php-backend/
├── .htaccess                 # Apache rewrite rules & security
├── config/
│   ├── database.php          # PDO connection + CORS
│   └── jwt.php               # JWT sign/verify helpers
├── database/
│   └── schema.sql            # Full MySQL schema
├── api/
│   ├── auth/
│   │   ├── login.php         # POST - User login
│   │   └── register.php      # POST - User registration
│   ├── wallets/
│   │   ├── read.php          # GET  - Get wallet balance
│   │   └── update.php        # PUT  - Update wallet fields
│   ├── trades/
│   │   ├── create.php        # POST - Place a trade
│   │   ├── read.php          # GET  - List user trades
│   │   └── update.php        # PUT  - Settle/update trade
│   ├── transactions/
│   │   ├── create.php        # POST - Create transaction
│   │   └── read.php          # GET  - List transactions
│   ├── profiles/
│   │   ├── read.php          # GET  - Get user profile
│   │   └── update.php        # PUT  - Update profile
│   ├── notifications/
│   │   └── read.php          # GET  - List notifications
│   ├── support/
│   │   ├── tickets.php       # GET/POST/PUT - Manage tickets
│   │   └── messages.php      # GET/POST - Ticket messages
│   ├── levels/
│   │   ├── configs.php       # CRUD - Level configurations
│   │   └── claims.php        # GET/POST - Level reward claims
│   ├── announcements/
│   │   ├── read.php          # GET  - Active announcements
│   │   └── manage.php        # CRUD - Admin announcement management
│   ├── deposits/
│   │   ├── coins.php         # CRUD - Deposit coins
│   │   └── chains.php        # CRUD - Deposit chains/networks
│   ├── currencies/
│   │   └── manage.php        # CRUD - Fiat currencies
│   ├── trading-pairs/
│   │   └── manage.php        # CRUD - Trading pairs
│   ├── settings/
│   │   ├── read.php          # GET  - Platform settings
│   │   └── update.php        # POST - Update settings (admin)
│   ├── admin/
│   │   ├── users.php         # GET/PUT - User management
│   │   ├── transactions.php  # GET/PUT - Transaction management
│   │   ├── stats.php         # GET  - Dashboard statistics
│   │   └── audit-log.php     # GET  - Admin action log
│   ├── login-activity/
│   │   └── read.php          # GET  - Login history
│   ├── uploads/
│   │   ├── avatar.php        # POST/DELETE - Avatar upload
│   │   ├── kyc.php           # POST - KYC document upload
│   │   └── pwa-assets.php    # POST - PWA icon upload (admin)
│   ├── telegram/
│   │   └── notify.php        # POST - Send Telegram notifications
│   ├── binance/
│   │   └── proxy.php         # GET  - Binance API proxy with caching
│   └── sse/
│       ├── stream.php        # SSE  - User real-time stream
│       └── admin-stream.php  # SSE  - Admin real-time stream
├── uploads/
│   ├── .htaccess             # Deny PHP execution in uploads
│   ├── avatars/              # User avatar files
│   ├── kyc/                  # KYC documents
│   └── pwa/                  # PWA icons
└── cache/
    └── binance/              # Binance API response cache (auto-created)
```

---

## 5. Authentication

All authenticated endpoints require the `Authorization` header:

```
Authorization: Bearer <jwt_token>
```

| Auth Level | Description |
|---|---|
| **None** | Public endpoint, no token needed |
| **User** | Any valid JWT (`requireAuth()`) |
| **Admin** | JWT with `role: "admin"` (`requireAdmin()`) |

### Token Lifecycle

1. **Obtain** — `POST /api/auth/login.php` or `POST /api/auth/register.php` returns `{ "token": "..." }`
2. **Use** — Send as `Authorization: Bearer <token>` on every authenticated request
3. **Expiry** — Tokens expire after **24 hours**; client must re-login
4. **Storage** — Frontend stores in `localStorage` as `auth_token`

---

## 6. API Reference

### Base URL

```
https://api.yourdomain.com/api
```

All request/response bodies are **JSON** unless noted otherwise (file uploads use `multipart/form-data`).

---

### 6.1 Auth

#### POST `/auth/register.php` — Register

**Auth:** None

**Request:**
```json
{
  "email": "user@example.com",
  "password": "securePass123",
  "referral_code": "abc123"     // optional
}
```

**Response** `200`:
```json
{
  "token": "eyJhbGciOi...",
  "user": {
    "id": "a1b2c3d4...",
    "email": "user@example.com"
  }
}
```

**Errors:**
| Status | Body |
|---|---|
| `400` | `{"error": "Email and password required"}` |
| `409` | `{"error": "User already exists"}` |

**Side effects:**
- Creates `users`, `profiles`, `wallets`, `user_roles` records
- If valid `referral_code` is provided and referrals are enabled, applies bonus to both referrer and referee wallets

---

#### POST `/auth/login.php` — Login

**Auth:** None

**Request:**
```json
{
  "email": "user@example.com",
  "password": "securePass123"
}
```

**Response** `200`:
```json
{
  "token": "eyJhbGciOi...",
  "user": {
    "id": "a1b2c3d4...",
    "email": "user@example.com",
    "role": "user"
  }
}
```

**Errors:**
| Status | Body |
|---|---|
| `400` | `{"error": "Email and password required"}` |
| `401` | `{"error": "Invalid credentials"}` |
| `403` | `{"error": "Account is blocked"}` |

**Side effects:**
- Logs entry in `login_activity` table with IP and user agent

---

### 6.2 Wallets

#### GET `/wallets/read.php` — Get wallet

**Auth:** User

**Response** `200`:
```json
{
  "id": "uuid",
  "user_id": "uuid",
  "balance": "1250.50",
  "demo_balance": "50000.00",
  "force_next_result": null,
  "created_at": "2025-01-01 00:00:00",
  "updated_at": "2025-01-15 12:00:00"
}
```

---

#### PUT `/wallets/update.php` — Update wallet

**Auth:** User

**Request:**
```json
{
  "balance": 1300.00,
  "demo_balance": 48000.00,
  "force_next_result": "win"
}
```

All fields are optional. Only provided fields are updated.

**Response** `200`:
```json
{ "success": true }
```

---

### 6.3 Trades

#### POST `/trades/create.php` — Place a trade

**Auth:** User

**Request:**
```json
{
  "amount": 100,
  "direction": "up",
  "pair": "BTC/USDT",
  "expiry_seconds": 60,
  "entry_price": 66500.00,
  "payout_percent": 85,
  "is_demo": true
}
```

| Field | Type | Required | Description |
|---|---|---|---|
| `amount` | number | ✅ | Trade amount (deducted from balance) |
| `direction` | string | ✅ | `"up"` or `"down"` |
| `pair` | string | ✅ | Trading pair label |
| `expiry_seconds` | int | ✅ | Duration in seconds |
| `entry_price` | number | ✅ | Price at trade entry |
| `payout_percent` | number | ❌ | Payout % (default: 85) |
| `is_demo` | bool | ❌ | Demo mode (default: true) |

**Response** `200`:
```json
{ "id": "trade-uuid", "status": "active" }
```

**Errors:**
| Status | Body |
|---|---|
| `400` | `{"error": "Invalid trade parameters"}` |
| `400` | `{"error": "Insufficient balance"}` |

---

#### GET `/trades/read.php` — List trades

**Auth:** User

**Query params:**
| Param | Type | Default | Description |
|---|---|---|---|
| `status` | string | all | Filter: `active`, `won`, `lost` |
| `is_demo` | string | all | `"true"` or `"false"` |
| `limit` | int | 50 | Max results |

**Response** `200`: Array of trade objects.

---

#### PUT `/trades/update.php` — Settle a trade

**Auth:** User

**Request:**
```json
{
  "id": "trade-uuid",
  "status": "won",
  "exit_price": 66800.00,
  "profit": 85.00,
  "ended_at": "2025-01-15T12:01:00Z"
}
```

Updatable fields: `status`, `exit_price`, `profit`, `ended_at`

---

### 6.4 Transactions

#### POST `/transactions/create.php` — Create transaction

**Auth:** User

**Request:**
```json
{
  "type": "deposit",
  "amount": 500.00,
  "status": "pending",
  "description": "USDT TRC20 deposit"
}
```

| Field | Type | Required | Description |
|---|---|---|---|
| `type` | string | ✅ | `deposit`, `withdrawal`, `transfer` |
| `amount` | number | ✅ | Amount |
| `status` | string | ❌ | Default: `pending` |
| `description` | string | ❌ | Free text |

---

#### GET `/transactions/read.php` — List transactions

**Auth:** User

**Query params:**
| Param | Type | Default |
|---|---|---|
| `type` | string | all |
| `limit` | int | 50 |

---

### 6.5 Profiles

#### GET `/profiles/read.php` — Get profile

**Auth:** User

Returns the authenticated user's profile including `display_name`, `avatar_url`, `referral_code`, `kyc_status`, `language`, `is_blocked`.

---

#### PUT `/profiles/update.php` — Update profile

**Auth:** User

**Request:**
```json
{
  "display_name": "John Doe",
  "language": "es"
}
```

---

### 6.6 Notifications

#### GET `/notifications/read.php` — List notifications

**Auth:** User

Returns notifications for the authenticated user, ordered by most recent.

---

### 6.7 Support Tickets & Messages

#### Tickets — `/support/tickets.php`

| Method | Auth | Description |
|---|---|---|
| `GET` | User | List user's own tickets (admin sees all) |
| `POST` | User | Create a new ticket |
| `PUT` | User | Update ticket status |

**POST Request:**
```json
{
  "subject": "Cannot withdraw funds"
}
```

**PUT Request:**
```json
{
  "id": "ticket-uuid",
  "status": "closed"
}
```

#### Messages — `/support/messages.php`

| Method | Auth | Query/Body |
|---|---|---|
| `GET` | User | `?ticket_id=<uuid>` |
| `POST` | User | `{ "ticket_id": "uuid", "message": "text" }` |

Admin messages are flagged with `is_admin: true` automatically.

---

### 6.8 Levels & Claims

#### Level Configs — `/levels/configs.php`

| Method | Auth | Description |
|---|---|---|
| `GET` | None | List all level configurations |
| `POST` | Admin | Create level config |
| `PUT` | Admin | Update level config |
| `DELETE` | Admin | `?id=<uuid>` — Delete level config |

**POST/PUT Request:**
```json
{
  "level": 1,
  "name": "Bronze",
  "min_wins": 10,
  "reward_usdt": 5.00,
  "icon_emoji": "🥉"
}
```

#### Claims — `/levels/claims.php`

| Method | Auth | Description |
|---|---|---|
| `GET` | User | Get user's claimed rewards |
| `POST` | User | Claim a level reward: `{ "level_id": "uuid" }` |

---

### 6.9 Announcements

#### GET `/announcements/read.php` — Public active announcements

**Auth:** None

#### CRUD `/announcements/manage.php` — Admin management

| Method | Auth | Description |
|---|---|---|
| `GET` | Admin | List all announcements |
| `POST` | Admin | Create announcement |
| `PUT` | Admin | Update announcement |
| `DELETE` | Admin | `?id=<uuid>` |

**POST/PUT Request:**
```json
{
  "title": "Scheduled Maintenance",
  "message": "Platform will be down for 2 hours.",
  "type": "warning",
  "is_active": true,
  "expires_at": "2025-02-01T00:00:00Z"
}
```

Types: `info`, `warning`, `success`, `error`

---

### 6.10 Deposit Coins & Chains

#### Coins — `/deposits/coins.php`

| Method | Auth | Query/Body |
|---|---|---|
| `GET` | None | Active coins (add `?all` for all) |
| `POST` | Admin | Create coin |
| `PUT` | Admin | Update coin |
| `DELETE` | Admin | `?id=<uuid>` |

**POST Request:**
```json
{
  "symbol": "BTC",
  "name": "Bitcoin",
  "is_active": true,
  "sort_order": 1
}
```

#### Chains — `/deposits/chains.php`

| Method | Auth | Query/Body |
|---|---|---|
| `GET` | None | All chains (filter: `?coin_id=<uuid>`) |
| `POST` | Admin | Create chain |
| `PUT` | Admin | Update chain |
| `DELETE` | Admin | `?id=<uuid>` |

**POST Request:**
```json
{
  "coin_id": "uuid",
  "chain_name": "Tron (TRC20)",
  "chain_key": "trc20",
  "short_name": "TRC20",
  "deposit_address": "TVx9a3...",
  "fee": 1.0,
  "min_deposit": 1.0,
  "min_withdraw": 10.0,
  "is_deposit_enabled": true,
  "is_withdraw_enabled": true,
  "arrival_time": "~1 min",
  "confirmations": "1 block"
}
```

---

### 6.11 Currencies

#### `/currencies/manage.php`

| Method | Auth | Query/Body |
|---|---|---|
| `GET` | None | Active currencies (add `?all` for all) |
| `POST` | Admin | Create currency |
| `PUT` | Admin | Update currency |
| `DELETE` | Admin | `?id=<uuid>` |

**POST Request:**
```json
{
  "code": "EUR",
  "symbol": "€",
  "rate": 0.92,
  "is_active": true,
  "sort_order": 2
}
```

---

### 6.12 Trading Pairs

#### `/trading-pairs/manage.php`

| Method | Auth | Query/Body |
|---|---|---|
| `GET` | None | Active pairs (add `?all` for all) |
| `POST` | Admin | Create pair |
| `PUT` | Admin | Update pair |
| `DELETE` | Admin | `?id=<uuid>` |

**POST Request:**
```json
{
  "symbol": "BTCUSDT",
  "label": "BTC/USDT",
  "base_asset": "BTC",
  "quote_asset": "USDT",
  "base_price": 66500.00,
  "is_active": true,
  "sort_order": 1
}
```

---

### 6.13 Platform Settings

#### GET `/settings/read.php` — Read settings

**Auth:** None

**Response** `200`:
```json
{
  "platformName": "TanSparks Trade",
  "supportEmail": "support@tansparks.com",
  "registrationEnabled": "true",
  "liveTradingEnabled": "true",
  ...
}
```

#### POST `/settings/update.php` — Update settings

**Auth:** Admin

**Request:**
```json
{
  "settings": {
    "platformName": "New Name",
    "registrationEnabled": "false"
  }
}
```

**Available settings keys:**

| Key | Default | Description |
|---|---|---|
| `platformName` | TanSparks Trade | Platform display name |
| `supportEmail` | support@tansparks.com | Support email |
| `platformTagline` | Professional Trading | Tagline |
| `platformVersion` | 1.0.0 | Version string |
| `registrationEnabled` | true | Allow new registrations |
| `liveTradingEnabled` | true | Enable real-money trading |
| `ticketSystemEnabled` | true | Support ticket system |
| `twoFactorEnabled` | true | 2FA support |
| `referralEnabled` | true | Referral system |
| `referrerBonus` | 5 | USDT bonus for referrer |
| `refereeBonus` | 5 | USDT bonus for referee |
| `leaderboardEnabled` | true | Leaderboard visibility |
| `levelsEnabled` | true | Levels & rewards system |
| `lightModeEnabled` | true | Allow light theme |
| `legalSectionEnabled` | true | Show legal pages |
| `loginActivityEnabled` | true | Track logins |
| `languageSwitcherEnabled` | true | Language selector |
| `transferEnabled` | true | User-to-user transfers |
| `pwaEnabled` | true | PWA install prompt |
| `telegramBotToken` | — | Telegram bot token |
| `telegramChatId` | — | Telegram chat ID |

---

### 6.14 Admin

#### GET `/admin/users.php` — List all users

**Auth:** Admin

Returns all profiles with wallet balances and roles.

#### PUT `/admin/users.php` — Update user

**Auth:** Admin

**Request:**
```json
{
  "user_id": "uuid",
  "is_blocked": true,
  "role": "moderator",
  "balance": 500.00,
  "demo_balance": 50000.00,
  "kyc_status": "approved"
}
```

All fields except `user_id` are optional.

---

#### GET `/admin/transactions.php` — List all transactions

**Auth:** Admin

**Query params:** `?status=pending&type=withdrawal&limit=100`

#### PUT `/admin/transactions.php` — Update transaction status

**Auth:** Admin

**Request:**
```json
{
  "id": "uuid",
  "status": "completed"
}
```

---

#### GET `/admin/stats.php` — Dashboard stats

**Auth:** Admin

**Response:**
```json
{
  "total_users": 1250,
  "new_users_24h": 42,
  "active_trades": 18,
  "total_volume": "5432100.00",
  "pending_deposits": 5,
  "pending_withdrawals": 3
}
```

---

#### GET `/admin/audit-log.php` — Audit log

**Auth:** Admin

Returns admin action history with details.

---

### 6.15 Login Activity

#### GET `/login-activity/read.php`

**Auth:** User

Returns the user's login history with `ip_address`, `user_agent`, `device`, `location`, `created_at`.

---

### 6.16 File Uploads

All upload endpoints use **`multipart/form-data`** (not JSON).

#### POST `/uploads/avatar.php` — Upload avatar

**Auth:** User  
**Field:** `avatar` (file)  
**Max size:** 5 MB  
**Allowed types:** JPEG, PNG, WebP, GIF

**Response:**
```json
{
  "success": true,
  "avatar_url": "/uploads/avatars/userid_1700000000.jpg"
}
```

#### DELETE `/uploads/avatar.php` — Remove avatar

**Auth:** User

---

#### POST `/uploads/kyc.php` — Upload KYC document

**Auth:** User  
**Field:** `document` (file)

---

#### POST `/uploads/pwa-assets.php` — Upload PWA icon

**Auth:** Admin  
**Field:** `asset` (file)

---

### 6.17 Telegram Notifications

#### POST `/telegram/notify.php`

**Auth:** Admin

**Request — Send notification:**
```json
{
  "action": "send",
  "message": "🔔 New withdrawal request: $500 from user@email.com"
}
```

**Request — Test connection:**
```json
{
  "action": "test",
  "message": "✅ Test notification"
}
```

**Request — Clear webhook:**
```json
{
  "action": "clear_webhook"
}
```

> Telegram bot token and chat ID must be configured in Platform Settings first.

---

### 6.18 Binance Proxy

Proxies Binance REST API to avoid CORS in the browser. Includes file-based caching.

#### GET `/binance/proxy.php`

**Auth:** None

**Query params:**

| Param | Required | Description |
|---|---|---|
| `endpoint` | ✅ | `ticker/24hr` or `klines` |
| `symbol` | for klines | e.g. `BTCUSDT` |
| `interval` | for klines | e.g. `1m`, `5m`, `1h` |
| `limit` | for klines | Number of candles |

**Examples:**
```
GET /api/binance/proxy.php?endpoint=ticker/24hr
GET /api/binance/proxy.php?endpoint=klines&symbol=BTCUSDT&interval=1m&limit=100
```

**Cache TTL:**
| Endpoint | TTL |
|---|---|
| `ticker/24hr` | 5 seconds |
| `klines` | 10 seconds |

**Response headers:**
- `X-Cache: HIT` — Served from cache
- `X-Cache: MISS` — Fresh fetch, cached
- `X-Cache: STALE` — Upstream failed, served stale cache

---

### 6.19 Server-Sent Events (SSE)

Real-time streaming for live updates (notifications, wallet changes, trade updates).

#### GET `/sse/stream.php` — User stream

**Auth:** via query param `?token=<jwt>`  
*(EventSource API cannot send headers)*

```javascript
const es = new EventSource(`/api/sse/stream.php?token=${token}`);
es.addEventListener('notification', (e) => { /* ... */ });
es.addEventListener('wallet', (e) => { /* ... */ });
es.addEventListener('trade', (e) => { /* ... */ });
```

#### GET `/sse/admin-stream.php` — Admin stream

**Auth:** via query param `?token=<jwt>` (admin only)

Streams admin-relevant events (new users, transactions, support tickets).

---

## 7. Database Schema

### Tables Overview

| Table | Purpose |
|---|---|
| `users` | Auth credentials (email + bcrypt hash) |
| `profiles` | User metadata, referrals, KYC status |
| `user_roles` | Role assignments (admin/moderator/user) |
| `wallets` | Real + demo balances per user |
| `trading_pairs` | Configurable trading instruments |
| `trades` | Trade history with entry/exit prices |
| `transactions` | Deposits, withdrawals, transfers |
| `notifications` | Per-user notification inbox |
| `platform_settings` | Key-value platform config |
| `support_tickets` | Support ticket metadata |
| `support_messages` | Messages within tickets |
| `login_activity` | Login audit trail |
| `deposit_coins` | Supported cryptocurrencies |
| `deposit_chains` | Network/chain configurations per coin |
| `currencies` | Fiat currency rates |
| `level_configs` | Gamification level definitions |
| `user_level_claims` | Claimed level rewards |
| `admin_audit_log` | Admin action history |
| `announcements` | Platform-wide announcements |

### Key Relationships

```
users (1) ──── (1) profiles
users (1) ──── (1) wallets
users (1) ──── (1) user_roles
users (1) ──── (N) trades
users (1) ──── (N) transactions
users (1) ──── (N) notifications
users (1) ──── (N) support_tickets
users (1) ──── (N) login_activity
users (1) ──── (N) user_level_claims
profiles (1) ── (N) profiles (referral: referred_by)
deposit_coins (1) ── (N) deposit_chains
support_tickets (1) ── (N) support_messages
level_configs (1) ── (N) user_level_claims
```

---

## 8. CORS

CORS headers are set globally in `config/database.php`:

```php
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With");
```

**For production**, restrict to your frontend domain:

```php
header("Access-Control-Allow-Origin: https://yourdomain.com");
```

All endpoints handle `OPTIONS` preflight requests automatically.

---

## 9. Error Handling

All errors return JSON:

```json
{ "error": "Human-readable error message" }
```

| Status | Meaning |
|---|---|
| `400` | Bad request / validation error |
| `401` | Missing or invalid JWT |
| `403` | Insufficient permissions (not admin) / blocked account |
| `404` | Resource not found |
| `409` | Conflict (e.g. duplicate email) |
| `500` | Server error |
| `502` | Upstream proxy failure |

---

## 10. Frontend Integration

The frontend uses a centralized API client at `src/lib/api.ts`:

```typescript
import { authApi, walletsApi, tradesApi } from '@/lib/api';

// Login
const { token, user } = await authApi.login(email, password);

// Get wallet
const wallet = await walletsApi.read();

// Place trade
const trade = await tradesApi.create({
  amount: 100,
  direction: 'up',
  pair: 'BTC/USDT',
  entry_price: 66500,
  expiry_seconds: 60,
  payout_percent: 85,
  is_demo: true,
});
```

The `API_BASE` is configured via the `VITE_API_URL` environment variable:

```
VITE_API_URL=https://api.yourdomain.com/api
```

If not set, it defaults to `/api` (same-origin).
