Files
XC_VM/docs/en/builds/build_system.md
T
Divarion-D 76844fef11 docs: restructure, fix PSR-4 drift, and unify en/ru
Overhaul the Docsify documentation (English + Russian) so it matches the current
codebase and follows one consistent pattern.

Content accuracy (post-migration):
- Rewrite development/autoloader.md to PSR-4 / Composer (the old XC_Autoloader
  scanner, igbinary tmp/cache/autoload_map and registerDirectories are gone).
- PascalCase every source path (src/core -> src/Core, domain/Stream, cli/Commands,
  public/Controllers, Infrastructure/Redis, ...) across all docs.
- Replace the removed autoload.php references with vendor/autoload.php
  (build_system, bootstrap-contexts, error-handling, modules).
- ssl-generation: note that the installer now auto-generates a unique self-signed
  certificate before Nginx starts.

Common pattern (Clean & uniform):
- Strip emoji from headings; remove the in-page Navigation blocks (the Docsify
  sidebar already provides navigation).
- One H1 + intro per doc; uniform "Related files" / "Связанные файлы" section,
  added to the code-centric docs that lacked it.

Structure:
- Remove the empty stray docs/api/; move updates_checklist.md into builds/;
  link the previously-orphaned ucs-integration.md.
- Regroup the sidebars (split the oversized guides group into Developer Guides /
  Security & Access / Integrations; fold builds into Build & Release).

Augment:
- dev-workflow: Local Setup (make dev-tools) + Quality Checks (phpstan, cs, gates).
- build_system: Composer Dependencies section (committed prod-only vendor,
  committed lock, dev tools via composer install, no build-time vendor step).

en/ru parity:
- Apply the same structure, fixes and pattern to docs/ru/ (translated), including
  a new Russian ucs-integration.md. The en and ru file sets are now identical.
2026-06-26 15:56:15 +03:00

9.1 KiB

XC_VM Build System (MAIN vs LB)

How XC_VM produces two build variants from a single codebase: a full MAIN server and a lightweight Load Balancer (LB) server.


Build Variants

XC_VM supports two deployment roles from a single source tree:

Variant Archive Purpose
MAIN xc_vm.tar.gz Full application — admin panel, streaming, all modules, cron jobs
LB (Load Balancer) loadbalancer.tar.gz Streaming-only server — no admin panel, no user management

MAIN is the primary server that manages everything: admin UI, database writes, user/device management, EPG processing, backups, etc.

LB is a lightweight streaming node that receives streams from MAIN (or other sources) and delivers them to clients. It connects to the master database in read-only mode and has no admin panel or management capabilities.


Makefile Targets

Target Output Description
make main dist/xc_vm.tar.gz Full MAIN build
make lb dist/loadbalancer.tar.gz LB build (streaming-only subset)
make main_update dist/update.tar.gz Incremental MAIN update
make lb_update dist/loadbalancer_update.tar.gz Incremental LB update
make new Both full builds Shortcut: main + lb

Additional outputs:

  • XC_VM.zip — installer package (install/ + xc_vm.tar.gz)
  • hashes.md5 — MD5 checksums for integrity verification

Composer Dependencies

src/vendor/ (the Composer PSR-4 autoloader plus the production dependencies) is committed and shipped as-is — the deploy path has no Composer and never runs composer install. It is kept production-only via composer install --no-dev, so both build variants ship a lean vendor with no dev tooling.

  • src/composer.lock is committed so composer install is reproducible.
  • Dev tools (PHPStan, PHP-CS-Fixer) are require-dev and are not in the committed vendor or the archives. Developers and CI add them with make dev-tools (composer install); the check-vendor-prod-only gate fails if a dev package is ever committed under src/vendor/.
  • There is no build-time vendor step — make main / make lb copy the committed vendor/ directly into the archive.

What Goes Into Each Build

MAIN Build

The MAIN build contains the entire src/ directory.

LB Build — Included Directories

Only these directories are copied into the LB archive:

bin/        Cli/        config/     content/    Core/
Domain/     Infrastructure/         public/     resources/
signals/    Streaming/  tmp/        www/

Plus root files: bootstrap.php, console.php, service, update.

LB Build — Excluded Content

After copying, admin-specific content is removed from the LB build:

Directories removed:

Path Reason
bin/install/ Installer scripts (not needed on LB)
bin/redis/ Redis binary (LB doesn't run its own Redis)
bin/nginx/conf/codes/ Error code pages (admin UI)
Public/Controllers/Admin/ Admin panel controllers
Public/Controllers/Player/ Player panel controllers
Public/Controllers/Reseller/ Reseller panel controllers
Public/Views/ Panel templates
Public/assets/ Panel static assets
Public/routes/ Panel route maps
Domain/User/ User management
Domain/Device/ Device registration
Domain/Auth/ Auth management (panel auth)
resources/langs/ Language resource files
resources/libs/ Admin library resources

Files removed:

File Reason
Public/Controllers/Api/AdminApiController.php Full admin API removed from LB
Public/Controllers/Api/ResellerRestApiController.php Reseller API removed from LB
Infrastructure/legacy/reseller_api.php Legacy reseller API bootstrap not needed on LB
www/xplugin.php, www/probe.php, www/playlist.php Admin endpoints
www/player_api.php, www/epg.php, www/enigma2.php Client API endpoints (served by MAIN)
www/stream/auth.php Auth endpoint removed from LB package
www/admin/api.php, www/admin/proxy_api.php Admin API
bin/maxmind/GeoLite2-City.mmdb GeoIP DB shipped separately
config/rclone.conf Backup config
Domain/Epg/EPG.php EPG processing class
bin/nginx/conf/gzip.conf Gzip config (LB uses own)

CLI commands removed:

File Reason
Cli/Commands/MigrateCommand.php Migration is MAIN-only
Cli/Commands/CacheHandlerCommand.php Cache handler is MAIN-only
Cli/Commands/ServerInstallCommand.php Server installer (not needed on LB itself)
Cli/Commands/LbInstallFlow.php LB install helper (not needed on LB itself)
Cli/Commands/ProxyInstallFlow.php Proxy install helper (not needed on LB itself)

Cron jobs removed:

File Reason
Cli/CronJobs/RootMysqlCronJob.php DB maintenance (MAIN-only)
Cli/CronJobs/BackupsCronJob.php Backups (MAIN-only)
Cli/CronJobs/CacheEngineCronJob.php Full cache rebuild (MAIN-only)
Cli/CronJobs/EpgCronJob.php EPG processing (MAIN-only)
Cli/CronJobs/UpdateCronJob.php Update check (MAIN-only)
Cli/CronJobs/ProvidersCronJob.php Provider sync (MAIN-only)
Cli/CronJobs/SeriesCronJob.php Series metadata (MAIN-only)

Note: Module-related crons (TMDB, Plex, Watch) now live inside modules/<name>/ and are excluded from LB builds automatically since modules/ is not in LB_DIRS.

LB Build — Replaced Configs

These files from lb_configs/ replace the MAIN versions:

Source Target Purpose
lb_configs/nginx.conf bin/nginx/conf/nginx.conf Performance-tuned nginx for streaming
lb_configs/live.conf bin/nginx_rtmp/conf/live.conf RTMP callback hooks

MAIN vs LB — Key Differences

Aspect MAIN LB
Admin panel ✅ Full UI ❌ Not included
Database role Read + Write Read-only consumer
User/device management ✅ ❌
EPG processing ✅ ❌
Backups ✅ ❌
Migration tool ✅ ❌
Stream delivery ✅ ✅
RTMP ingestion ✅ ✅
Transcoding (FFmpeg) ✅ ✅
CLI commands 26 ~15 (admin-only removed)
Cron jobs 25 ~16 (admin-only removed)
Module system ✅ ❌

LB Nginx Configuration

The LB build uses a specialized nginx config optimized for high-throughput streaming:

Setting Value Purpose
Worker processes auto Scale to CPU cores
Worker connections 16,000 High concurrency per worker
Max file descriptors 300,000 System resource limit
Thread pool pool_xc_vm (32 threads) Async I/O for streaming
Gzip OFF Streaming data is already compressed
Access logs OFF Reduce I/O overhead
Rate limiting 20 req/s per IP DDoS mitigation
Send timeout 20 min Support long-running streams

RTMP hooks (lb_configs/live.conf) route authentication through local HTTP callbacks instead of the admin panel:

on_play http://127.0.0.1:8080/stream/rtmp;
on_publish http://127.0.0.1:8080/stream/rtmp;
on_play_done http://127.0.0.1:8080/stream/rtmp;

Runtime Behavior on LB

Conditional Command Loading

console.php uses file_exists() guards for commands that may not exist on LB servers:

if (file_exists(__DIR__ . '/Cli/Commands/CacheHandlerCommand.php')) {
    $rRegistry->register(new CacheHandlerCommand());
}

This prevents crashes when LB attempts to register a command whose file was removed during the build.

Streaming Dependency Chain

LB servers retain the full streaming pipeline:

www/stream/*.php
  ├── www/stream/init.php
  ├── vendor/autoload.php (Composer PSR-4 autoloader)
  ├── bootstrap.php (lightweight stream/bootstrap path)
  ├── Core/* (Config, Database, Cache, Auth, Http, Logging, Util)
  ├── Domain/Stream, Domain/Server, Domain/Vod, Domain/Bouquet
  ├── Streaming/* (Auth, Delivery, Codec, Protection)
  ├── Infrastructure/Redis, Infrastructure/Database
  └── resources/data

Adding New Code to Builds

New streaming-relevant directory under src/

Add it to LB_DIRS in the Makefile:

LB_DIRS = bin cli config content core domain ... your_dir

New admin-only directory

Add it to LB_DIRS_TO_REMOVE:

LB_DIRS_TO_REMOVE = ... your_dir/admin_stuff

New admin-only file

Add it to LB_FILES_TO_REMOVE:

LB_FILES_TO_REMOVE = ... your_dir/admin_file.php

New CLI command (admin-only)

  1. Add file_exists() guard in console.php
  2. Add the file to LB_FILES_TO_REMOVE

Build Verification

After modifying the build, verify both variants:

# Build both
make new

# Check LB contains streaming code
tar -tzf dist/loadbalancer.tar.gz | grep -cE "Core/|Domain/Stream|Streaming/"
# Expected: > 0

# Check LB does NOT contain admin code
tar -tzf dist/loadbalancer.tar.gz | grep -cE "admin/|player/|ministra|reseller"
# Expected: 0

# Compare sizes (LB should be significantly smaller)
ls -lh dist/xc_vm.tar.gz dist/loadbalancer.tar.gz