- Added new fields to module.json: environment, dependencies, has_navbar, and has_settings. - Updated ModuleLoader to support environment filtering and topological sorting of modules based on dependencies. - Implemented error handling for missing and cyclic dependencies during module loading. - Enhanced documentation for module.json structure and ModuleLoader functionality. - Introduced unit tests for ModuleLoader to validate loading behavior and dependency resolution. - Updated existing modules' manifest files to include new fields. Co-authored-by: Copilot <copilot@github.com>
15 KiB
MODULES.md
XC_VM Modules Specification
Актуальный план рефакторинга и развития модульной системы XC_VM.
Язык документа: русский. Этот файл описывает текущее состояние модульной системы и только актуальный roadmap. Никакие секреты, токены и API-ключи не должны попадать в клиентскую часть модулей. Обновлено: 2026-04-17
Содержание
- Текущее состояние
- Что уже реализовано
- Что ещё не доведено до цели
- Целевая модель модулей
- Пошаговый план рефакторинга
- Правила разработки модулей
- Definition of Done
1. Текущее состояние
СИСТЕМА МОДУЛЕЙ В XC_VM УЖЕ СУЩЕСТВУЕТ.
ПРОБЛЕМА НЕ В ОТСУТСТВИИ МОДУЛЕЙ,
А В НЕПОЛНОЙ WEB-ИНТЕГРАЦИИ И LEGACY-СЦЕПЛЕНИЯХ.
На текущий момент:
- модули обнаруживаются через
modules/*/module.json - CLI-интеграция работает
- есть UI для install, uninstall, enable, disable, update и upload ZIP
- часть модульных маршрутов уже описана в самих модулях
- web runtime всё ещё не использует модульный boot как основной путь
2. Что уже реализовано
| Компонент | Статус | Примечание |
|---|---|---|
ModuleInterface |
ГОТОВО |
Базовый контракт присутствует |
ModuleLoader::loadAll() |
ГОТОВО |
Auto-discovery по module.json |
ModuleLoader::loadAll() с dependencies |
ГОТОВО |
Topological sort (DFS) с detection cyclic deps и missing deps |
ModuleLoader::loadAll() с environment filter |
ГОТОВО |
Фильтрация по SERVER_TYPE (main/lb/any) |
ModuleLoader::registerAllCommands() |
ГОТОВО |
CLI-команды модулей реально подключаются |
ModuleLoader::bootAll() |
ГОТОВО |
Реализован; остаются legacy-узлы web bootstrap вне модульного lifecycle |
config/modules.php |
ГОТОВО |
Overrides для enabled/class |
ModuleManager |
ГОТОВО |
Список, install, uninstall, enable, disable, update, upload |
| Админ-страница модулей | ГОТОВО |
ModulesController + Views/admin/modules.php |
Регистрация events в контейнере |
ГОТОВО |
Это больше не backlog |
7 модулей в src/modules/ |
ГОТОВО |
watch, plex, tmdb, ministra, fingerprint, theft-detection, magscan |
ВЫВОД:
УПРАВЛЕНИЕ МОДУЛЯМИ УЖЕ ЕСТЬ.
ПЕРЕПИСЫВАТЬ ЕГО С НУЛЯ НЕ НУЖНО.
3. Что ещё не доведено до цели
3.1. Web boot модулей не включён
public/index.phpне вызываетModuleLoader::loadAll()иbootAll()- из-за этого
boot()иregisterRoutes()не являются реальным источником web routing
3.2. Маршруты модулей продублированы в ядре
watch,plex,fingerprint,theft_detectionи связанные страницы зарегистрированы статически вpublic/routes/admin.php- это делает модульную маршрутизацию вторичной и неавторитетной
3.3. Legacy-остатки в навигации и web bootstrap
- модульные пункты меню уже регистрируются через
registerNavbar()+NavbarRegistry - рендер в
public/Views/admin/header.phpвыполняется из дереваNavbarRegistry, без hardcoded ссылок конкретных модулей - остаются точки legacy-сцепления вне navbar (в отдельных route/bootstrap участках), которые ещё нужно довести до полной целевой модели
3.4. module.json v2 — готово
M-4 завершена. Manifest теперь содержит:
name— имя модуляdescription— описаниеversion— версия (semver)requires_core— требуемая версия ядраenvironment— окружение (main/lb/any) NEWdependencies— список зависимостей от других модулей NEWhas_navbar— наличие пунктов навбара (boolean) NEWhas_settings— наличие страницы настроек (boolean) NEW
Все 7 модулей уже переведены на v2 манифест.
3.5. Core patching остаётся аварийным обходным путём
CoreCodePatchableModuleInterfaceиCoreCodePatcherуже есть- это допустимо только как временный stopgap
- целевая архитектура не должна расширяться заменой файлов ядра
3.6. Ministra остаётся особым случаем
- часть поведения завязана на
www/cиwww/portal.php - модуль
ministraесть, но интеграция не доведена до единой модульной модели
4. Целевая модель модулей
ЦЕЛЬ:
МОДУЛЬ = ИЗОЛИРОВАННАЯ ДИРЕКТОРИЯ + ДЕКЛАРАТИВНЫЙ MANIFEST +
РЕАЛЬНЫЙ WEB/CLI LIFECYCLE БЕЗ ПАТЧИНГА ЯДРА.
4.1. Целевой lifecycle
ModuleLoader::loadAll()ModuleLoader::bootAll($container, $router)в web-контекстеModuleLoader::registerAllCommands($registry)в CLI-контексте- navbar, settings и hooks строятся из декларации модуля
- ядро не содержит hardcoded пунктов модульной логики
4.2. Manifest v2 — уже реализован
{
"name": "watch",
"description": "Watch activity tracking module",
"version": "1.1.0",
"requires_core": ">=2.0",
"environment": "main",
"dependencies": [],
"has_navbar": true,
"has_settings": true
}
Примеры с зависимостями:
{
"name": "plex",
"version": "1.0.0",
"requires_core": ">=2.0",
"environment": "any",
"dependencies": ["ministra"],
"has_navbar": true,
"has_settings": true
}
Как это работает:
- ModuleLoader сканирует
modules/*/module.json - Для каждого модуля проверяет:
- Окружение совпадает с
SERVER_TYPE(main/lb) илиany - Все зависимости тоже в списке обнаруженных модулей
- Окружение совпадает с
- Строит граф зависимостей и сортирует топологически (DFS)
- Если цикл или отсутствующая зависимость → fail-fast с понятной ошибкой
- Загружает модули в правильном порядке: зависимости всегда раньше зависимых
4.3. Целевая интеграция UI
Модуль должен уметь декларативно регистрировать:
- маршруты
- команды
- event subscribers
- navbar items
- страницу настроек
Без прямого редактирования:
public/routes/admin.phppublic/Views/admin/header.php- файлов ядра в
core/
5. Пошаговый план рефакторинга
PHASE M-1 / WEB BOOT
- Подключить
ModuleLoader::loadAll()иbootAll()вpublic/index.phpпосле загрузки статических route files. - Добавить dev-guard на конфликты маршрутов.
- Зафиксировать правило приоритета: core route first, module route second, затем планомерное удаление legacy-дубликатов.
Результат: web runtime впервые начинает реально использовать lifecycle модулей.
PHASE M-2 / ROUTE CUTOVER
- Удалить из
public/routes/admin.phpмаршруты, уже описанные в модулях. - Для каждого удаления подготовить smoke-check страницы и API-действий.
- Включить логирование route collisions на переходный период.
Результат: источник истины по маршрутам перемещается в модули.
PHASE M-3 / NAVBAR API
- Создать extension points для header navigation. ✅
- Вынести builder/render слой модульной навигации из
header.php. ✅ - Добавить декларацию navbar items на стороне модулей. ✅
- Удалить hardcoded ссылки
plex,watch,fingerprintиз header runtime. ✅
Результат: ядро перестаёт знать о конкретных модулях на уровне меню.
PHASE M-4 / MANIFEST V2 [✅ ЗАВЕРШЕНА]
Что сделано:
- ✅
module.jsonрасширен полямиenvironment,dependencies,has_navbar,has_settings - ✅
ModuleLoaderфильтрует по окружению (main/lb/any) - ✅
ModuleLoaderсортирует топологически (DFS) с detection циклических и отсутствующих зависимостей - ✅ Все 7 модулей переведены на v2 манифест
- ✅ Документированы строгие типы для dependency items (non-empty strings)
- ✅ Добавлены unit-тесты для всех сценариев (missing-dep, cyclic-dep, sort-order, env-filter)
- ✅ ModuleLoader полностью документирован англоязычными docblocks
Результат: модульная система получила управляемый порядок загрузки, awareness по окружению и fail-fast валидацию.
PHASE M-5 / HOOKS INSTEAD OF PATCHES
- Инвентаризировать, где реально нужен
CoreCodePatcher. - Для каждого кейса ввести hook point в ядре или публичный extension contract.
- Запретить новые модули, требующие full-file patching core-файлов.
Результат: модульная система становится расширяемой без замены файлов ядра.
PHASE M-6 / MINISTRA NORMALIZATION
- Перевести
ministraна единые asset/runtime правила. - Убрать управление
www/cиwww/portal.phpиз module lifecycle. - Завести отдельную документированную integration boundary для MAG и portal compatibility.
Результат: Ministra перестаёт быть legacy-исключением внутри модульной модели.
6. Правила разработки модулей
6.1. Архитектурные правила
- Модуль зависит только от
core/,domain/и публичных extension contracts. - Модуль не модифицирует
core/иdomain/напрямую. - Модуль не ходит в БД мимо agreed service/repository boundary, если такой boundary уже существует.
- CLI-регистрация всегда явная через
registerCommands(). - Web-интеграция всегда проходит через
boot()иregisterRoutes().
6.2. UI-правила
- Модуль не вставляет секреты, API-ключи, служебные токены и внутренние endpoint credentials в HTML, JS, CSS и шаблоны.
- Клиентская часть получает только публичные флаги и данные, уже разрешённые сервером.
- Настройки модуля рендерятся через server-side flow, а не через захардкоженные JS-константы с чувствительными данными.
6.3. Правило маршрутов
НОВЫЙ ROUTE В МОДУЛЕ НЕЛЬЗЯ ДОБАВЛЯТЬ В public/routes/admin.php.
НОВЫЙ ROUTE ОБЯЗАН ЖИТЬ В registerRoutes().
6.4. Правило навигации
НОВЫЙ ПУНКТ МЕНЮ НЕЛЬЗЯ ВСТАВЛЯТЬ В header.php РУКАМИ.
ОН ДОЛЖЕН ПРИХОДИТЬ ИЗ NAVBAR CONTRACT МОДУЛЯ.
7. Definition of Done
Модульная система считается доведённой до целевого состояния, когда одновременно выполнены все условия:
public/index.phpреально вызываетModuleLoader::bootAll().- В
public/routes/admin.phpне осталось hardcoded маршрутов модулей. - В
public/Views/admin/header.phpне осталось hardcoded ссылок на конкретные модули. - Новый manifest поддерживает
environmentиdependencies. CoreCodePatcherне нужен для штатного расширения ядра.ministraработает без опоры наwww/cиwww/portal.php.- Ни один модуль не раскрывает секреты или API-ключи в клиентской части.
ФИНАЛЬНОЕ СОСТОЯНИЕ:
МОДУЛИ = ПОЛНОЦЕННЫЙ EXTENSION LAYER.
НЕ ХАРДКОД В ЯДРЕ.
НЕ ЛОКАЛЬНЫЕ ИСКЛЮЧЕНИЯ.
НЕ ПАТЧИНГ ФАЙЛОВ.