mirror of
https://github.com/Vateron-Media/XC_VM.git
synced 2026-10-13 12:02:54 +02:00
chore(github): add composer to dependabot, fix stale AI instructions
dependabot.yml: the comment claimed "no Composer/npm manifests committed", but src/composer.json + composer.lock ARE committed. Added a grouped composer ecosystem (directory /src) so the 4 prod deps and the dev tools get advisory monitoring; noted the production-only vendor recommit step. instructions/php-conventions + architecture-rules: rewritten to the current Composer PSR-4 architecture. They previously described the pre-migration state and misdirected Copilot: - "No autoloading via Composer — custom src/autoload.php" (file removed) and "Do NOT introduce Composer dependencies" → Composer PSR-4, vendor committed production-only, dump-autoload workflow - lowercase paths (src/cli, src/core, src/modules, …) → real PascalCase (src/Cli, src/Core, src/Modules, src/Streaming, …) - setDb() / $r-prefix (both gone from the codebase) → DatabaseAware + self::db(); dropped the dead $r naming rule - inverted namespace guidance → new code is namespaced; legacy coexists, don't mass-migrate - dangling ARCHITECTURE.md ref → docs/en/development/architecture.md (which exists), src/config/modules.php path fixed
This commit is contained in:
@@ -1,55 +1,64 @@
|
||||
---
|
||||
description: "Use when creating or modifying services, repositories, controllers, modules, or any domain/core code. Enforces XC_VM architectural rules from ARCHITECTURE.md."
|
||||
description: "Use when creating or modifying services, repositories, controllers, modules, or any domain/core code. Enforces XC_VM architectural rules — see docs/en/development/architecture.md."
|
||||
---
|
||||
# Architecture Rules — XC_VM
|
||||
|
||||
## Layer Pattern
|
||||
Every domain context follows: **Controller → Service → Repository → Database**
|
||||
Structured PHP monolith with a modular extension layer — intentionally **no DDD /
|
||||
Hexagonal / Clean Architecture**. Split by context with minimal abstractions.
|
||||
Authoritative reference: `docs/en/development/architecture.md`.
|
||||
|
||||
## Source tree (PSR-4, `XcVm\` → `src/`)
|
||||
|
||||
| Path | Role |
|
||||
|------|------|
|
||||
| `src/Core/` | Infrastructure primitives: DI container, events, HTTP router, config, auth, logging |
|
||||
| `src/Domain/` | Business contexts: Stream, VOD, Line, User, Server, Security, … (`Controller → Service → Repository`) |
|
||||
| `src/Infrastructure/` | Cross-cutting adapters (Database, TMDb client, …) |
|
||||
| `src/Streaming/` | Streaming runtime — used by both MAIN and LB builds |
|
||||
| `src/Public/` | Front controller, router, controllers, views, assets |
|
||||
| `src/Cli/` | Console commands and cron entry points |
|
||||
| `src/Modules/` | Optional extension layer (`{name}_{hash5}/`), loaded by `ModuleLoader` |
|
||||
| `src/ministra/` | Stalker Portal — isolated subsystem (`BoundaryInterface`) |
|
||||
|
||||
## Layer pattern
|
||||
Every domain context follows **Controller → Service → Repository → Database**:
|
||||
|
||||
```
|
||||
public/Controllers/Admin/StreamController.php → presentation
|
||||
domain/Stream/StreamService.php → business logic
|
||||
domain/Stream/StreamRepository.php → data access
|
||||
core/Database/Database.php → infrastructure
|
||||
Public/Controllers/Admin/StreamController.php → presentation
|
||||
Domain/Stream/StreamService.php → business logic
|
||||
Domain/Stream/StreamRepository.php → data access
|
||||
Infrastructure/Database/… + Core/Database/… → infrastructure
|
||||
```
|
||||
|
||||
## Dependency Direction (strict)
|
||||
## Dependency direction (inward only)
|
||||
|
||||
| Layer | Can depend on | CANNOT depend on |
|
||||
|-------|---------------|------------------|
|
||||
| `public/` | `domain/` (Service+Repository), `core/` | `streaming/`, `modules/` directly |
|
||||
| `domain/` | `core/` (Database, Cache, Events) | `public/`, `streaming/`, `modules/`, `infrastructure/` |
|
||||
| `core/` | Only other `core/` subdirectories | Everything else |
|
||||
| `streaming/` | `core/` (subset), `domain/` (read-only) | `public/`, `modules/` |
|
||||
| `modules/` | `domain/`, `core/` | Other modules, `public/`, `streaming/` |
|
||||
| Layer | May depend on | MUST NOT depend on |
|
||||
|-------|---------------|--------------------|
|
||||
| `Public/` | `Domain/` (Service + Repository), `Core/` | `Streaming/`, `Modules/` directly |
|
||||
| `Domain/` | `Core/`, `Infrastructure/` | `Public/`, `Modules/` |
|
||||
| `Streaming/` | `Core/` (subset), `Domain/` (read-only) | `Public/`, `Modules/` |
|
||||
| `Core/` | Only other `Core/` subdirectories | Everything else |
|
||||
| `Modules/` | `Domain/`, `Core/` | Other modules, `Public/`, `Streaming/` |
|
||||
|
||||
## Constructor Injection
|
||||
- `ServiceContainer` is used ONLY in bootstrap (composition root)
|
||||
- After bootstrap, all dependencies are passed via constructor
|
||||
- No service may call `$container->get()` inside its methods
|
||||
- Legacy exceptions marked with `// @legacy-container`
|
||||
## Dependency injection
|
||||
- `ServiceContainer` (PSR-11) is used ONLY at the composition root (bootstrap paths / module `boot()`).
|
||||
- After bootstrap, collaborators are passed by constructor; the shared DB connection comes via the `DatabaseAware` trait + `self::db()`.
|
||||
- No service calls `$container->get()` inside its own methods (no Service Locator).
|
||||
|
||||
## File Consolidation Rules
|
||||
- Do NOT create separate file if class has < 150 lines AND < 5 public methods
|
||||
- Small Repository + Service in same context → combine in one file
|
||||
- Service with 1-2 methods → merge into nearest related context
|
||||
- Separate files only when class > 150 lines OR ≥ 5 public methods OR used from 3+ contexts
|
||||
## Module boundaries
|
||||
- A module is an isolated directory `src/Modules/{name}_{hash5}/` (`{Pascal}Module extends BaseModule`, namespace `XcVm\Module\{Pascal}`).
|
||||
- **Modules own their DB schema** via file migrations (`migrations/<semver>.sql` + `database.sql` master + `database_drop.sql` teardown, run by `ModuleMigrator`). Do NOT add module tables to core `src/bin/install/database.sql`.
|
||||
- **Core must never touch module-owned tables directly** (a module can be uninstalled, dropping them). Instead core dispatches an event (e.g. `StreamsDeletedEvent`) and the owning module subscribes via `#[ListensTo(Event::class)]` to clean up.
|
||||
- Removing/disabling a module (via `src/config/modules.php`) must NOT break the system — graceful degradation.
|
||||
|
||||
## Module Boundaries
|
||||
- Module = isolated directory under `src/modules/`
|
||||
- Removing a module must NOT break the system (graceful degradation)
|
||||
- Modules depend on `domain/` and `core/`, never on other modules
|
||||
- Core never depends on modules
|
||||
## Multi-build awareness
|
||||
- **MAIN build:** full panel (admin + streaming + MySQL/MariaDB).
|
||||
- **LoadBalancer build:** streaming subset only — admin/reseller/player and privileged CLI are stripped (`make lb`). Modules are MAIN-only. Code in `Domain/` / `Streaming/` reached by the LB must not pull admin-only dependencies.
|
||||
|
||||
## Decision Filters (from ARCHITECTURE.md)
|
||||
Before any architectural decision, apply:
|
||||
1. Can a contributor understand it in 5 minutes? → if no, simplify
|
||||
2. Does it break the streaming hot path? → if yes, reject
|
||||
3. Can it be isolated as a module? → if no, justify why
|
||||
## Decision filters
|
||||
Before an architectural decision, apply:
|
||||
1. Can a contributor understand it in 5 minutes? If no → simplify.
|
||||
2. Does it break the streaming hot path? If yes → reject.
|
||||
3. Can it be isolated as a module? If no → justify why.
|
||||
|
||||
If a decision improves "code beauty" but raises the entry barrier → reject it.
|
||||
|
||||
## Multi-Build Awareness
|
||||
- **MAIN build**: full admin + streaming
|
||||
- **LoadBalancer build**: streaming subset only, admin dirs stripped
|
||||
- Code in `domain/` used by streaming must NOT pull admin-only dependencies
|
||||
If a change improves "code beauty" but raises the entry barrier → reject it.
|
||||
|
||||
@@ -3,67 +3,51 @@ applyTo: "**/*.php"
|
||||
---
|
||||
# PHP Conventions — XC_VM
|
||||
|
||||
XC_VM is a PHP 8.1+ modular monolith **migrated to Composer PSR-4** (`XcVm\` → `src/`).
|
||||
The application root is `src/` (composer.json, vendor/, bootstrap.php all live there).
|
||||
`short_open_tag=1` is on — view templates use `<?` / `<?=`.
|
||||
|
||||
## Formatting
|
||||
- **Brace style:** K&R (opening brace on same line)
|
||||
- **Indentation:** Tabs (1 tab per level), NOT spaces
|
||||
- **Brace style:** K&R (opening brace on the same line)
|
||||
- **Indentation:** tabs (1 tab per level), NOT spaces
|
||||
- **No trailing whitespace**
|
||||
|
||||
## Comment Language
|
||||
- **New code:** write all comments and DocBlocks in **English** (keep PHPDoc tags
|
||||
`@param`, `@return`, `@package`, etc. in English as they already are).
|
||||
- **Legacy files:** the existing codebase has Russian-language DocBlocks in ~23%
|
||||
of files (notably `src/cli/`, `src/core/Auth/`, `src/public/Controllers/`).
|
||||
Do NOT mass-translate. Translate Russian comments to English only when you are
|
||||
already editing that file for another reason, or when explicitly asked.
|
||||
- **Do not mix languages** within a single new comment block.
|
||||
## Autoloading & dependencies
|
||||
- **Composer PSR-4:** `XcVm\` maps to `src/` (e.g. `XcVm\Core\Database\DatabaseHandler` = `src/Core/Database/DatabaseHandler.php`). Modules load via their own namespace autoloader, not the Composer PSR-4 map.
|
||||
- **`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 deps, re-commit a `composer install --no-dev` vendor and `composer.lock`.
|
||||
- **Don't add dependencies casually** — a new Composer package means a lockfile update and a production-only vendor recommit. Prefer the standard library or existing vendored libs.
|
||||
|
||||
## Typing and Declarations
|
||||
- **`declare(strict_types=1)`:** legacy code (controllers, `cli/`, most of `core/`) omits it — do NOT add it there. New code already uses it (e.g. `src/core/Auth/*`, `src/core/Enum/*`, `src/core/Events/ListensTo.php`) — follow the pattern of neighbouring files.
|
||||
- **Namespaces:** legacy first-party code has none — do NOT add namespaces to it. The module system *is* namespaced (`src/modules/*/`…`Module.php`), as are bundled parsers (`core/Parsing/M3uParser`, `core/Parsing/PhpM3u8`) — match the surrounding file when working there.
|
||||
- Do NOT add PHP docblocks or type annotations to existing code unless explicitly asked
|
||||
- Parameter type hints: use when writing new service/repository methods, omit when editing legacy code
|
||||
## Namespaces & strict types (new code)
|
||||
- **New PHP files** declare a namespace under `XcVm\…` matching their path, and start with `declare(strict_types=1)`.
|
||||
- **Legacy first-party files** that are not yet namespaced (roughly half the tree) still exist. Do NOT mass-migrate them: only add a namespace / `strict_types` when you are already rewriting that file for another reason. Match the surrounding file when editing.
|
||||
- Modules are namespaced `XcVm\Module\{Pascal}` with the class `{Pascal}Module` in `src/Modules/{name}_{hash5}/`.
|
||||
|
||||
## Database access
|
||||
- **New code** uses the `DatabaseAware` trait: `use \XcVm\Infrastructure\Database\DatabaseAware;` then call `self::db()` (it resolves the connection from the `DatabaseFactory` singleton). Do NOT reintroduce per-class `setDb()` wiring.
|
||||
- `Core/Database/DatabaseHandler` is the PDO wrapper. Query with `?` placeholders, never named parameters: `self::db()->query('SELECT * FROM streams WHERE id = ?;', $id)`. Terminate the SQL string with a semicolon.
|
||||
- Legacy superglobals (`$db`, `$rSettings`, `$rUserInfo`, `$rServers`) are still bridged by `LegacyInitializer` for legacy code — preserve them when editing legacy files, but never introduce new global state in new code.
|
||||
|
||||
## Naming
|
||||
- **Classes:** PascalCase (`StreamService`, `Database`, `FileLogger`)
|
||||
- **Methods:** camelCase (`getById`, `processStream`, `closeConnection`)
|
||||
- **Variables:** `$r` prefix for data arrays and results: `$rData`, `$rArray`, `$rReturn`, `$rRow`, `$rStreamID`
|
||||
- **Constants:** UPPER_SNAKE_CASE (`STATUS_SUCCESS`, `GIT_OWNER`); for typed sets prefer enums (`BootContext`, `ModuleState`) over new string constants
|
||||
- **Database columns in queries:** snake_case as stored in DB
|
||||
- **Classes:** PascalCase (`StreamService`, `DatabaseHandler`)
|
||||
- **Methods:** camelCase (`getById`, `processStream`)
|
||||
- **Constants:** UPPER_SNAKE_CASE; for typed sets prefer enums (`BootContext`, `ModuleState`) over new string constants
|
||||
- **DB columns in queries:** snake_case as stored
|
||||
|
||||
## Class Patterns
|
||||
- Services use `public static` methods in current codebase (legacy pattern)
|
||||
- New domain code follows Controller → Service → Repository pattern per `docs/en/development/architecture.md`
|
||||
- Constructor injection for new services; legacy code still uses `global $db`, `global $rSettings`
|
||||
## Class patterns
|
||||
- New domain code follows **Controller → Service → Repository** (see `docs/en/development/architecture.md`).
|
||||
- Prefer constructor injection for collaborators; use the `DatabaseAware` trait for the shared connection.
|
||||
|
||||
## Global Variables (legacy — do NOT introduce new ones)
|
||||
- `$db` — Database instance
|
||||
- `$rSettings` — System settings array
|
||||
- `$rUserInfo` — Current user info
|
||||
- `$rServers` — Servers configuration
|
||||
- `$_TITLE` — Page metadata
|
||||
## Comments
|
||||
- **New code:** English comments and DocBlocks (keep `@param`, `@return`, `@package` tags in English).
|
||||
- **Legacy files** carry Russian-language DocBlocks in some files. Do NOT mass-translate; translate only a file you are already editing for another reason, or when asked. Don't mix languages within one comment block.
|
||||
|
||||
When editing legacy files that use globals, preserve the pattern. Do NOT refactor globals unless explicitly asked.
|
||||
## Error handling
|
||||
- Prefer typed exceptions from the `XcVmException` hierarchy for new code.
|
||||
- For fatal API responses the codebase uses `exit(json_encode(...))` — match the surrounding handler.
|
||||
- Do NOT wrap existing code in try-catch "just in case".
|
||||
|
||||
## SQL
|
||||
- Use PDO prepared statements with `?` placeholders: `$db->query('SELECT * FROM streams WHERE id = ?;', $rID)`
|
||||
- Do NOT use named parameters (`:name` style)
|
||||
- Terminate SQL strings with semicolon inside the query string
|
||||
|
||||
## Error Handling
|
||||
- Use try-catch + `exit(json_encode(...))` for fatal API errors
|
||||
- Use status constants (`STATUS_SUCCESS`, etc.) for validation flows
|
||||
- Do NOT add exception handling to code that doesn't have it unless asked
|
||||
|
||||
## File Structure
|
||||
- No autoloading via Composer — project uses custom `src/autoload.php`
|
||||
- Admin pages: `src/public/Views/admin/*.php` — mixed PHP/HTML templates (legacy-compatible)
|
||||
- Domain services: `src/domain/{Context}/{ContextService}.php`
|
||||
- Core utilities: `src/core/{Subsystem}/*.php`
|
||||
|
||||
## What NOT to Do
|
||||
- Do NOT add `use` / `namespace` to legacy first-party code (controllers, `cli/`, legacy `core/`) — but keep namespaces when editing the module system (`src/modules/*`), which is already namespaced
|
||||
- Do NOT introduce Composer dependencies
|
||||
- Do NOT restructure legacy files into PSR-4 layout (modules are already namespaced / PSR-4-like)
|
||||
- Do NOT convert existing `global` usage to DI without explicit request
|
||||
- Do NOT add PHPDoc to unchanged code
|
||||
- Do NOT wrap existing code in try-catch "just in case"
|
||||
## What NOT to do
|
||||
- Do NOT run `composer install` on a deploy path, and do NOT add Composer dependencies casually.
|
||||
- Do NOT reintroduce `setDb()` static injection or new `global` usage in new code.
|
||||
- Do NOT mass-migrate legacy files to namespaces / `strict_types` / DI without an explicit request — keep changes surgical.
|
||||
- Do NOT add PHPDoc or type annotations to unchanged code.
|
||||
|
||||
Reference in New Issue
Block a user