From 2abd19b0d5fb6b2e45da620deecb683a4c46ef07 Mon Sep 17 00:00:00 2001 From: Divarion_D Date: Fri, 7 Aug 2026 20:11:26 +0300 Subject: [PATCH] chore(github): add composer to dependabot, fix stale AI instructions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- .github/dependabot.yml | 23 ++++- .../architecture-rules.instructions.md | 91 +++++++++--------- .../php-conventions.instructions.md | 92 ++++++++----------- 3 files changed, 109 insertions(+), 97 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 400e8eb1..44c885cb 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,7 +1,6 @@ version: 2 updates: - # The project has no Composer/npm manifests committed, so only GitHub Actions - # versions are tracked here. Add more ecosystems if package manifests are added. + # GitHub Actions pinned in .github/workflows/*. - package-ecosystem: "github-actions" directory: "/" schedule: @@ -11,3 +10,23 @@ updates: labels: - "dependencies" - "github-actions" + + # Composer dependencies. The manifest and lockfile are committed at src/ + # (composer.json + composer.lock). NOTE: vendor/ is committed and + # PRODUCTION-ONLY — after merging a bump you must re-commit a production + # vendor with `composer install --no-dev` (and `composer dump-autoload`); + # never run `composer install` on a deploy path. See CLAUDE.md. + # Grouped so each run opens a single PR instead of one per package. + - package-ecosystem: "composer" + directory: "/src" + schedule: + interval: "weekly" + commit-message: + prefix: "deps" + labels: + - "dependencies" + - "composer" + groups: + composer: + patterns: + - "*" diff --git a/.github/instructions/architecture-rules.instructions.md b/.github/instructions/architecture-rules.instructions.md index ae244f8c..09190fd2 100644 --- a/.github/instructions/architecture-rules.instructions.md +++ b/.github/instructions/architecture-rules.instructions.md @@ -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/.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. diff --git a/.github/instructions/php-conventions.instructions.md b/.github/instructions/php-conventions.instructions.md index df252087..544c3d78 100644 --- a/.github/instructions/php-conventions.instructions.md +++ b/.github/instructions/php-conventions.instructions.md @@ -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 `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.