# Technical Documentation: cedar2025/Xboard

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/cedar2025/Xboard)

### Overview (`README.md`)

# Xboard

<div align="center">

[](https://t.me/XboardOfficial)


[](LICENSE)

</div>

## 📖 Introduction

Xboard is a modern panel system built on Laravel 11, focusing on providing a clean and efficient user experience.

## ✨ Features

- 🚀 Built with Laravel 12 + Octane for significant performance gains
- 🎨 Redesigned admin interface (React + Shadcn UI)
- 📱 Modern user frontend (Vue3 + TypeScript)
- 🐳 Ready-to-use Docker deployment solution
- 🎯 Optimized system architecture for better maintainability

## 🚀 Quick Start

```bash
git clone -b compose --depth 1 https://github.com/cedar2025/Xboard && \
cd Xboard && \
docker compose run -it --rm \
    -e ENABLE_SQLITE=true \
    -e ENABLE_REDIS=true \
    -e ADMIN_ACCOUNT=admin@demo.com \
    xboard php artisan xboard:install && \
docker compose up -d
```

> After installation, visit: http://SERVER_IP:7001  
> ⚠️ Make sure to save the admin credentials shown during installation

## 📖 Documentation

### 🔄 Upgrade Notice
> 🚨 **Important:** This version involves significant changes. Please strictly follow the upgrade documentation and backup your database before upgrading. Note that upgrading and migration are different processes, do not confuse them.

### Development Guides
- [Plugin Development Guide](./docs/en/development/plugin-development-guide.md) - Complete guide for developing XBoard plugins

### Deployment Guides

PHP **8.2.35 or later** is required. Use the latest security patch for your PHP release series. Docker deployments must meet this requirement inside the container.

- [Deploy with 1Panel](./docs/en/installation/1panel.md)
- [Deploy with Docker Compose](./docs/en/installation/docker-compose.md)
- [Deploy with aaPanel](./docs/en/installation/aapanel.md)
- [Deploy with aaPanel + Docker](./docs/en/installation/aapanel-docker.md) (Recommended)

### Migration Guides
- [Migrate from v2board dev](./docs/en/migration/v2board-dev.md)
- [Migrate from v2board 1.7.4](./docs/en/migration/v2board-1.7.4.md)
- [Migrate from v2board 1.7.3](./docs/en/migration/v2board-1.7.3.md)

## 🛠️ Tech Stack

- Backend: Laravel 11 + Octane
- Admin Panel: React + Shadcn UI + TailwindCSS
- User Frontend: Vue3 + TypeScript + NaiveUI
- Deployment: Docker + Docker Compose
- Caching: Redis + Octane Cache

## 📷 Preview




## ⚠️ Disclaimer

This project is for learning and communication purposes only. Users are responsible for any consequences of using this project.

## ❤️ Support The Project

If this project has helped you, donations are appreciated. They help support ongoing maintenance and would make me very happy.

TRC20: `TLypStEWsVrj6Wz9mCxbXffqgt5yz3Y4XB`

## 🌟 Maintenance Notice

This project is currently under light maintenance. We will:
- Fix critical bugs and security issues
- Review and merge important pull requests
- Provide necessary updates for compatibility

However, new feature development may be limited.

## 🔔 Important Notes

1. Restart required after modifying admin path:
```bash
docker compose restart
```

2. For aaPanel installations, restart the Octane daemon process

## 🤝 Contributing

Issues and Pull Requests are welcome to help improve the project.

## 📈 Star History

[](https://starchart.cc/cedar2025/Xboard)

---

### Overview (`plugins-core/Telegram/README.md`)

# Telegram 插件

XBoard 的 Telegram Bot 插件，提供用户账号绑定、流量查询、订阅链接获取等功能。

## 功能特性

-   ✅ 工单通知功能（可配置开关）
-   ✅ 支付通知功能（可配置开关）
-   ✅ 用户账号绑定/解绑
-   ✅ 流量使用情况查询
-   ✅ 订阅链接获取
-   ✅ 工单回复支持

## 可用命令

### `/start` - 开始使用

欢迎新用户并显示帮助信息，支持动态配置。

### `/bind` - 绑定账号

绑定用户的 XBoard 账号到 Telegram。

```
/bind [订阅链接]
```

### `/traffic` - 查看流量

查看当前绑定账号的流量使用情况。

### `/getlatesturl` - 获取订阅链接

获取最新的订阅链接。

### `/unbind` - 解绑账号

解绑当前 Telegram 账号与 XBoard 账号的关联。

## 配置选项

### 基础配置

| 配置项       | 类型    | 默认值                                                                                     | 说明                 |
| ------------ | ------- | ------------------------------------------------------------------------------------------ | -------------------- |
| `auto_reply` | boolean | true                                                                                       | 是否自动回复未知命令 |
| `help_text`  | text    | '请使用以下命令：\\n/bind - 绑定账号\\n/traffic - 查看流量\\n/getlatesturl - 获取最新链接' | 未知命令的回复文本   |

### `/start` 命令动态配置

| 配置项                  | 类型 | 说明                     |
| ----------------------- | ---- | ------------------------ |
| `start_welcome_title`   | text | 欢迎标题                 |
| `start_bot_description` | text | 机器人功能介绍           |
| `start_bind_guide`      | text | 未绑定用户的绑定指导     |
| `start_unbind_guide`    | text | 已绑定用户显示的命令列表 |
| `start_bind_commands`   | text | 未绑定用户显示的命令列表 |
| `start_footer`          | text | 底部提示信息             |

### 工单通知配置

| 配置项                 | 类型    | 默认值 | 说明                 |
| ---------------------- | ------- | ------ | -------------------- |
| `enable_ticket_notify` | boolean | true   | 是否开启工单通知功能 |

### 支付通知配置

| 配置项                  | 类型    | 默认值 | 说明                 |
| ----------------------- | ------- | ------ | -------------------- |
| `enable_payment_notify` | boolean | true   | 是否开启支付通知功能 |

## 使用流程

### 新用户使用流程

1. 用户首次使用 Bot，发送 `/start`
2. 根据提示绑定账号：`/bind [订阅链接]`
3. 绑定成功后即可使用其他功能

### 日常使用流程

1. 查看流量：`/traffic`
2. 获取订阅链接：`/getlatesturl`
3. 管理绑定：`/unbind`

---

### En Development Device Limit (`docs/en/development/device-limit.md`)

# Online Device Limit Design

## Overview

This document describes the design and implementation of the online device limit feature in Xboard.

## Design Goals

1. Accurate Control
   - Precise counting of online devices
   - Real-time monitoring of device status
   - Accurate device identification

2. Performance Optimization
   - Minimal impact on system performance
   - Efficient device tracking
   - Optimized resource usage

3. User Experience
   - Smooth connection experience
   - Clear error messages
   - Graceful handling of limit exceeded cases

## Implementation Details

### 1. Device Identification

#### Device ID Generation
```php
public function generateDeviceId($user, $request) {
    return md5(
        $user->id . 
        $request->header('User-Agent') . 
        $request->ip()
    );
}
```

#### Device Information Storage
```php
[
    'device_id' => 'unique_device_hash',
    'user_id' => 123,
    'ip' => '192.168.1.1',
    'user_agent' => 'Mozilla/5.0...',
    'last_active' => '2024-03-21 10:00:00'
]
```

### 2. Connection Management

#### Connection Check
```php
public function checkDeviceLimit($user, $deviceId) {
    $onlineDevices = $this->getOnlineDevices($user->id);
    
    if (count($onlineDevices) >= $user->device_limit) {
        if (!in_array($deviceId, $onlineDevices)) {
            throw new DeviceLimitExceededException();
        }
    }
    
    return true;
}
```

#### Device Status Update
```php
public function updateDeviceStatus($userId, $deviceId) {
    Redis::hset(
        "user:{$userId}:devices",
        $deviceId,
        json_encode([
            'last_active' => now(),
            'status' => 'online'
        ])
    );
}
```

### 3. Cleanup Mechanism

#### Inactive Device Cleanup
```php
public function cleanupInactiveDevices() {
    $inactiveThreshold = now()->subMinutes(30);
    
    foreach ($this->getUsers() as $user) {
        $devices = $this->getOnlineDevices($user->id);
        
        foreach ($devices as $deviceId => $info) {
            if ($info['last_active'] < $inactiveThreshold) {
                $this->removeDevice($user->id, $deviceId);
            }
        }
    }
}
```

## Error Handling

### Error Types
1. Device Limit Exceeded
   ```php
   class DeviceLimitExceededException extends Exception {
       protected $message = 'Device limit exceeded';
       protected $code = 4001;
   }
   ```

2. Invalid Device
   ```php
   class InvalidDeviceException extends Exception {
       protected $message = 'Invalid device';
       protected $code = 4002;
   }
   ```

### Error Messages
```php
return [
    'device_limit_exceeded' => 'Maximum number of devices reached',
    'invalid_device' => 'Device not recognized',
    'device_expired' => 'Device session expired'
];
```

## Performance Considerations

1. Cache Strategy
   - Use Redis for device tracking
   - Implement cache expiration
   - Optimize cache structure

2. Database Operations
   - Minimize database queries
   - Use batch operations
   - Implement query optimization

3. Memory Management
   - Efficient data structure
   - Regular cleanup of expired data
   - Memory usage monitoring

## Security Measures

1. Device Verification
   - Validate device information
   - Check for suspicious patterns
   - Implement rate limiting

2. Data Protection
   - Encrypt sensitive information
   - Implement access control
   - Regular security audits

## Future Improvements

1. Enhanced Features
   - Device management interface
   - Device activity history
   - Custom device names

2. Performance Optimization
   - Improved caching strategy
   - Better cleanup mechanism
   - Reduced memory usage

3. Security Enhancements
   - Advanced device fingerprinting
   - Fraud detection
   - Improved encryption

## Conclusion

This design provides a robust and efficient solution for managing online device limits while maintaining good performance and user experience. Regular monitoring and updates will ensure the system remains effective and secure.

---

### En Development Performance (`docs/en/development/performance.md`)

# Performance Comparison Report

## Test Environment

### Hardware Configuration
- CPU: AMD EPYC 7K62 48-Core Processor
- Memory: 4GB
- Disk: NVMe SSD
- Network: 1Gbps

### Software Environment
- OS: Ubuntu 22.04 LTS
- PHP: 8.2
- MySQL: 5.7
- Redis: 7.0
- Docker: Latest stable version

## Test Scenarios

### 1. User Login Performance
- Concurrent users: 100
- Test duration: 60 seconds
- Request type: POST
- Target endpoint: `/api/v1/passport/auth/login`

Results:
- Average response time: 156ms
- 95th percentile: 245ms
- Maximum response time: 412ms
- Requests per second: 642

### 2. User Dashboard Loading
- Concurrent users: 100
- Test duration: 60 seconds
- Request type: GET
- Target endpoint: `/api/v1/user/dashboard`

Results:
- Average response time: 89ms
- 95th percentile: 167ms
- Maximum response time: 289ms
- Requests per second: 1121

### 3. Node List Query
- Concurrent users: 100
- Test duration: 60 seconds
- Request type: GET
- Target endpoint: `/api/v1/user/server/nodes`

Results:
- Average response time: 134ms
- 95th percentile: 223ms
- Maximum response time: 378ms
- Requests per second: 745

## Performance Optimization Measures

1. Database Optimization
   - Added indexes for frequently queried fields
   - Optimized slow queries
   - Implemented query caching

2. Cache Strategy
   - Using Redis for session storage
   - Caching frequently accessed data
   - Implementing cache warming

3. Code Optimization
   - Reduced database queries
   - Optimized database connection pool
   - Improved error handling

## Comparison with Previous Version

| Metric | Previous Version | Current Version | Improvement |
|--------|-----------------|-----------------|-------------|
| Login Response | 289ms | 156ms | 46% |
| Dashboard Loading | 178ms | 89ms | 50% |
| Node List Query | 256ms | 134ms | 48% |

## Future Optimization Plans

1. Infrastructure Level
   - Implement horizontal scaling
   - Add load balancing
   - Optimize network configuration

2. Application Level
   - Further optimize database queries
   - Implement more efficient caching strategies
   - Reduce memory usage

3. Monitoring and Maintenance
   - Add performance monitoring
   - Implement automatic scaling
   - Regular performance testing

## Conclusion

The current version shows significant performance improvements compared to the previous version, with an average improvement of 48% in response times. The optimization measures implemented have effectively enhanced the system's performance and stability.

---

### En Development Plugin Development Guide (`docs/en/development/plugin-development-guide.md`)

# XBoard Plugin Development Guide

## 📦 Plugin Structure

Each plugin is an independent directory with the following structure:

```
plugins/
└── YourPlugin/               # Plugin directory (PascalCase naming)
    ├── Plugin.php           # Main plugin class (required)
    ├── config.json          # Plugin configuration (required)
    ├── routes/
    │   └── api.php          # API routes
    ├── Controllers/         # Controllers directory
    │   └── YourController.php
    ├── Commands/            # Artisan commands directory
    │   └── YourCommand.php
    └── README.md            # Documentation
```

## 🚀 Quick Start

### 1. Create Configuration File `config.json`

```json
{
    "name": "My Plugin",
    "code": "my_plugin", // Corresponds to plugin directory (lowercase + underscore)
    "version": "1.0.0",
    "description": "Plugin functionality description",
    "author": "Author Name",
    "require": {
        "xboard": ">=1.0.0" // Version not fully implemented yet
    },
    "config": {
        "api_key": {
            "type": "string",
            "default": "",
            "label": "API Key",
            "description": "API Key"
        },
        "timeout": {
            "type": "number",
            "default": 300,
            "label": "Timeout (seconds)",
            "description": "Timeout in seconds"
        }
    }
}
```

### 2. Create Main Plugin Class `Plugin.php`

```php
<?php

namespace Plugin\YourPlugin;

use App\Services\Plugin\AbstractPlugin;

class Plugin extends AbstractPlugin
{
    /**
     * Called when plugin starts
     */
    public function boot(): void
    {
        // Register frontend configuration hook
        $this->filter('guest_comm_config', function ($config) {
            $config['my_plugin_enable'] = true;
            $config['my_plugin_setting'] = $this->getConfig('api_key', '');
            return $config;
        });
    }
}
```

### 3. Create Controller

**Recommended approach: Extend PluginController**

```php
<?php

namespace Plugin\YourPlugin\Controllers;

use App\Http\Controllers\PluginController;
use Illuminate\Http\Request;

class YourController extends PluginController
{
    public function handle(Request $request)
    {
        // Get plugin configuration
        $apiKey = $this->getConfig('api_key');
        $timeout = $this->getConfig('timeout', 300);

        // Your business logic...

        return $this->success(['message' => 'Success']);
    }
}
```

### 4. Create Routes `routes/api.php`

```php
<?php

use Illuminate\Support\Facades\Route;
use Plugin\YourPlugin\Controllers\YourController;

Route::group([
    'prefix' => 'api/v1/your-plugin'
], function () {
    Route::post('/handle', [YourController::class, 'handle']);
});
```

## 🔧 Configuration Access

In controllers, you can easily access plugin configuration:

```php
// Get single configuration
$value = $this->getConfig('key', 'default_value');

// Get all configurations
$allConfig = $this->getConfig();

// Check if plugin is enabled
$enabled = $this->isPluginEnabled();
```

## 🎣 Hook System

### Popular Hooks (Recommended to follow)

XBoard has built-in hooks for many business-critical nodes. Plugin developers can flexibly extend through `filter` or `listen` methods. Here are the most commonly used and valuable hooks:

| Hook Name                 | Type   | Typical Parameters       | Description      |
| ------------------------- | ------ | ----------------------- | ---------------- |
| user.register.before      | action | Request                 | Before user registration |
| user.register.after       | action | User                    | After user registration |
| user.login.after          | action | User                    | After user login |
| user.password.reset.after | action | User                    | After password reset |
| order.cancel.before       | action | Order                   | Before order cancellation |
| order.cancel.after        | action | Order                   | After order cancellation |
| payment.notify.before     | action | method, uuid, request   | Before payment callback |
| payment.notify.verified   | action | array                   | Payment callback verification successful |
| payment.notify.failed     | action | method, uuid, request   | Payment callback verification failed |
| traffic.reset.after       | action | User                    | After traffic reset |
| ticket.create.after       | action | Ticket                  | After ticket creation |
| ticket.reply.user.after   | action | Ticket                  | After user replies to ticket |
| ticket.close.after        | action | Ticket                  | After ticket closure |

> ⚡️ The hook system will continue to expand. Developers can always follow this documentation and the `php artisan hook:list` command to get the latest supported hooks.

### Filter Hooks

Used to modify data:

```php
// In Plugin.php boot() method
$this->filter('guest_comm_config', function ($config) {
    // Add configuration for frontend
    $config['my_setting'] = $this->getConfig('setting');
    return $config;
});
```

### Action Hooks

Used to execute operations:

```php
$this->listen('user.created', function ($user) {
    // Operations after user creation
    $this->doSomething($user);
});
```

## 📝 Real Example: Telegram Login Plugin

Using TelegramLogin plugin as an example to demonstrate complete implementation:

**Main Plugin Class** (23 lines):

```php
<?php

namespace Plugin\TelegramLogin;

use App\Services\Plugin\AbstractPlugin;

class Plugin extends AbstractPlugin
{
    public function boot(): void
    {
        $this->filter('guest_comm_config', function ($config) {
            $config['telegram_login_enable'] = true;
            $config['telegram_login_domain'] = $this->getConfig('domain', '');
            $config['telegram_bot_username'] = $this->getConfig('bot_username', '');
            return $config;
        });
    }
}
```

**Controller** (extends PluginController):

```php
class TelegramLoginController extends PluginController
{
    public function telegramLogin(Request $request)
    {
        // Check plugin status
        if ($error = $this->beforePluginAction()) {
            return $error[1];
        }

        // Get configuration
        $botToken = $this->getConfig('bot_token');
        $timeout = $this->getConfig('auth_timeout', 300);

        // Business logic...

        return $this->success($result);
    }
}
```

## ⏰ Plugin Scheduled Tasks (Scheduler)

Plugins can register their own scheduled tasks by implementing the `schedule(Schedule $schedule)` method in the main class.

**Example:**

```php
use Illuminate\Console\Scheduling\Schedule;

class Plugin extends AbstractPlugin
{
    public function schedule(Schedule $schedule): void
    {
        // Execute every hour
        $schedule->call(function () {
            // Your scheduled task logic
            \Log::info('Plugin scheduled task executed');
        })->hourly();
    }
}
```

- Just implement the `schedule()` method in Plugin.php.
- All plugin scheduled tasks will be automatically scheduled by the main program.
- Supports all Laravel scheduler usage.

## 🖥️ Plugin Artisan Commands

Plugins can automatically register Artisan commands by creating command classes in the `Commands/` directory.

### Command Directory Structure

```
plugins/YourPlugin/
├── Commands/
│   ├── TestCommand.php      # Test command
│   ├── BackupCommand.php    # Backup command
│   └── CleanupCommand.php   # Cleanup command
```

### Create Command Class

**Example: TestCommand.php**

```php
<?php

namespace Plugin\YourPlugin\Commands;

use Illuminate\Console\Command;

class TestCommand extends Command
{
    protected $signature = 'your-plugin:test {action=ping} {--message=Hello}';
    protected $description = 'Test plugin functionality';

    public function handle(): int
    {
        $action = $this->argument('action');
        $message = $this->option('message');

        try {
            return match ($action) {
                'ping' => $this->ping($message),
                'info' => $this->showInfo(),
                default => $this->showHelp()
            };
        } catch (\Exception $e) {
            $this->error('Operation failed: ' . $e->getMessage());
            return 1;
        }
    }

    protected function ping(string $message): int
    {
        $this->info("✅ {$message}");
        return 0;
    }

    protected function showInfo(): int
    {
        $this->info('Plugin Information:');
        $this->table(
            ['Property', 'Value'],
            [
                ['Plugin Name', 'YourPlugin'],
                ['Version', '1.0.0'],
                ['Status', 'Enabled'],
            ]
        );
        return 0;
    }

    protected function showHelp(): int
    {
        $this->info('Usage:');
        $this->line('  php artisan your-plugin:test ping --message="Hello"  # Test');
        $this->line('  php artisan your-plugin:test info                    # Show info');
        return 0;
    }
}
```

### Automatic Command Registration

- ✅ Automatically register all commands in `Commands/` directory when plugin is enabled
- ✅ Command namespace automatically set to `Plugin\YourPlugin\Commands`
- ✅ Supports all Laravel command features (arguments, options, interaction, etc.)

### Usage Examples

```bash
# Test command
php artisan your-plugin:test ping --message="Hello World"

# Show information
php artisan your-plugin:test info

# View help
php artisan your-plugin:test --help
```

### Best Practices

1. **Command Naming**: Use `plugin-name:action` format, e.g., `telegram:test`
2. **Error Handling**: Wrap main logic with try-catch
3. **Return Values**: Return 0 for success, 1 for failure
4. **User Friendly**: Provide clear help information and error messages
5. **Type Declarations**: Use PHP 8.2 type declarations

## 🛠️ Development Tools

### Controller Base Class Selection

**Method 1: Extend PluginController (Recommended)**

- Automatic configuration access: `$this->getConfig()`
- Automatic status checking: `$this->beforePluginAction()`
- Unified error handling

**Method 2: Use HasPluginConfig Trait**

```php
use App\Http\Controllers\Controller;
use App\Traits\HasPluginConfig;

class YourController extends Controller
{
    use HasPluginConfig;

    public function handle()
    {
        $config = $this->getConfig('key');
        // ...
    }
}
```

### Configuration Types

Supported configuration types:

- `string` - String
- `number` - Number
- `boolean` - Boolean
- `json` - Array
- `yaml`

## 🎯 Best Practices

### 1. Concise Main Class

- Plugin main class should be as concise as possible
- Mainly used for registering hooks and routes
- Complex logic should be placed in controllers or services

### 2. Configuration Management

- Define all configuration items in `config.json`
- Use `$this->getConfig()` to access configuration
- Provide default values for all configurations

### 3. Route Design

- Use semantic route prefixes
- Place API routes in `routes/api.php`
- Place Web routes in `routes/web.php`

### 4. Error Handling

```php
public function handle(Request $request)
{
    // Check plugin status
    if ($error = $this->beforePluginAction()) {
        return $error[1];
    }

    try {
        // Business logic
        return $this->success($result);
    } catch (\Exception $e) {
        return $this->fail([500, $e->getMessage()]);
    }
}
```

## 🔍 Debugging Tips

### 1. Logging

```php
\Log::info('Plugin operation', ['data' => $data]);
\Log::error('Plugin error', ['error' => $e->getMessage()]);
```

### 2. Configuration Checking

```php
// Check required configuration
if (!$this->getConfig('required_key')) {
    return $this->fail([400, 'Missing configuration']);
}
```

### 3. Development Mode

```php
if (config('app.debug')) {
    // Detailed debug information for development environment
}
```

## 📋 Plugin Lifecycle

1. **Installation**: Validate configuration, register to database
2. **Enable**: Load plugin, register hooks and routes
3. **Running**: Handle requests, execute business logic

## 🎉 Summary

Based on TelegramLogin plugin practical experience:

- **Simplicity**: Main class only 23 lines, focused on core functionality
- **Practicality**: Extends PluginController, convenient configuration access
- **Maintainability**: Clear directory structure, standard development patterns
- **Extensibility**: Hook-based architecture, easy to extend functionality

Following this guide, you can quickly develop plugins with complete functionality and concise code! 🚀

## 🖥️ Complete Plugin Artisan Commands Guide

### Feature Highlights

✅ **Auto Registration**: Automatically register all commands in `Commands/` directory when plugin is enabled  
✅ **Namespace Isolation**: Each plugin's commands use independent namespaces  
✅ **Type Safety**: Support PHP 8.2 type declarations  
✅ **Error Handling**: Comprehensive exception handling and error messages  
✅ **Configuration Integration**: Commands can access plugin configuration  
✅ **Interaction Support**: Support user input and confirmation operations

### Real Case Demonstrations

#### 1. Telegram Plugin Commands

```bash
# Test Bot connection
php artisan telegram:test ping

# Send message
php artisan telegram:test send --message="Hello World"

# Get Bot information
php artisan telegram:test info
```

#### 2. TelegramExtra Plugin Commands

```bash
# Show all statistics
php artisan telegram-extra:stats all

# User statistics
php artisan telegram-extra:stats users

# JSON format output
php artisan telegram-extra:stats users --format=json
```

#### 3. Example Plugin Commands

```bash
# Basic usage
php artisan example:hello

# With arguments and options
php artisan example:hello Bear --message="Welcome!"
```

### Development Best Practices

#### 1. Command Naming Conventions

```php
// ✅ Recommended: Use plugin name as prefix
protected $signature = 'telegram:test {action}';
protected $signature = 'telegram-extra:stats {type}';
protected $signature = 'example:hello {name}';

// ❌ Avoid: Use generic names
protected $signature = 'test {action}';
protected $signature = 'stats {type}';
```

#### 2. Error Handling Pattern

```php
public function handle(): int
{
    try {
        // Main logic
        return $this->executeAction();
    } catch (\Exception $e) {
        $this->error('Operation failed: ' . $e->getMessage());
        return 1;
    }
}
```

#### 3. User Interaction

```php
// Get user input
$chatId = $this->ask('Please enter chat ID');

// Confirm operation
if (!$this->confirm('Are you sure you want to execute this operation?')) {
    $this->info('Operation cancelled');
    return 0;
}

// Choose operation
$action = $this->choice('Choose operation', ['ping', 'send', 'info']);
```

#### 4. Configuration Access

```php
// Access plugin configuration in commands
protected function getConfig(string $key, $default = null): mixed
{
    // Get plugin instance through PluginManager
    $plugin = app(\App\Services\Plugin\PluginManager::class)
        ->getEnabledPlugins()['example_plugin'] ?? null;

    return $plugin ? $plugin->getConfig($key, $default) : $default;
}
```

### Advanced Usage

#### 1. Multi-Command Plugins

```php
// One plugin can have multiple commands
plugins/YourPlugin/Commands/
├── BackupCommand.php      # Backup command
├── CleanupCommand.php     # Cleanup command
├── StatsCommand.php       # Statistics command
└── TestCommand.php        # Test command
```

#### 2. Inter-Command Communication

```php
// Share data between commands through cache or database
Cache::put('plugin:backup:progress', $progress, 3600);
$progress = Cache::get('plugin:backup:progress');
```

#### 3. Scheduled Task Integration

```php
// Call commands in plugin's schedule method
public function schedule(Schedule $schedule): void
{
    $schedule->command('your-plugin:backup')->daily();
    $schedule->command('your-plugin:cleanup')->weekly();
}
```

### Debugging Tips

#### 1. Command Testing

```bash
# View command help
php artisan your-plugin:command --help

# Verbose output
php artisan your-plugin:command --verbose

# Debug mode
php artisan your-plugin:command --debug
```

#### 2. Logging

```php
// Log in commands
Log::info('Plugin command executed', [
    'command' => $this->signature,
    'arguments' => $this->arguments(),
    'options' => $this->options()
]);
```

#### 3. Performance Monitoring

```php
// Record command execution time
$startTime = microtime(true);
// ... execution logic
$endTime = microtime(true);
$this->info("Execution time: " . round(($endTime - $startTime) * 1000, 2) . "ms");
```

### Common Issues

#### Q: Commands not showing in list?

A: Check if plugin is enabled and ensure `Commands/` directory exists and contains valid command classes.

#### Q: Command execution failed?

A: Check if command class namespace is correct and ensure it extends `Illuminate\Console\Command`.

#### Q: How to access plugin configuration?

A: Get plugin instance through `PluginManager`, then call `getConfig()` method.

#### Q: Can commands call other commands?

A: Yes, use `Artisan::call()` method to call other commands.

```php
Artisan::call('other-plugin:command', ['arg' => 'value']);
```

### Summary

The plugin command system provides powerful extension capabilities for XBoard:

- 🚀 **Development Efficiency**: Quickly create management commands
- 🔧 **Operational Convenience**: Automate daily operations
- 📊 **Monitoring Capability**: Real-time system status viewing
- 🛠️ **Debug Support**: Convenient problem troubleshooting tools

By properly using plugin commands, you can greatly improve system maintainability and user experience! 🎉

---

### En Installation 1panel (`docs/en/installation/1panel.md`)

# Quick Deployment Guide for 1Panel

This guide explains how to deploy Xboard using 1Panel.

The Xboard container must run **PHP 8.2.35 or later**, with the latest security patch for its PHP release series. Host PHP is not required.

## 1. Environment Preparation

Install 1Panel:
```bash
curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_start.sh && \
sudo bash quick_start.sh
```

## 2. Environment Configuration

1. Install from App Store:
   - OpenResty (any version)
     - ⚠️ Check "External Port Access" to open firewall
   - MySQL 5.7 (Use MariaDB for ARM architecture)

2. Create Database:
   - Database name: `xboard`
   - Username: `xboard`
   - Access rights: All hosts (%)
   - Save the database password for installation

## 3. Deployment Steps

1. Add Website:
   - Go to "Website" > "Create Website" > "Reverse Proxy"
   - Domain: Enter your domain
   - Code: `xboard`
   - Proxy address: `127.0.0.1:7001`

2. Configure Reverse Proxy:
```nginx
location ^~ / {
    proxy_pass http://127.0.0.1:7001;
    proxy_http_version 1.1;
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $http_connection;
    proxy_read_timeout 60s;
    proxy_buffering off;
    proxy_cache off;
}
```
> The all-in-one container's embedded Caddy fuses HTTP and the panel↔node WebSocket on port 7001. The single `Upgrade`/`Connection` pair above is enough; no separate `/ws/` location is needed. To opt out and expose Octane / `:8076` directly, set `ENABLE_CADDY=false` in `compose.yaml`.

3. Install Xboard:
```bash
# Enter site directory
cd /opt/1panel/apps/openresty/openresty/www/sites/xboard/index

# Install Git (if not installed)
## Ubuntu/Debian
apt update && apt install -y git
## CentOS/RHEL
yum update && yum install -y git

# Clone repository
git clone -b compose --depth 1 https://github.com/cedar2025/Xboard ./
# (Optional shortcut: skip the clone and just fetch the sample file with
#  curl -fsSL https://raw.githubusercontent.com/cedar2025/Xboard/master/compose.sample.yaml -o compose.yaml
#  — the running PHP code is in the Docker image, not in the clone.)

# Configure Docker Compose
```

4. Prepare `compose.yaml` from the **1Panel-specific** sample. This sample joins the external `1panel-network` so the container can reach the 1Panel-managed MySQL/Redis containers by their hostname:
```bash
cp compose.1panel.sample.yaml compose.yaml
```
The file is gitignored so your edits survive `git pull`. See [docker-compose.md](./docker-compose.md) for tuning environment variables (`RESOURCE_PROFILE`, `ENABLE_HORIZON`, `ENABLE_REDIS`, etc.) and the other `compose.*.sample.yaml` alternatives.

5. Initialize Installation:
```bash
docker compose run -it --rm xboard php artisan xboard:install
```

⚠️ Important Configuration Notes:
1. Database Configuration
   - Database Host: Choose based on your deployment:
     1. If database and Xboard are in the same network, use `mysql`
     2. If connection fails, go to: Database -> Select Database -> Connection Info -> Container Connection, and use the "Host" value
     3. If using external database, enter your actual database host
   - Database Port: `3306` (default port unless configured otherwise)
   - Database Name: `xboard` (the database created earlier)
   - Database User: `xboard` (the user created earlier)
   - Database Password: Enter the password saved earlier

2. Redis Configuration
   - Choose to use built-in Redis
   - No additional configuration needed

3. Administrator Information
   - Save the admin credentials displayed after installation
   - Note down the admin panel access URL

After configuration, start the services:
```bash
docker compose up -d
```

6. Start Services:
```bash
docker compose up -d
```

## 4. Version Update

```bash
docker compose pull && docker compose up -d
```

The container always runs `php artisan xboard:update` (migrate + plugin install + version cache + theme refresh) on boot, so no extra command is required.

> **Using a `compose.yaml` from before 2026-04-19?** That template did not auto-run `xboard:update` on container start, so use the following command to upgrade instead:
> ```bash
> docker compose pull && docker compose run -it --rm web php artisan xboard:update && docker compose up -d
> ```

## Important Notes

- ⚠️ Ensure firewall is enabled to prevent port 7001 exposure to public
- Service restart is required after code modifications
- SSL certificate configuration is recommended for secure access

> The node will automatically detect WebSocket availability during handshake. No extra configuration is needed on the node side.

---

### En Installation Aapanel Docker (`docs/en/installation/aapanel-docker.md`)

# Xboard Deployment Guide for aaPanel + Docker Environment

## Table of Contents
1. [Requirements](#requirements)
2. [Quick Deployment](#quick-deployment)
3. [Detailed Configuration](#detailed-configuration)
4. [Maintenance Guide](#maintenance-guide)
5. [Troubleshooting](#troubleshooting)

## Requirements

### Hardware Requirements
- CPU: 1 core or above
- Memory: 2GB or above
- Storage: 10GB+ available space

### Software Requirements
- Operating System: Ubuntu 20.04+ / CentOS 7+ / Debian 10+
- Latest version of aaPanel
- Docker and Docker Compose
- Nginx (any version)
- MySQL 5.7+

## Quick Deployment

### 1. Install aaPanel
```bash
curl -sSL https://www.aapanel.com/script/install_6.0_en.sh -o install_6.0_en.sh && \
bash install_6.0_en.sh aapanel
```

### 2. Basic Environment Setup

#### 2.1 Install Docker
```bash
# Install Docker
curl -sSL https://get.docker.com | bash

# For CentOS systems, also run:
systemctl enable docker
systemctl start docker
```

#### 2.2 Install Required Components
In the aaPanel dashboard, install:
- Nginx (any version)
- MySQL 5.7
- ⚠️ PHP and Redis are not required on the host

The Xboard container must run **PHP 8.2.35 or later**, with the latest security patch for its PHP release series.

### 3. Site Configuration

#### 3.1 Create Website
1. Navigate to: aaPanel > Website > Add site
2. Fill in the information:
   - Domain: Enter your site domain
   - Database: Select MySQL
   - PHP Version: Select Pure Static

#### 3.2 Deploy Xboard
```bash
# Enter site directory
cd /www/wwwroot/your-domain

# Clean directory
chattr -i .user.ini
rm -rf .htaccess 404.html 502.html index.html .user.ini

# Clone the compose branch
git clone -b compose --depth 1 https://github.com/cedar2025/Xboard.git ./

# Prepare configuration file
cp compose.host.sample.yaml compose.yaml

# Install dependencies and initialize
docker compose run -it --rm xboard php artisan xboard:install
```
> ⚠️ Please save the admin dashboard URL, username, and password shown after installation

#### 3.3 Start Services
```bash
docker compose up -d
```

#### 3.4 Configure Reverse Proxy
Add the following content to your site configuration:
```nginx
location ^~ / {
    proxy_pass http://127.0.0.1:7001;
    proxy_http_version 1.1;
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $http_connection;
    proxy_read_timeout 60s;
    proxy_buffering off;
    proxy_cache off;
}
```
> The all-in-one container's embedded Caddy fuses HTTP and the panel↔node WebSocket on port 7001. The single `Upgrade`/`Connection` pair above is enough; no separate `/ws/` location is needed. To opt out and expose Octane / `:8076` directly, set `ENABLE_CADDY=false` in `compose.yaml`.

## Maintenance Guide

### Version Updates

```bash
docker compose pull && docker compose up -d
```

The container always runs `php artisan xboard:update` (migrate + plugin install + version cache + theme refresh) on boot, so no extra command is required.

> **Using a `compose.yaml` from before 2026-04-19?** That template did not auto-run `xboard:update` on container start, so use the following command to upgrade instead:
> ```bash
> docker compose pull && docker compose run -it --rm web sh update.sh && docker compose up -d
> ```

### Routine Maintenance
- Regular log checking: `docker compose logs`
- Monitor system resource usage
- Regular backup of database and configuration files

## Troubleshooting

If you encounter any issues during installation or operation, please check:
1. **Empty Admin Dashboard**: If the admin panel is blank, run `git submodule update --init --recursive --force` to restore the theme files.
2. System requirements are met
3. All required ports are available
3. Docker services are running properly
4. Nginx configuration is correct
5. Check logs for detailed error messages

> The node will automatically detect WebSocket availability during handshake. No extra configuration is needed on the node side.

---

### En Installation Aapanel (`docs/en/installation/aapanel.md`)

# Xboard Deployment Guide for aaPanel Environment

## Table of Contents
1. [Requirements](#requirements)
2. [Quick Deployment](#quick-deployment)
3. [Detailed Configuration](#detailed-configuration)
4. [Maintenance Guide](#maintenance-guide)
5. [Troubleshooting](#troubleshooting)

## Requirements

### Hardware Requirements
- CPU: 1 core or above
- Memory: 2GB or above
- Storage: 10GB+ available space

### Software Requirements
- Operating System: Ubuntu 20.04+ / Debian 10+ (⚠️ CentOS 7 is not recommended)
- Latest version of aaPanel
- PHP **8.2.35 or later**, using the latest security patch for your PHP release series
- MySQL 5.7+
- Redis
- Nginx (any version)

## Quick Deployment

### 1. Install aaPanel
```bash
URL=https://www.aapanel.com/script/install_6.0_en.sh && \
if [ -f /usr/bin/curl ];then curl -ksSO "$URL" ;else wget --no-check-certificate -O install_6.0_en.sh "$URL";fi && \
bash install_6.0_en.sh aapanel
```

### 2. Basic Environment Setup

#### 2.1 Install LNMP Environment
In the aaPanel dashboard, install:
- Nginx (any version)
- MySQL 5.7
- PHP 8.2, updated to **8.2.35 or later** within the 8.2 series

Check the installed version with `/www/server/php/82/bin/php -v` and `php -v`. The website, CLI, scheduled tasks and Supervisor processes must all use an updated PHP runtime. After upgrading, restart PHP-FPM and any running Horizon, Octane and WebSocket workers.

#### 2.2 Install PHP Extensions
Required PHP extensions:
- redis
- fileinfo
- swoole
- readline
- event
- mbstring

#### 2.3 Enable Required PHP Functions
Functions that need to be enabled:
- putenv
- proc_open
- pcntl_alarm
- pcntl_signal

### 3. Site Configuration

#### 3.1 Create Website
1. Navigate to: aaPanel > Website > Add site
2. Fill in the information:
   - Domain: Enter your site domain
   - Database: Select MySQL
   - PHP Version: Select 8.2 with patch version **8.2.35 or later**

#### 3.2 Deploy Xboard
```bash
# Enter site directory
cd /www/wwwroot/your-domain

# Clean directory
chattr -i .user.ini
rm -rf .htaccess 404.html 502.html index.html .user.ini

# Clone repository
git clone https://github.com/cedar2025/Xboard.git ./

# Install dependencies
sh init.sh
```

#### 3.3 Configure Site
1. Set running directory to `/public`
2. Add rewrite rules:
```nginx
location /downloads {
}

location / {  
    try_files $uri $uri/ /index.php$is_args$query_string;  
}

location ~ .*\.(js|css)?$
{
    expires      1h;
    error_log off;
    access_log /dev/null; 
}
```

## Detailed Configuration

### 1. Configure Daemon Process
1. Install Supervisor
2. Add queue daemon process:
   - Name: `Xboard`
   - Run User: `www`
   - Running Directory: Site directory
   - Start Command: `php artisan horizon`
   - Process Count: 1

### 2. Configure Scheduled Tasks
- Type: Shell Script
- Task Name: v2board
- Run User: www
- Frequency: 1 minute
- Script Content: `php /www/wwwroot/site-directory/artisan schedule:run`

### 3. Octane Configuration (Optional)
#### 3.1 Add Octane Daemon Process
- Name: Octane
- Run User: www
- Running Directory: Site directory
- Start Command: `/www/server/php/82/bin/php artisan octane:start --port 7010`
- Process Count: 1

#### 3.2 Octane-specific Rewrite Rules
```nginx
location ~* \.(jpg|jpeg|png|gif|js|css|svg|woff2|woff|ttf|eot|wasm|json|ico)$ {
}

location ~ .* {
    proxy_pass http://127.0.0.1:7010;
    proxy_http_version 1.1;
    proxy_set_header Connection "";
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Real-PORT $remote_port;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_set_header Scheme $scheme;
    proxy_set_header Server-Protocol $server_protocol;
    proxy_set_header Server-Name $server_name;
    proxy_set_header Server-Addr $server_addr;
    proxy_set_header Server-Port $server_port;
}
```

## Maintenance Guide

### Version Updates
```bash
# Enter site directory
cd /www/wwwroot/your-domain

# Execute update script
git fetch --all && git reset --hard origin/master && git pull origin master
sh update.sh

# If Octane is enabled, restart the daemon process
# aaPanel > App Store > Tools > Supervisor > Restart Octane
```

### Routine Maintenance
- Regular log checking
- Monitor system resource usage
- Regular backup of database and configuration files

## Troubleshooting

### Common Issues
1. **Empty Admin Dashboard**: If the admin panel is blank, run `git submodule update --init --recursive --force` to restore the theme files.
2. Changes to admin path require service restart to take effect
3. Any code changes after enabling Octane require restart to take effect
3. When PHP extension installation fails, check if PHP version is correct
4. For database connection failures, check database configuration and permissions

## Enable WebSocket Real-time Sync (Optional)

WebSocket enables real-time synchronization of configurations and user changes to nodes.

### 1. Start WS Server

Add a WebSocket daemon process in aaPanel Supervisor:
- Name: `Xboard-WS`
- Run User: `www`
- Running Directory: Site directory
- Start Command: `php artisan ws-server start`
- Process Count: 1

### 2. Configure Nginx

Add the WebSocket location **before** the main `location ^~ /` block in your site's Nginx configuration:
```nginx
location /ws/ {
    proxy_pass http://127.0.0.1:8076;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_read_timeout 60s;
}
```

### 3. Restart Services

Restart the Octane and WS Server processes in Supervisor.

> The node will automatically detect WebSocket availability during handshake. No extra configuration is needed on the node side.

---

### En Installation Docker Compose (`docs/en/installation/docker-compose.md`)

# Quick Deployment Guide with Docker Compose

This guide explains how to quickly deploy Xboard using Docker Compose. By default, it uses SQLite database, eliminating the need for a separate MySQL installation.

The Xboard container must run **PHP 8.2.35 or later**, with the latest security patch for its PHP release series. Host PHP is not required.

### 1. Environment Preparation

Install Docker:
```bash
curl -sSL https://get.docker.com | bash

# For CentOS systems, also run:
systemctl enable docker
systemctl start docker
```

### 2. Deployment Steps

1. Clone the `compose` branch (it ships `compose.sample.yaml` and the other `compose.*.sample.yaml` variants):
   ```bash
   git clone -b compose --depth 1 https://github.com/cedar2025/Xboard
   cd Xboard
   cp compose.sample.yaml compose.yaml
   ```

2. Install database:  

- Quick installation (Recommended for beginners)
```bash
docker compose run -it --rm \
    -e ENABLE_SQLITE=true \
    -e ENABLE_REDIS=true \
    -e ADMIN_ACCOUNT=admin@demo.com \
    xboard php artisan xboard:install
```
- Custom configuration installation (Advanced users)
```bash
docker compose run -it --rm xboard php artisan xboard:install
```
> Please save the admin dashboard URL, username, and password shown after installation
> The repository ships **four** compose templates in the `compose` branch — pick the one matching your setup, copy it to `compose.yaml`, then run the install command:
>
> | File | Network | When to use |
> |------|---------|-------------|
> | `compose.sample.yaml` | bridge + ports `7001:7001` | bare docker, custom reverse proxy, aaPanel + Docker (default) |
> | `compose.host.sample.yaml` | `network_mode: host` | aaPanel native (openresty on host) |
> | `compose.1panel.sample.yaml` | bridge + external `1panel-network` | 1Panel users (so the container can reach 1Panel-managed MySQL/Redis) |
> | `compose.split.sample.yaml` | multi-container (web/horizon/ws-server/redis split) | K8s migration, advanced scaling |
>
> The local `compose.yaml` is gitignored so your edits survive `git pull` when you do clone the repo.

3. Start services:
```bash
docker compose up -d
```

4. Access the site:
- Default port: 7001
- Website URL: http://your-server-ip:7001

### 3. Version Updates

```bash
cd Xboard
docker compose pull && docker compose up -d
```

The container always runs `php artisan xboard:update` (migrate + plugin install + version cache + theme refresh) on boot, so no extra command is required.

> **Using a `compose.yaml` from before 2026-04-19?** That template did not auto-run `xboard:update` on container start, so use the following command to upgrade instead:
> ```bash
> docker compose pull && docker compose run -it --rm web php artisan xboard:update && docker compose up -d
> ```

For security, upgrade to an image running **PHP 8.2.35 or later** with the latest security fixes for its PHP release series.

### 4. Version Rollback

1. Modify the version number in `docker-compose.yaml` to the version you want to roll back to
2. Execute: `docker compose up -d`

### Important Notes

- If you need to use MySQL, please install it separately and redeploy
- Code changes require service restart to take effect
- You can configure Nginx reverse proxy to use port 80

---

### En Migration Config (`docs/en/migration/config.md`)

# Configuration Migration Guide

This guide explains how to migrate configuration files from v2board to Xboard. Xboard stores configurations in the database instead of files.

### 1. Docker Compose Environment

1. Prepare configuration file:
```bash
# Create config directory
mkdir config

# Copy old configuration file
cp old-project-path/config/v2board.php config/
```

2. Modify `docker-compose.yaml`, uncomment the following line:
```yaml
- ./config/v2board.php:/www/config/v2board.php
```

3. Execute migration:
```bash
docker compose run -it --rm web php artisan migrateFromV2b config
```

### 2. aaPanel Environment

1. Copy configuration file:
```bash
cp old-project-path/config/v2board.php config/v2board.php
```

2. Execute migration:
```bash
php artisan migrateFromV2b config
```

### 3. aaPanel + Docker Environment

1. Copy configuration file:
```bash
cp old-project-path/config/v2board.php config/v2board.php
```

2. Execute migration:
```bash
docker compose run -it --rm web php artisan migrateFromV2b config
```

### Important Notes

- After modifying the admin path, service restart is required:
  - Docker environment: `docker compose restart`
  - aaPanel environment: Restart the Octane daemon process

---

### En Migration V2board 1.7.3 (`docs/en/migration/v2board-1.7.3.md`)

# V2board 1.7.3 Migration Guide

This guide explains how to migrate from V2board version 1.7.3 to Xboard.

### 1. Database Changes Overview

- `v2_stat_order` table renamed to `v2_stat`:
  - `order_amount` → `order_total`
  - `commission_amount` → `commission_total`
  - New fields added:
    - `paid_count` (integer, nullable)
    - `paid_total` (integer, nullable)
    - `register_count` (integer, nullable)
    - `invite_count` (integer, nullable)
    - `transfer_used_total` (string(32), nullable)

- New tables added:
  - `v2_log`
  - `v2_server_hysteria`
  - `v2_server_vless`

### 2. Prerequisites

⚠️ Please complete the basic Xboard installation first (SQLite not supported):
- [Docker Compose Deployment](../installation/docker-compose.md)
- [aaPanel + Docker Deployment](../installation/aapanel-docker.md)
- [aaPanel Deployment](../installation/aapanel.md)

### 3. Migration Steps

#### Docker Environment

```bash
# 1. Stop services
docker compose down

# 2. Clear database
docker compose run -it --rm xboard php artisan db:wipe

# 3. Import old database (Important)
# Please manually import the V2board 1.7.3 database

# 4. Execute migration
docker compose run -it --rm xboard php artisan migratefromv2b 1.7.3
```

#### aaPanel Environment

```bash
# 1. Clear database
php artisan db:wipe

# 2. Import old database (Important)
# Please manually import the V2board 1.7.3 database

# 3. Execute migration
php artisan migratefromv2b 1.7.3
```

### 4. Configuration Migration

After completing the data migration, you need to migrate the configuration file:
- [Configuration Migration Guide](./config.md)

---

### En Migration V2board 1.7.4 (`docs/en/migration/v2board-1.7.4.md`)

# V2board 1.7.4 Migration Guide

This guide explains how to migrate from V2board version 1.7.4 to Xboard.

### 1. Database Changes Overview

- New table added:
  - `v2_server_vless`

### 2. Prerequisites

⚠️ Please complete the basic Xboard installation first (SQLite not supported):
- [Docker Compose Deployment](../installation/docker-compose.md)
- [aaPanel + Docker Deployment](../installation/aapanel-docker.md)
- [aaPanel Deployment](../installation/aapanel.md)

### 3. Migration Steps

#### Docker Environment

```bash
# 1. Stop services
docker compose down

# 2. Clear database
docker compose run -it --rm xboard php artisan db:wipe

# 3. Import old database (Important)
# Please manually import the V2board 1.7.4 database

# 4. Execute migration
docker compose run -it --rm xboard php artisan migratefromv2b 1.7.4
```

#### aaPanel Environment

```bash
# 1. Clear database
php artisan db:wipe

# 2. Import old database (Important)
# Please manually import the V2board 1.7.4 database

# 3. Execute migration
php artisan migratefromv2b 1.7.4
```

### 4. Configuration Migration

After completing the data migration, you need to migrate the configuration file:
- [Configuration Migration Guide](./config.md)

---

### En Migration V2board Dev (`docs/en/migration/v2board-dev.md`)

# V2board Dev Migration Guide

This guide explains how to migrate from V2board Dev version (2023/10/27) to Xboard.

⚠️ Please upgrade to version 2023/10/27 following the official guide before proceeding with migration.

### 1. Database Changes Overview

- `v2_order` table:
  - Added `surplus_order_ids` (text, nullable) - Deduction orders

- `v2_plan` table:
  - Removed `daily_unit_price` - Affects period value
  - Removed `transfer_unit_price` - Affects traffic value

- `v2_server_hysteria` table:
  - Removed `ignore_client_bandwidth` - Affects bandwidth configuration
  - Removed `obfs_type` - Affects obfuscation type configuration

### 2. Prerequisites

⚠️ Please complete the basic Xboard installation first (SQLite not supported):
- [Docker Compose Deployment](../installation/docker-compose.md)
- [aaPanel + Docker Deployment](../installation/aapanel-docker.md)
- [aaPanel Deployment](../installation/aapanel.md)

### 3. Migration Steps

#### Docker Environment

```bash
# 1. Stop services
docker compose down

# 2. Clear database
docker compose run -it --rm xboard php artisan db:wipe

# 3. Import old database (Important)
# Please manually import the V2board Dev database

# 4. Execute migration
docker compose run -it --rm xboard php artisan migratefromv2b dev231027
```

#### aaPanel Environment

```bash
# 1. Clear database
php artisan db:wipe

# 2. Import old database (Important)
# Please manually import the V2board Dev database

# 3. Execute migration
php artisan migratefromv2b dev231027
```

### 4. Configuration Migration

After completing the data migration, you need to migrate the configuration file:
- [Configuration Migration Guide](./config.md)

---

--- METRICS ---
- Files Extracted: 13
- Estimated Token Budget: ~13503 tokens
- Canonical Reference: https://codewiki.google/github.com/cedar2025/Xboard
