Тестовый стенд
Новое Собрали ответы на частые вопросы о работе с системой Открыть раздел →
🍪 Cookie и персональные данные

  Мы используем обязательные cookie для работы сайта и аналитические — для сбора обезличенной статистики. Нажимая «Принять», вы соглашаетесь на аналитику. Выбор «Только необходимые» оставит сайт полностью функциональным.

Подробнее — в политике конфиденциальности и пользовательском соглашении.

🧩

Разработчикам

Обычный Laravel 13 без собственной вселенной: модуль — папка с сервис-провайдером, расширение — подписанная поставка, и всё ставится и снимается кнопкой или командой artisan.

Обновлено 08.11.2026 ~9 мин чтения Участие
Разработчикам
  • Laravel 13основа — без своего «ядра с хуками»
  • PHP 8.5минимальная версия
  • 25модулей в поставке, каждый — отдельная папка
  • 5видов кирпичей: платформа, тема, шаблон, модуль, язык

Архитектура

Ядро и кирпичи

Контроллеры, модели, миграции и вьюхи лежат там, где их ищет любой Laravel-разработчик. Разобраться здесь дешевле, чем в системе с собственными правилами на каждый случай.

Ядро

Вход, раздел «Модули», Маркет, обновления, установка, темы, меню и материалы. Ядро есть всегда, и снять его нельзя.

Кирпичи

Платформа, тема, шаблон, модуль и язык. Ставятся и снимаются целиком, снятие обратимо, а совместимость с сайтом видна ещё до нажатия.

Реестры

Ядро не знает кирпич по имени. Оно спрашивает реестры шаблонов, языков и разделов панели и проверяет class_exists. Нет кирпича — нет пункта, а не ошибка 500.

Это правило сторожит отдельный тест: если ядро где-то обратится к модулю напрямую, снятие модуля уронит страницу — и тест упадёт раньше, чем это увидит покупатель.

Модуль изнутри

Модуль — это папка, а не магия

Каждый раздел живёт в modules/<Имя>/, и всё, что ему нужно, лежит рядом.

  • module.jsonИмя, версия, приоритет загрузки, зависимости requires и список провайдеров.
  • Routes/web.phpМаршруты подключаются сами, но только у включённого модуля.
  • Views/Вьюхи в пространстве имён модуля: view('Имя::…').
  • Lang/Словари модуля, тоже под его именем: __('Имя::файл.ключ').
  • Controllers, Models, ServicesОбычные классы Laravel в пространстве Modules\Имя.
  • Providers/Обычный сервис-провайдер Laravel. Никаких чужих точек расширения.

Каркас создаёт одна команда, а модуль появится в разделе «Модули» сам — система сверяет папки с таблицей модулей при запуске.

php artisan make:module Portfolio

# modules/Portfolio/module.json
{
    "name": "Portfolio",
    "title": "Portfolio",
    "version": "1.0.0",
    "active": true,
    "priority": 50,
    "description": "Модуль Portfolio",
    "providers": [
        "Modules\\Portfolio\\Providers\\PortfolioServiceProvider"
    ]
}

Важно. Миграции модуля кладите в общую database/migrations/. В папке модуля миграция молча не выполнится. Выключенный модуль не грузится совсем — ни маршрутов, ни провайдеров, — а его таблицы остаются в базе и вернутся вместе с ним.

Шаблон материала

Новая витрина — два файла

Шаблон решает, как выглядит материал: лента, товар, услуга клиники, урок. Чтобы добавить свой, не нужно трогать ни контроллер, ни базу.

  1. Вьюха. resources/views/frontend/templates/<ключ>.blade.php — как выглядит материал.
  2. Карточка. Рядом <ключ>.json: название, версия, описание, категория и рекомендованные модули.
  3. Готово. Реестр шаблонов находит карточку сам — шаблон появляется в форме материала. Удалили файлы — пропал из списка, без висящих записей в базе.
# resources/views/frontend/templates/clinic.json
{
    "template": "clinic",
    "version": "1.3.0",
    "title": "Клиника",
    "description": "Медцентры и частные практики: приёмы, врачи, цены",
    "category": "commerce",
    "recommends": [
        "Forms",
        "Comments"
    ]
}

Маркет и консоль

Две равные двери

Всё, что владелец делает кнопкой в Маркете, разработчик делает командой — с тем же результатом и теми же проверками. Виды: theme, template, module, language.

php artisan market:list module --installed
php artisan market:install theme graphite
php artisan market:install template clinic --with=Forms --with=Comments
php artisan market:remove module Comments
php artisan market:remove template clinic --with-data
php artisan updates:apply --release=3.10.41        # только план
php artisan updates:apply --release=3.10.41 --yes  # установить
КомандаЧто делает
market:listЧто стоит и что можно поставить; --installed и --available сужают список
market:installСтавит тему, шаблон, модуль или язык; --with заодно ставит рекомендованные модули
market:removeСнимает кирпич. Данные модуля остаются в базе; --with-data удаляет и таблицы, а материалы снятого шаблона переводит на «Новости»
updates:versionsДоступные версии и куда можно вернуться
updates:applyБез --yes показывает план и ничего не меняет; --release, --file и --module выбирают, что ставить
security:watchСверяет файлы с описью и сообщает о подброшенных и изменённых; --accept принимает текущие находки как ваши правки
lang:checkСверяет словари всех языков с эталонным русским

Поставки и подпись

Обновление — сравнение двух описей, а не копирование поверх

Канал обновлений — это канал исполнения кода сразу на всех сайтах покупателей. Поэтому он устроен строже, чем обычно.

Как обычно

  • Архив копируется поверх сайта
  • Файл, убранный в новой версии, остаётся и продолжает исполняться
  • Правки владельца молча затираются
  • Подпись проверяется после распаковки — или не проверяется вовсе
  • Снятый модуль возвращается с первым же обновлением

В NEXUM-CORE

  • Опись перечисляет все файлы с суммами: что добавить, заменить, удалить
  • Файл, которого нет в новой версии, удаляется
  • Файл, который правили вы, не трогается и показывается списком
  • Подпись описи (RSA-SHA256) проверяется до распаковки
  • Снятое записано и не вернётся, пока вы не поставите его снова

Проверок перед установкой две. Совместимость — карта: она гасит кнопку ещё до скачивания, если не хватает PHP, нужного модуля, места или прав на запись. Настоящий заслон — проверка по подписанной описи уже скачанной поставки с тремя исходами: отказ, предупреждение, порядок. Пустой открытый ключ не разрешает обновления без проверки, а запрещает их.

# так собирается каждая поставка: платформа, шаблон, тема, язык
php artisan release:build 3.10.41 --severity=feature --notes="..."
php artisan release:template clinic 1.3.0
php artisan release:theme graphite
php artisan release:language en 3.10.41
php artisan market:publish nexum-core-3.10.41.zip

Границы обновления

Чего обновление не коснётся

Не читается и не обновляется вовсе

  • .env и его варианты — настройки вашей установки
  • storage/ — загрузки, кеш, журналы, замок установки
  • public/uploads/ — медиатека
  • vendor/ — его ставит composer по composer.lock, отдельным процессом и только когда замок разошёлся

Обновляется, только пока вы его не правили

  • config/*.php
  • public/.htaccess
  • public/robots.txt

Безопасность в коде

Защита, которую не нужно включать

Включено с первой установки

Большая часть рубежей стоит в самом коде и работает без настройки.

  • Выполняется только index.php. public/.htaccess не даст запустить подброшенный PHP-файл.
  • PHP в содержимом выключен. Включается только явным CONTENT_PHP=true в .env.
  • Сторож целостности. Раз в час сверяет описи платформы, модулей, шаблонов и языков и ищет посторонний PHP; о находке сообщает один раз — в журнал безопасности и письмом администраторам.
  • Автономный режим. Запрет исходящих запросов стоит на самом сетевом клиенте, а не в каждом сервисе по отдельности.
  • Строка PHP в сводке. Панель смотрит ветку PHP и журнал пакета Debian или Ubuntu — видно, закрыта ли уязвимость, даже если номер версии старый.
Кабели и стойки в серверной

Соглашения

Правила, по которым написан код

Их немного, и за каждым — грабли, на которые уже наступали.

  • Только PostgreSQL. С другим драйвером приложение не запустится и скажет почему. Тесты идут на SQLite, поэтому миграции пишутся построителем схемы, без сырого SQL.
  • Строки интерфейса — только через словари resources/lang/ru и en с одинаковыми ключами; расхождения ловит lang:check.
  • Комментарии не доходят до браузера. Служебные пояснения вырезаются при компиляции Blade.
  • Скрипты в браузере — только с латинскими именами.
  • Правите модуль или шаблон — поднимите версию в module.json или карточке шаблона: исправление — третья цифра, новое — вторая.
  • Компонент модуля в ядре выводится только через <x-dynamic-component> с проверкой, что модуль стоит.

Ядро не знает кирпич по имени: только реестры и проверка, что класс существует.

Принцип NEXUM-CORE

Вопросы

Что спрашивают разработчики

Можно ли писать свои модули?

Да. make:module создаёт каркас, а сам модуль — обычный сервис-провайдер Laravel, объявленный в module.json. Он разрабатывается и обновляется отдельно от ядра.

Сторож целостности отметит мой модуль как чужой код?

Да, в первый раз: исполняемый PHP, которого нет ни в одной описи, — это находка. Нажмите «Это мои правки» в сводке или запустите security:watch --accept. Принятое запоминается по сумме: изменится файл ещё раз — сторож снова скажет.

Затрёт ли обновление платформы мои правки в файлах ядра?

Нет. Файл, который разошёлся с описью, обновление пропускает и показывает списком. Но свою логику удобнее держать в модуле: тогда правки ядра не нужны вовсе.

Можно ли откатить неудачное обновление?

Да. Перед заменой файлов снимается копия для возврата назад, включая vendor/, если менялись библиотеки. Куда можно вернуться, показывает updates:versions.

Почему нельзя MySQL, хотя бы для разработки?

Потому что боевая база — PostgreSQL, и запрос, написанный под другую базу, упадёт в худший момент. Заслон стоит при запуске приложения; для тестов разрешён только SQLite.

Где подробности устройства?

На этой странице и в частых вопросах. Исходный код открыт и читается как обычный Laravel-проект, а нестандартную задачу можно разобрать с автором системы напрямую.

Нужна доработка под ваш сайт?

Модуль, шаблон или связка с вашей системой — 2 500 ₽ в час. Обмен с 1С или МойСкладом — от 9 900 ₽.

Обсудить задачуЦены

На главную
Поделиться:
Остались вопросы? Ответим в течение рабочего дня — напишите нам удобным способом.
Написать нам