Files
XC_VM/docs/en/development/architecture.md
T
Divarion_D c982bb2f1e docs: audit dev docs for source drift, split oversized pages, add core-wiring
Verify every dev-doc claim against src/ and fix factual drift: wrong method
signatures/return types, wrong enum casing (BootContext cases are PascalCase),
stale paths (M3u parsers are Composer deps under vendor/, MobileDetect is
mobiledetect/mobiledetectlib v4.9.0 \Detection\MobileDetect, NotFoundException
lives in XcVm\Core\Container\Psr), a fictional `stream:check` command/class,
reversed migration-failure semantics ([FAIL] = not recorded, retried),
inverted isStreamRunning/isStreamAlive descriptions, findProcessPIDs ANY-not-ALL,
acquireCronLock has no shutdown callback, and nonexistent make targets.

Split oversized pages and fix nav + cross-links:
- modules.md -> module-authoring / module-lifecycle / module-extension-points
- cli-tools.md -> cli-tools + database-migrations
- streaming-subsystem.md -> + streaming-diagnostics
- geoip-and-device-detection.md -> geoip-isp-and-geo-routing + device-detection-and-stb-locking

Add development/core-wiring.md: how the core assembles itself at boot
(container population, ServiceContainer reference, bootAll orchestration,
CLI command auto-discovery, end-to-end Admin/CLI boot walkthroughs).

Only docs/en + mkdocs.yml touched; docs/ru is regenerated before release.
2026-08-26 22:42:43 +03:00

4.3 KiB

Architecture Overview

Project type

Structured PHP monolith with a modular extension layer.

  • No DDD, no Hexagonal, no Clean Architecture — intentional.
  • Split by context with minimal abstractions: Controller → Service → Repository.
  • Two build artifacts from one codebase: MAIN (full panel) and LB (load balancer subset).

Source tree

Path Role
src/Core/ Framework primitives: DI container, events, HTTP/router, config, auth, logging
src/Domain/ Business contexts: Stream, VOD, Line, User, Server, Security, etc.
src/Infrastructure/ External adapters: DatabaseFactory, cache readers, Redis, TMDb
src/Streaming/ Streaming subsystem: bootstrap, auth, delivery, balancer, protection
src/Modules/ Optional extension layer — loaded by ModuleLoader
src/Public/ Front controller, router, controllers, views, assets
src/Cli/ Console commands and cron entry points
src/Ministra/ Stalker Portal — in core; served at /home/xc_vm/Ministra

Runtime model

Dependencies flow inward — modules may use core and domain, never the reverse.

Public/index.php
    └── XC_Bootstrap::boot(BootContext::Admin)
            └── ServiceContainer (DI)
                    ├── EventDispatcher (PSR-14)
                    ├── ModuleLoader → loadAll() → bootAll()
                    └── Router → dispatch()

Domain and module classes do not take $db in their constructor. They use \XcVm\Infrastructure\Database\DatabaseAware and call self::db(), which lazily resolves the shared connection. bootstrap.php::wireDomainDatabase() sets that connection once per boot (via DatabaseAware::setDb()) — there is no per-class wiring and no global $db in the web request path.


Module system

Modules are isolated directories under src/Modules/ with a module.json manifest and a class extending BaseModule. See Module Authoring for the full reference (and the linked Lifecycle / Extension Points pages).

src/Modules/my-module/
├── module.json          # metadata
├── MyModuleModule.php   # extends BaseModule, namespace XcVm\Module\MyModule
└── ...

Bootstrap contexts

Four contexts control which subsystems initialize. See Bootstrap Contexts.

Context Used for
BootContext::Minimal Scripts needing only paths/config
BootContext::Cli Cron jobs and CLI commands
BootContext::Stream Streaming endpoints
BootContext::Admin Admin/reseller panel

Build variants (MAIN vs LB)

MAIN LB
Admin panel ✅ ❌
Streaming ✅ ✅
Module system ✅ subset

Controlled by the ServerEnvironment enum and each module.json's environment field (main / lb / any). At boot, ModuleLoader::getCurrentEnvironment() resolves the node's environment from the SERVER_TYPE constant ('lb' → ServerEnvironment::LoadBalancer, else ServerEnvironment::Main); a module whose environment doesn't match the node is skipped, so the LB gets a subset of modules.


Key extension points

Mechanism How to use
PSR-14 events EventDispatcher::listen() / #[ListensTo] — see Event System
Service decoration $container->decorate('id', callable, priority) — see Module Extension Points
Stream middleware Implement StreamMiddlewareProviderInterface — see Module Extension Points
Cron entries getCronEntries() in the module class — see Module Extension Points
DB migrations MigratableInterface::getMigrations() — see Module Extension Points

Contributor rules

  1. Modules must not modify core files.
  2. No eval, monkey patching, or runtime file replacement.
  3. Any module can be disabled via config/modules.php without touching core.
  4. Protected services (db, settings, config, auth) cannot be decorated.
  5. Keep EN and RU docs in sync in the same commit.