Contributing to Phlix
Everything you need to contribute across all Phlix repositories — server, hub, clients, and plugins.
TL;DR
# Clone all repos
git clone git@github.com:detain/phlix-server.git
git clone git@github.com:detain/phlix-hub.git
git clone git@github.com:detain/phlix-shared.git
git clone git@github.com:detain/phlix-mobile-client.git
git clone git@github.com:detain/phlix-tizen-client.git
git clone git@github.com:detain/phlix-roku-client.git
git clone git@github.com:detain/phlix-windows-client.git
# Server dev setup
cd phlix-server && composer install && php scripts/run-migrations.php && php public/index.php
# Hub dev setup
cd phlix-hub && composer install && php bin/hub.php
# Mobile/Windows clients
cd phlix-mobile-client && npm install
cd phlix-windows-client && npm installBranch → commit → PR → squash-merge → delete. PSR-12, phpstan level 9, all PHPUnit tests must pass.
Cloning all repositories
Phlix is split across seven repositories:
| Repository | Language / stack | What it runs |
|---|---|---|
phlix-server | PHP 8.3+, Workerman 5 | Media server (HTTP, WS, HLS, DLNA, LiveTV) |
phlix-hub | PHP 8.3+, Workerman 5 | Hub orchestration (pairing, relay tunnel) |
phlix-shared | PHP 8.3+ | Shared types, DTOs, event classes |
phlix-mobile-client | React Native | iOS + Android mobile app |
phlix-tizen-client | JavaScript / Tizen | Samsung Tizen TV app |
phlix-roku-client | BrightScript | Roku channel |
phlix-windows-client | Electron | Windows desktop app |
git clone git@github.com:detain/phlix-server.git
git clone git@github.com:detain/phlix-hub.git
git clone git@github.com:detain/phlix-shared.git
git clone git@github.com:detain/phlix-mobile-client.git
git clone git@github.com:detain/phlix-tizen-client.git
git clone git@github.com:detain/phlix-roku-client.git
git clone git@github.com:detain/phlix-windows-client.gitDevelopment environment setup
phlix-server
cd phlix-server
composer install
php scripts/run-migrations.php # creates all DB tables
php public/index.php # starts the server on 0.0.0.0:8080The server uses Workerman\MySQL\Connection (never PDO or mysqli). All DB access goes through the connection pool. See docs/dev/architecture-server.md for the bootstrap path.
phlix-hub
cd phlix-hub
composer install
php bin/hub.php # starts the hub on 0.0.0.0:8800The hub holds server claim codes, runs heartbeat loops, multiplexes relay tunnels, and issues RS256 user-session JWTs. See docs/dev/architecture-hub.md for internals.
Mobile client (phlix-mobile-client)
cd phlix-mobile-client
npm install # or: yarn
npx react-native start # Metro bundler
npx react-native run-android # Android emulator
npx react-native run-ios # iOS simulatorWindows client (phlix-windows-client)
cd phlix-windows-client
npm install # or: yarn
npm run dev # starts Electron with hot reloadTizen client (phlix-tizen-client)
Tizen builds require the Tizen Studio toolchain. Build commands are defined in the .tizen project file; refer to the repo's README.md for the full build instructions.
Roku client (phlix-roku-client)
Roku builds require the Roku SDK. Refer to the repo's README.md for the full build instructions.
Branch naming
Use a consistent prefix so the purpose of each branch is obvious at a glance:
| Prefix | Use for |
|---|---|
feature/{slug} | New features |
fix/{slug} | Bug fixes |
step-{phase}.{step}-{slug} | Phase/step deliverables (e.g., step-n.23-contributing, step-c.2-hubclient) |
Never commit directly to master. All work happens in feature branches.
Commit format
{type}: {description}Types for conventional contributions:
| Type | When to use |
|---|---|
feat: | New feature |
fix: | Bug fix |
chore: | Tooling, dependencies, config |
docs: | Documentation only |
refactor: | Code restructure without behaviour change |
step-N.M: | Phase/step deliverable (e.g., step-N.23:) |
Examples:
step-N.23: add contributing guide (repo structure, dev setup, branch conventions)
fix: resolve race condition in HubClient heartbeat loop
feat: add FanartProvider for TV series artwork
docs: document DLNA ContentDirectoryBrowse response formatPull request process
- Branch from
master. - Write your change + tests + docs.
- Run locally before pushing:bash
./vendor/bin/phpcs --standard=PSR12 src/ ./vendor/bin/phpstan analyze src/ --level=9 ./vendor/bin/phpunit - Push and open a PR. Title format:
step-N.M: {description}for phase work. - Review — CI must be green, at least one approval required.
- Merge — squash-merge preferred; branch is deleted after merge.
- Sync — pull
masterlocally and delete the topic branch.
PHPDoc requirements
Every public and protected method must have:
/**
* @param string $mediaId The unique media item identifier.
* @param int $position Ticks position in the playback stream.
* @return array{media_id: string, user_id: string}
* @throws InvalidArgumentException If the media ID is not found.
*/
public function getPosition(string $mediaId, int $position): arrayMinimum required tags: @param, @return, @throws. Add @see for related methods and @internal when a method is not part of the public API.
Code standards
PSR-12
./vendor/bin/phpcs --standard=PSR12 src/All PHP files must pass PSR-12. No exceptions in submitted PRs.
Static analysis (phpstan level 9)
./vendor/bin/phpstan analyze src/ --level=9Level 9 is the maximum. If phpstan reports errors, fix them — do not lower the level to silence warnings.
Syntax check
find src -name '*.php' -exec php -l {} \;All files must parse cleanly. No output means no errors.
PHPUnit tests
./vendor/bin/phpunit # all suites
./vendor/bin/phpunit --testsuite Unit # unit tests only
./vendor/bin/phpunit --testsuite IntegrationAll tests must pass. Unit tests mock Workerman\MySQL\Connection:
$db = $this->createMock(Workerman\MySQL\Connection::class);
$db->method('query')
->willReturn([['col' => 'val']]); // SELECT result
$db->expects($this->once())
->method('query')
->with($this->stringContains('INSERT'), $this->anything()); // write assertionTest files live in tests/unit/{Module}/{Class}Test.php with namespace Phlix\Tests\Unit\{Module} and extend PHPUnit\Framework\TestCase.
Code coverage
./vendor/bin/phpunit --coverage-textCoverage writes to coverage.xml and coverage-report/ (configured in phpunit.xml). Target ≥ 80% on src/Common/Container/**.
Plugin contribution
Plugins extend the Phlix feature set without modifying the core server. The plugin SDK lives in docs/dev/plugin-sdk.md — it covers the manifest schema, lifecycle (install → enable → disable → uninstall), container bindings plugins can use, and how to add a new plugin type.
To list a plugin in the in-product catalog, submit a PR to detain/phlix-plugin-catalog with the plugin's manifest and metadata.
See docs/plugins/developer-guide.md for the full author-facing guide.
What can go wrong
PHP version mismatch
Symptom: composer install succeeds but the server crashes with Error: Class 'Workerman\MySQL\Connection' not found.
Cause: The project requires PHP 8.3+. Older PHP versions lack required features (e.g., attributes, readonly properties, first-class enum constants).
Fix:
php -v # confirm PHP 8.3+
composer install # re-run after upgrading PHP
php public/index.php # verify the server startsUse phpbrew, nvm (with phpenv), or Docker to manage multiple PHP versions.
Migration failure on first run
Symptom: php scripts/run-migrations.php exits non-zero. DB tables are missing or partially created.
Cause: Migration script run against a pre-existing database with stale schema, or the MySQL server is not reachable.
Fix:
# Verify MySQL is reachable
mysql -h 127.0.0.1 -u phlix -p -e "SELECT 1"
# Drop and recreate (development only — NEVER do this in production):
mysql -h 127.0.0.1 -u phlix -p -e "DROP DATABASE IF EXISTS phlix"
mysql -h 127.0.0.1 -u phlix -p -e "CREATE DATABASE phlix"
php scripts/run-migrations.php
# Or run the SQL files directly for incremental fixes:
mysql -h 127.0.0.1 -u phlix -p phlix < migrations/001_initial_schema.sqlCheck migrations/ for the current set of SQL files.
Missing environment variables
Symptom: Server starts but returns 500 on all requests. Log shows RuntimeException: JWT_SECRET environment variable is not set.
Cause: Required env vars are not set. The server reads config from config/server.php which may reference getenv().
Fix:
# Copy and edit the env example
cp .env.example .env
# Fill in all required values (JWT_SECRET, DB_* credentials, etc.)
php public/index.phpThe required variables are documented in docs/reference/env-vars.md.
phpstan level 9 failures
Symptom: phpstan analyze reports errors on new code.
Cause: Level 9 is the strictest level. Common issues: missing return types, incorrect nullable types, accessing properties that may not exist on a mixed value.
Fix: Add explicit type declarations. Do not use @var annotations to silence phpstan — fix the underlying code.
# Audit your specific file only while developing
./vendor/bin/phpstan analyze src/Server/Http/Router.php --level=9Next steps
docs/dev/plugin-sdk.md— Plugin SDK internals (manifest schema, lifecycle, container bindings, events). Start here for plugin development.docs/dev/workflow.md— Day-to-day developer workflow (debugging, hot reload, logging).docs/dev/architecture-hub.md— Hub internals (pairing protocol, relay tunnel, namespace map).docs/dev/architecture-server.md— Server bootstrap, container, request lifecycle.