# Contributing to XC_VM Thank you for considering contributing! XC_VM is an open-source, Xtream-Codes-style IPTV management panel (PHP 8.1+, AGPL-3.0) โ€” a modular monolith migrated to Composer PSR-4. This guide covers the layout, the local dev loop, the checks CI enforces, and how to open a good pull request. ## ๐Ÿ“Œ General Guidelines - Minimally use AI; you own every line you submit and must understand it. - Follow the project's coding style and best practices. - Keep pull requests focused on a single change. - Write meaningful commit messages (Conventional Commits, English). - Document behaviour that isn't obvious from the code. - If you refactor and aren't sure code is unused elsewhere, comment it out with a note instead of deleting โ€” it can be removed after the next release. ## ๐Ÿงญ Repository Layout (read this first) The trap for new contributors: **the application lives under `src/`, not the repo root.** - **`src/` is the application root and the deploy root.** `composer.json`, `vendor/`, `bootstrap.php`, `console.php` all live in `src/`. It maps 1:1 to the install root on a server (`src/Core/X.php` โ†’ `/home/xc_vm/Core/X.php`). - **PSR-4:** `XcVm\` โ†’ `src/` (e.g. `XcVm\Core\Database\DatabaseHandler` = `src/Core/Database/DatabaseHandler.php`). - **The repo root holds build & CI tooling only:** `Makefile`, `tools/`, `tests/`, `install/`, `lb_configs/`, `build/`, `docs/`. Two build flavours are produced from the same tree: the full **MAIN** panel and a stripped **Load Balancer (LB)** archive (restreaming only โ€” admin/reseller/ player code, installers, and privileged commands removed). **Modules are MAIN-only.** Deeper architecture notes live in `docs/en/development/` and the repo `CLAUDE.md`. ## โš ๏ธ Hard Constraints - **`src/vendor/` is committed and PRODUCTION-ONLY.** Never run `composer install` on a deploy path. To change the autoload map, run `composer dump-autoload` from `src/`. After changing dependencies, re-commit a `composer install --no-dev` vendor tree plus the updated `composer.lock`. - **Modules own their DB schema** via file migrations (`src/Modules//migrations/.up.sql`/`.down.sql`). Do **not** add module tables to `src/bin/install/database.sql`, and core must not touch module-owned tables directly โ€” dispatch an event and let the module clean up. - **Bundled binaries are regular Git objects (not Git LFS).** The `ffmpeg`/`ffprobe`, `redis-server`, `yt-dlp`, MaxMind DBs, `login-bg.mp4`, etc. are committed as plain binary blobs (marked `-text -diff` in `.gitattributes`) โ€” a normal `git clone` fetches them whole, no `git lfs pull` needed. A `verify_no_lfs_pointers` build gate still guards against stray legacy LFS pointer stubs. - Outbound HTTPS from PHP must use **cURL** โ€” `file_get_contents()` over https does not work in this environment. ## ๐Ÿ› ๏ธ Local Setup You need PHP 8.1+, `git`, `make`, and Composer. ```sh git clone https://github.com/Vateron-Media/XC_VM.git cd XC_VM make dev-tools # composer install in src/ โ€” adds PHPStan + # phpcs (Slevomat) + unused-public to src/vendor ``` `make dev-tools` installs the `require-dev` toolchain (PHPStan 2.2.9, PHP_ CodeSniffer + Slevomat, Tomas Votruba's unused-public) into `src/vendor`. These are **not** in the committed vendor tree, so run it before the checks below. When you're done, `make dev-clean` prunes `src/vendor` back to production-only. ## ๐Ÿ” The Dev Loop: Deploying to a Live Box **Prerequisite โ€” you need a working XC_VM install to sync onto.** `sync-dev.sh` does not provision a server; it pushes changed code onto an existing install root (`/home/xc_vm/` by default). So first stand up a throwaway/test box the normal way โ€” install the panel from a release (see [Quick Install](README.md#-quick-install) in the README: download `XC_VM.zip`, `unzip`, `sudo python3 install`). Only once the panel is installed and running does `sync-dev.sh` become useful for pushing your local edits onto it. Once you have that box, use `tools/sync-dev.sh` to iterate against it **without** building a release. It works out which files under `src/` your commits changed and copies their **full current content** to the server's install root. Files your commits **deleted are removed** on the server; renames delete the old path and copy the new one. It is a developer convenience โ€” it never runs DB migrations, ships binaries, or edits per-server config. For a real upgrade use the release archive + panel updater. ```sh # Preview the copy/delete plan โ€” never contacts the server; always safe: DEV_SERVER= tools/sync-dev.sh --dry-run # Push uncommitted edits to tracked files (fastest inner loop): DEV_SERVER= tools/sync-dev.sh --working --restart # Push committed work since the last sync (watermark in .dev-sync-state): DEV_SERVER= tools/sync-dev.sh --restart # Push everything since a tag / branch / sha: DEV_SERVER= tools/sync-dev.sh 2.4.1 --restart ``` Here `` is **usually the version tag of the panel currently installed on the box** (e.g. `2.4.1`). The box was installed from that release, so syncing `..HEAD` pushes exactly the changes your branch adds on top of it, nothing more. - `--working` โ€” also include uncommitted changes to tracked files (diff vs HEAD). - `--restart` โ€” restart the panel so OPcache reloads new **PHP** code. Slow (>1 min); run in the background under a short timeout. Pure CSS/JS/template changes are served statically and usually need only a hard refresh, not this. - `--cache` โ€” rebuild the settings cache (for settings-shaped changes). `RANGE` is a git range `A..B`, or a single ref `REF` (treated as `REF..HEAD`). Omitted, it continues from `.dev-sync-state` (or `HEAD~1..HEAD` on first run). SSH auth uses your keys by default; set `DEV_SSH_USER` / `DEV_SSH_PASS` (needs `sshpass`) to override. All SSH multiplexes over one ControlMaster socket so repeated syncs don't trip fail2ban. See the header of `tools/sync-dev.sh` (or `--help`) for the full reference. ## โœ… Pre-Commit Checks **Always run `make cs-fix` first.** It auto-formats your changes to the coding standard (K&R braces, tab indentation, spacing, import order) via phpcbf, so your diff matches what CI expects. Then run the checks below โ€” **CI runs the exact same set and will reject a PR that fails any of them:** ```sh make cs-fix # run FIRST โ€” auto-format to the coding standard (phpcbf) make cs # verify code style: PSR-12 base + K&R braces + tab indentation make phpstan # static analysis, level 5 (also catches syntax errors) make gates # PSR-4 regression gates (see below) php tests/phpunit.phar -c tests/phpunit.xml.dist # unit tests ``` `make cs-fix` applies everything auto-fixable; whatever `make cs` still reports afterwards (e.g. a missing parameter type hint) you fix by hand. `make gates` runs three CI blockers: - **`check-procedural-use`** โ€” every procedural/view file must `use`-import the `XcVm\` classes it references at the top (PHP `use` is positional; a bare short name faults at runtime). - **`verify-lb-archive`** โ€” the load-balancer build must contain no privileged code (admin/reseller/player UI, user/device domain, install/root crons). - **`check-vendor-prod-only`** โ€” the committed `src/vendor/` must stay production-only (no dev package tracked in the git index). Quick single-file syntax check while editing (no DB needed): ```sh php -l path/to/File.php ``` ## ๐Ÿ”ฌ Static Analysis (PHPStan) The project is analysed at **level 5** with the config in `build/phpstan.dist.neon`. PHPStan is a `require-dev` Composer package installed by `make dev-tools` (into `src/vendor/bin/phpstan`); a bootstrap in `tools/phpstan/` defines the ~131 runtime `define()` constants static scanning can't see. ```sh make phpstan # must report [OK] No errors ``` How the gate works: - A committed baseline (`build/phpstan-baseline.neon`) freezes pre-existing findings, so CI fails only on **new** issues your change introduces โ€” fix those. - The baseline is **not** a list of accepted bugs (most entries are false positives from dynamic DB-row shapes or templates). Do **not** grow it to hide a real problem in new code. - If you clear a batch of existing findings, regenerate the smaller baseline: `make phpstan-baseline`. - After runtime constants change, regenerate the stub with `make phpstan-stub`; after editing PHPDoc types, clear the cache first: `php src/vendor/bin/phpstan clear-result-cache`. ## โœจ Code Style The PHP standard (`build/phpcs.xml.dist`) is PSR-12 with project overrides โ€” **run `make cs-fix` to auto-format to it before committing** (`make cs` only reports). Key points: - **K&R** brace style (opening brace on the same line), not PSR-12's Allman. - **Tabs** for indentation (one tab per level), not spaces. - Give every function parameter a **type hint** (`make cs` flags untyped ones; this one is not auto-fixable โ€” add the type yourself). - The ruleset **excludes view templates** (`Public/Views/`, `Modules/*/views/`), so short-tag templates (` On an installed server, use the bundled interpreter instead of system PHP: > `/home/xc_vm/bin/php/bin/php tests/phpunit.phar ...` (see > `docs/en/guides/phpunit-phar.md`). On a dev machine, plain `php` is fine. Guidelines: - Add PHP tests under `tests/Unit/`, named after the class under test (e.g. `GitHubReleasesTest.php`). - Prefer focused tests for the file you changed over broad project-wide mocks. - Cover valid inputs, invalid inputs, edge cases, and side effects. - If code writes to stdout, capture it in the test so PHPUnit output stays clean. **End-to-end tests** (Playwright, in `tests/e2e/`) exercise the running panel UI: ```sh make e2e-install # one-time: npm ci + playwright install chromium make e2e # run the suite make e2e-ui # interactive UI mode ``` ## ๐Ÿงฐ Developer Tooling (`tools/`) Nothing in `tools/` ships to production. Highlights useful while developing โ€” see `tools/README.md` for the full list: | Tool | Purpose | | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | | `sync-dev.sh` | Incremental code deploy to a live box (see the dev loop above). | | `test_player_api.sh ` | HTTP smoke-test of every Player API endpoint (status / content-type / JSON shape). | | `stream-check/` | Dependency-free MPEG-TS + HLS stream integrity checker (`stream_queue_check.py`) with an SVG grapher (`stream_graph.py`). | | `test-stream-generator/` | Generates a synthetic moving test pattern (stopwatch + wall-clock) as an HTTP "live" source; no input file. | | `test-install/` | Docker end-to-end install test of the built release archive. | ## ๐Ÿ“ฆ Building a Release (maintainers) ```sh make main # full panel archive: dist/xc_vm.tar.gz + XC_VM.zip installer make lb # load-balancer archive (privileged code stripped; MAIN-only modules excluded) make new # wipe dist/ ``` Builds copy only git-tracked files and run `verify_no_lfs_pointers`. ## ๐Ÿ“š Documentation Docs are a **MkDocs Material** site under `docs/`. - **Edit only `docs/en/`** โ€” English is the single source of truth. - **Never hand-edit `docs/ru/`** (or any other language tree): it is generated from `docs/en` by `tools/docs/translate.py` and overwritten on the next run. - After editing English docs, verify with `make docs-build` (strict โ€” fails on broken links/anchors). Preview locally with `make docs-serve`. - `docs/ru` is regenerated locally before a release (`make docs-translate`), not in CI. ## ๐Ÿ”ฅ Submitting a Pull Request 1. Fork and branch (see naming conventions below): ```sh git checkout -b feature/your-feature ``` 2. Make your changes; run the pre-commit checks; commit with a Conventional Commits message: ```sh git commit -m "feat: short description of the change" ``` 3. Push and open a pull request on GitHub: ```sh git push origin feature/your-feature ``` Keep the PR focused on a single change and describe what and why. ### Branch Naming Conventions | Type | Template | Example | | ------------- | ------------------------------ | ----------------------------- | | Features | `feature/` | `feature/user-authentication` | | Bug Fixes | `fix/` | `fix/login-bug` | | Hotfixes | `hotfix/` | `hotfix/critical-error` | | Refactoring | `refactor/` | `refactor/code-cleanup` | | Testing | `test/` | `test/api-endpoints` | | Documentation | `docs/` | `docs/documentation-api` | ## ๐Ÿ‘€ Code Reviews - All PRs must be reviewed by at least 2 maintainers. - Address review comments before merging. ## ๐Ÿš€ Reporting Issues - Use **GitHub Issues** to report bugs and suggest features. - Provide clear steps to reproduce, plus relevant logs or error messages. ## ๐ŸŒŸ Recognition Your GitHub profile will be added to [CONTRIBUTORS.md](CONTRIBUTORS.md). Thank you for contributing! ๐ŸŽ‰