Technical Documentation: cedar2025/Xboard
โน๏ธ Provenance: Multi-Tier Ingestion ยท CodeWiki Reference
Overview (`README.md`)
Xboard
๐ 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
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 [email protected] \
xboard php artisan xboard:install && \
docker compose up -dAfter 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 - 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
- Deploy with Docker Compose
- Deploy with aaPanel
- Deploy with aaPanel + Docker (Recommended)
Migration Guides
๐ ๏ธ 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
- Restart required after modifying admin path:
docker compose restart- For aaPanel installations, restart the Octane daemon process
๐ค Contributing
Issues and Pull Requests are welcome to help improve the project.
๐ Star History
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 | ๆฏๅฆๅผๅฏๆฏไป้็ฅๅ่ฝ |
ไฝฟ็จๆต็จ
ๆฐ็จๆทไฝฟ็จๆต็จ
- ็จๆท้ฆๆฌกไฝฟ็จ Bot๏ผๅ้
/start - ๆ นๆฎๆ็คบ็ปๅฎ่ดฆๅท๏ผ
/bind [่ฎข้ ้พๆฅ] - ็ปๅฎๆๅๅๅณๅฏไฝฟ็จๅ ถไปๅ่ฝ
ๆฅๅธธไฝฟ็จๆต็จ
- ๆฅ็ๆต้๏ผ
/traffic - ่ทๅ่ฎข้
้พๆฅ๏ผ
/getlatesturl - ็ฎก็็ปๅฎ๏ผ
/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
Accurate Control
- Precise counting of online devices
- Real-time monitoring of device status
- Accurate device identification
Performance Optimization
- Minimal impact on system performance
- Efficient device tracking
- Optimized resource usage
User Experience
- Smooth connection experience
- Clear error messages
- Graceful handling of limit exceeded cases
Implementation Details
1. Device Identification
Device ID Generation
public function generateDeviceId($user, $request) {
return md5(
$user->id .
$request->header('User-Agent') .
$request->ip()
);
}Device Information Storage
[
'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
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
public function updateDeviceStatus($userId, $deviceId) {
Redis::hset(
"user:{$userId}:devices",
$deviceId,
json_encode([
'last_active' => now(),
'status' => 'online'
])
);
}3. Cleanup Mechanism
Inactive Device Cleanup
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
Device Limit Exceeded
phpclass DeviceLimitExceededException extends Exception { protected $message = 'Device limit exceeded'; protected $code = 4001; }Invalid Device
phpclass InvalidDeviceException extends Exception { protected $message = 'Invalid device'; protected $code = 4002; }
Error Messages
return [
'device_limit_exceeded' => 'Maximum number of devices reached',
'invalid_device' => 'Device not recognized',
'device_expired' => 'Device session expired'
];Performance Considerations
Cache Strategy
- Use Redis for device tracking
- Implement cache expiration
- Optimize cache structure
Database Operations
- Minimize database queries
- Use batch operations
- Implement query optimization
Memory Management
- Efficient data structure
- Regular cleanup of expired data
- Memory usage monitoring
Security Measures
Device Verification
- Validate device information
- Check for suspicious patterns
- Implement rate limiting
Data Protection
- Encrypt sensitive information
- Implement access control
- Regular security audits
Future Improvements
Enhanced Features
- Device management interface
- Device activity history
- Custom device names
Performance Optimization
- Improved caching strategy
- Better cleanup mechanism
- Reduced memory usage
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
Database Optimization
- Added indexes for frequently queried fields
- Optimized slow queries
- Implemented query caching
Cache Strategy
- Using Redis for session storage
- Caching frequently accessed data
- Implementing cache warming
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
Infrastructure Level
- Implement horizontal scaling
- Add load balancing
- Optimize network configuration
Application Level
- Further optimize database queries
- Implement more efficient caching strategies
- Reduce memory usage
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`
{
"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
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
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
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:
// 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:listcommand to get the latest supported hooks.
Filter Hooks
Used to modify data:
// 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:
$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
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):
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:
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 commandCreate Command Class
Example: TestCommand.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
# 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 --helpBest Practices
- Command Naming: Use
plugin-name:actionformat, e.g.,telegram:test - Error Handling: Wrap main logic with try-catch
- Return Values: Return 0 for success, 1 for failure
- User Friendly: Provide clear help information and error messages
- 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
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- Stringnumber- Numberboolean- Booleanjson- Arrayyaml
๐ฏ 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
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
\Log::info('Plugin operation', ['data' => $data]);
\Log::error('Plugin error', ['error' => $e->getMessage()]);2. Configuration Checking
// Check required configuration
if (!$this->getConfig('required_key')) {
return $this->fail([400, 'Missing configuration']);
}3. Development Mode
if (config('app.debug')) {
// Detailed debug information for development environment
}๐ Plugin Lifecycle
- Installation: Validate configuration, register to database
- Enable: Load plugin, register hooks and routes
- 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
# 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 info2. TelegramExtra Plugin Commands
# 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=json3. Example Plugin Commands
# Basic usage
php artisan example:hello
# With arguments and options
php artisan example:hello Bear --message="Welcome!"Development Best Practices
1. Command Naming Conventions
// โ
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
public function handle(): int
{
try {
// Main logic
return $this->executeAction();
} catch (\Exception $e) {
$this->error('Operation failed: ' . $e->getMessage());
return 1;
}
}3. User Interaction
// 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
// 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
// One plugin can have multiple commands
plugins/YourPlugin/Commands/
โโโ BackupCommand.php # Backup command
โโโ CleanupCommand.php # Cleanup command
โโโ StatsCommand.php # Statistics command
โโโ TestCommand.php # Test command2. Inter-Command Communication
// 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
// 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
# View command help
php artisan your-plugin:command --help
# Verbose output
php artisan your-plugin:command --verbose
# Debug mode
php artisan your-plugin:command --debug2. Logging
// Log in commands
Log::info('Plugin command executed', [
'command' => $this->signature,
'arguments' => $this->arguments(),
'options' => $this->options()
]);3. Performance Monitoring
// 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.
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:
curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_start.sh && \
sudo bash quick_start.sh2. Environment Configuration
Install from App Store:
- OpenResty (any version)
- โ ๏ธ Check "External Port Access" to open firewall
- MySQL 5.7 (Use MariaDB for ARM architecture)
- OpenResty (any version)
Create Database:
- Database name:
xboard - Username:
xboard - Access rights: All hosts (%)
- Save the database password for installation
- Database name:
3. Deployment Steps
Add Website:
- Go to "Website" > "Create Website" > "Reverse Proxy"
- Domain: Enter your domain
- Code:
xboard - Proxy address:
127.0.0.1:7001
Configure Reverse Proxy:
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/Connectionpair above is enough; no separate/ws/location is needed. To opt out and expose Octane /:8076directly, setENABLE_CADDY=falseincompose.yaml.
- Install Xboard:
# 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- Prepare
compose.yamlfrom the 1Panel-specific sample. This sample joins the external1panel-networkso the container can reach the 1Panel-managed MySQL/Redis containers by their hostname:
cp compose.1panel.sample.yaml compose.yamlThe file is gitignored so your edits survive git pull. See docker-compose.md for tuning environment variables (RESOURCE_PROFILE, ENABLE_HORIZON, ENABLE_REDIS, etc.) and the other compose.*.sample.yaml alternatives.
- Initialize Installation:
docker compose run -it --rm xboard php artisan xboard:installโ ๏ธ Important Configuration Notes:
Database Configuration
- Database Host: Choose based on your deployment:
- If database and Xboard are in the same network, use
mysql - If connection fails, go to: Database -> Select Database -> Connection Info -> Container Connection, and use the "Host" value
- If using external database, enter your actual database host
- If database and Xboard are in the same network, use
- 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
- Database Host: Choose based on your deployment:
Redis Configuration
- Choose to use built-in Redis
- No additional configuration needed
Administrator Information
- Save the admin credentials displayed after installation
- Note down the admin panel access URL
After configuration, start the services:
docker compose up -d- Start Services:
docker compose up -d4. Version Update
docker compose pull && docker compose up -dThe 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.yamlfrom before 2026-04-19? That template did not auto-runxboard:updateon container start, so use the following command to upgrade instead:bashdocker 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
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
curl -sSL https://www.aapanel.com/script/install_6.0_en.sh -o install_6.0_en.sh && \
bash install_6.0_en.sh aapanel2. Basic Environment Setup
2.1 Install Docker
# Install Docker
curl -sSL https://get.docker.com | bash
# For CentOS systems, also run:
systemctl enable docker
systemctl start docker2.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
- Navigate to: aaPanel > Website > Add site
- Fill in the information:
- Domain: Enter your site domain
- Database: Select MySQL
- PHP Version: Select Pure Static
3.2 Deploy Xboard
# 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
docker compose up -d3.4 Configure Reverse Proxy
Add the following content to your site configuration:
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/Connectionpair above is enough; no separate/ws/location is needed. To opt out and expose Octane /:8076directly, setENABLE_CADDY=falseincompose.yaml.
Maintenance Guide
Version Updates
docker compose pull && docker compose up -dThe 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.yamlfrom before 2026-04-19? That template did not auto-runxboard:updateon container start, so use the following command to upgrade instead:bashdocker 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:
- Empty Admin Dashboard: If the admin panel is blank, run
git submodule update --init --recursive --forceto restore the theme files. - System requirements are met
- All required ports are available
- Docker services are running properly
- Nginx configuration is correct
- 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
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
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 aapanel2. 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
- Navigate to: aaPanel > Website > Add site
- 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
# 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.sh3.3 Configure Site
- Set running directory to
/public - Add rewrite rules:
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
- Install Supervisor
- Add queue daemon process:
- Name:
Xboard - Run User:
www - Running Directory: Site directory
- Start Command:
php artisan horizon - Process Count: 1
- Name:
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
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
# 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 OctaneRoutine Maintenance
- Regular log checking
- Monitor system resource usage
- Regular backup of database and configuration files
Troubleshooting
Common Issues
- Empty Admin Dashboard: If the admin panel is blank, run
git submodule update --init --recursive --forceto restore the theme files. - Changes to admin path require service restart to take effect
- Any code changes after enabling Octane require restart to take effect
- When PHP extension installation fails, check if PHP version is correct
- 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:
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:
curl -sSL https://get.docker.com | bash
# For CentOS systems, also run:
systemctl enable docker
systemctl start docker2. Deployment Steps
Clone the
composebranch (it shipscompose.sample.yamland the othercompose.*.sample.yamlvariants):bashgit clone -b compose --depth 1 https://github.com/cedar2025/Xboard cd Xboard cp compose.sample.yaml compose.yamlInstall database:
- Quick installation (Recommended for beginners)
docker compose run -it --rm \
-e ENABLE_SQLITE=true \
-e ENABLE_REDIS=true \
-e [email protected] \
xboard php artisan xboard:install- Custom configuration installation (Advanced users)
docker compose run -it --rm xboard php artisan xboard:installPlease save the admin dashboard URL, username, and password shown after installation
The repository ships four compose templates in thecomposebranch โ pick the one matching your setup, copy it tocompose.yaml, then run the install command:
File Network When to use compose.sample.yamlbridge + ports 7001:7001bare docker, custom reverse proxy, aaPanel + Docker (default) compose.host.sample.yamlnetwork_mode: hostaaPanel native (openresty on host) compose.1panel.sample.yamlbridge + external 1panel-network1Panel users (so the container can reach 1Panel-managed MySQL/Redis) compose.split.sample.yamlmulti-container (web/horizon/ws-server/redis split) K8s migration, advanced scaling The local
compose.yamlis gitignored so your edits survivegit pullwhen you do clone the repo.
- Start services:
docker compose up -d- Access the site:
- Default port: 7001
- Website URL: http://your-server-ip:7001
3. Version Updates
cd Xboard
docker compose pull && docker compose up -dThe 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.yamlfrom before 2026-04-19? That template did not auto-runxboard:updateon container start, so use the following command to upgrade instead:bashdocker 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
- Modify the version number in
docker-compose.yamlto the version you want to roll back to - 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
- Prepare configuration file:
# Create config directory
mkdir config
# Copy old configuration file
cp old-project-path/config/v2board.php config/- Modify
docker-compose.yaml, uncomment the following line:
- ./config/v2board.php:/www/config/v2board.php- Execute migration:
docker compose run -it --rm web php artisan migrateFromV2b config2. aaPanel Environment
- Copy configuration file:
cp old-project-path/config/v2board.php config/v2board.php- Execute migration:
php artisan migrateFromV2b config3. aaPanel + Docker Environment
- Copy configuration file:
cp old-project-path/config/v2board.php config/v2board.php- Execute migration:
docker compose run -it --rm web php artisan migrateFromV2b configImportant Notes
- After modifying the admin path, service restart is required:
- Docker environment:
docker compose restart - aaPanel environment: Restart the Octane daemon process
- Docker environment:
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_ordertable renamed tov2_stat:order_amountโorder_totalcommission_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_logv2_server_hysteriav2_server_vless
2. Prerequisites
โ ๏ธ Please complete the basic Xboard installation first (SQLite not supported):
3. Migration Steps
Docker Environment
# 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.3aaPanel Environment
# 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.34. Configuration Migration
After completing the data migration, you need to migrate the configuration file:
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):
3. Migration Steps
Docker Environment
# 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.4aaPanel Environment
# 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.44. Configuration Migration
After completing the data migration, you need to migrate the configuration file:
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_ordertable:- Added
surplus_order_ids(text, nullable) - Deduction orders
- Added
v2_plantable:- Removed
daily_unit_price- Affects period value - Removed
transfer_unit_price- Affects traffic value
- Removed
v2_server_hysteriatable:- Removed
ignore_client_bandwidth- Affects bandwidth configuration - Removed
obfs_type- Affects obfuscation type configuration
- Removed
2. Prerequisites
โ ๏ธ Please complete the basic Xboard installation first (SQLite not supported):
3. Migration Steps
Docker Environment
# 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 dev231027aaPanel Environment
# 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 dev2310274. Configuration Migration
After completing the data migration, you need to migrate the configuration file:
--- METRICS ---
- Files Extracted: 13
- Estimated Token Budget: ~13503 tokens
- Canonical Reference: https://codewiki.google/github.com/cedar2025/Xboard