# Единая админка прелендингов — preland#22 Дата: 25.10.2026. Статус: проект на согласование; реализация и выпуск ещё не выполнены. Реестр: http://git.dira89kv.beget.tech:3000/anton/preland/issues/22. Размещение и доступы: preland#21. Секреты в документ не входят. ## Задача владельца Одна защищённая админка на поддомене stage управляет фактическими config.json и наборами indpic четырёх независимых прелендингов. Редактирование и публикация контента проходят без Git, ручной работы с JSON и разноса файлов через FTP-клиент. Домены и хостинги можно добавлять, менять и отключать через эту же админку. Начальные цели: zoomila.ru, zoomika.ru, zoompixel.ru, zoomstage.online. Отключённые .online не подключаются. Рабочее имя админки: admin.zoomstage.online. Размещение на отдельном поддомене и повторное использование редактора indpic CPanel поручены владельцем; конкретное имя admin и технические решения ниже предложены агентом. ## Подход Предлагается отдельное PHP-приложение в репозитории preland, с собственным Docker-образом и отдельной поставкой. Оно использует SFTP/SSH, а для каталогов на том же сервере — ограниченный файловый адаптер. Работа с конфигом не требует запуска деплоя. Управление не публикуется внутри поставки обычных прелендингов. Перенос всей Yii2 CPanel потребовал бы базы и зависимостей основного сайта; его API и релиз стали бы зависимостью обычного изменения настроек. Поэтому переносится конкретный редактор наборов, его внешний вид, поведение и файловый валидатор, а зависимые от БД операции заменяются файловым реестром админки. Клиентский FTP из браузера не подходит для серверных проверок и хранения доступов. Источник переиспользования: api origin/master 591a67cc8302, components/indpic/IndpicSetStorage.php и indpic-блок modules/cpanel/views/settings/index.php, соответствующие действия SettingsController. Копия снабжается ссылкой на источник и совместимыми контрактными тестами. Бизнес-логика основного API, платежи, PIN и маршруты основного сайта не меняются. ## Экран настроек Список доменов показывает stage/production, состояние соединения и последнее чтение. Открытие домена читает текущий удалённый файл; локальная копия не считается источником истины. При недоступности хоста сохранение в него недоступно, другие цели работают. Вместо текстового JSON — поля адреса основного сайта, строки реквизитов и восемь групп UTM: indpic, theme, degr, reg, banch, tp, cons, focus. Для каждой группы — вариант по умолчанию, таблица вариантов и неотрицательные веса, пояснения значений. Поддерживаются добавление и удаление строк весов. Реквизиты редактируются строками. Дополнительные уже существующие поля показываются типизированными вложенными полями (текст, число, переключатель, массив, объект), без редактора JSON. Отсутствующие неизвестные поля не создаются автоматически. Секреты не выводятся в диагностику. Текущий zoompixel.ru может содержать старые semantic-ключи/значения. Они отображаются понятными вариантами через действующий utm-codec; сохранение меняет только выбранные поля. Неизменённые поля, их типы и значения сохраняются. Конфликтующие старый и новый ключи нельзя молча объединять: показывается понятная ошибка до записи. После редактирования пользователь отмечает один или несколько доменов и нажимает «Применить к выбранным». Перед кнопкой видны выбранные поля и домены. По умолчанию отмечен только открытый домен; нет скрытого автоматического выбора всех целей. Распространяются только изменённые/явно выбранные поля, остальные настройки каждой цели сохраняются. Можно явно выбрать целую группу UTM или все поля формы. Если значения между доменами отличаются, показывается «Разные значения»; без явного ввода пользователя это состояние не превращается в новое значение. До публикации для каждой цели проверяются типы/структура, допустимые UTM 1–9, варианты theme/reg/banch/focus, веса, существование indpic для default и ненулевых весов. Для degr/tp/cons используются номера групп, проверяемые по доступным данным основного сайта. Если каталог доступен, неизвестный номер блокируется. Если каталог недоступен, разрешён ручной выбор номера 1–9 с явной пометкой «Существование группы на основном сайте не проверено» в форме и результате; сохранение не выдаётся за проверку API. Это решение исполнителя сохраняет независимость редактора от API; соответствующие состояния включены в приёмку. Выдуманного списка групп нет. Сумма весов может быть нулевой: действующий преленд тогда использует default. Адрес сайта — допустимый HTTPS-хост без пути. ## Сохранение и массовые операции Каждая форма хранит версию прочитанного файла (SHA-256). Непосредственно перед записью проверяется текущая версия под блокировкой публикации. Если файл изменился снаружи, цель получает конфликт и предложение перечитать/повторно применить изменения. Чужая версия не затирается. Успешная запись: резерв вне webroot, временный файл, проверка JSON, атомарная замена и повторное чтение/сверка. Протокол и адаптер должны поддерживать этот контракт, иначе соединение нельзя включить для записи. SSH доступен на начальных REG.RU-хостах и позволяет выполнить проверку/замену под удалённой блокировкой; одной локальной блокировки админки недостаточно. Массовое применение — независимые операции с отдельными статусами: ожидание, выполняется, сохранено и проверено, конфликт, ошибка, неизвестный результат. Сбой одной цели не отменяет уже успешные и не мешает остальным. Общего обещания «всё сохранено» при частичном успехе нет. Повтор выполняется только для выбранных неуспешных целей; после таймаута сначала перечитывается фактическое состояние. Задание и результаты сохраняются на сервере, обновление страницы их не теряет. Есть журнал с доменом, временем, изменёнными полями и исходом без паролей. Восстановление выбранной резервной версии проходит ту же защиту от конфликта. ## Наборы indpic Переиспользуется таблица CPanel: номер/название, default, проверка, ZIP, действия; добавление ZIP либо проверка набора, уже загруженного по SFTP, модальное окно результата. Номер для прелендинга ограничен 1–9 действующим внешним UTM-контрактом. Название хранится в приватном реестре админки, default/веса — в config.json цели. Один архив можно отправить на один или несколько выбранных доменов. Проверка до доставки: каталог номера набора и ровно 90 обязательных изображений, отсутствие лишних/повторных/вложенных/опасных путей, чтение каждого изображения и размеры из существующего IndpicSetStorage. Лимиты ZIP, распаковки и времени задаются сервером. Проверенный набор передаётся в непубличную подготовительную папку на целевом хосте, проверяются все файлы/SHA-256, затем переключается каталог с резервом и откатом при ошибке. Папки подготовки/резерва никогда не обслуживаются веб-сервером. Для уже загруженного по SFTP набора файлы проверяются тем же валидатором. Загрузка не меняет default и веса автоматически. Назначение default — явная операция сохранения config.json. Нельзя активировать неполный набор. Замена существующего набора предварительно предупреждает о текущем использовании. Удаление из реестра, как в CPanel, оставляет файлы; нельзя убрать набор, используемый default или весом>0. Удаление физического контента не входит в исходное поручение. ## Подключения и защита Отдельный вход по логину/паролю, хеш пароля, HTTPS, HttpOnly/SameSite session, CSRF, ограничение попыток. Админка использует отдельные доступы ограниченного объёма; приватный ключ root основного сервера приложению не передаётся. Список целей, их имена, окружение, хост/порт, пользователь, корневая папка, проверенный ключ SFTP и секрет редактируются на странице подключений. Секрет можно заменить, но нельзя прочитать обратно в интерфейсе. Проверка соединения должна подтвердить права и реальные пути до включения записи. Приватное состояние, ключи, резервные копии, архивы и журнал — вне webroot/Git, с ограниченными правами и персистентными Docker-томами. Удаление подключения отключает управление и убирает его из списка целей, не удаляя сайт и контент хостинга. Одновременные операции на одном конфиге/наборе сериализуются. Приложение не выполняет произвольные команды, пути ограничены каталогом выбранной цели, host key проверяется. ## Независимость контента от Git и выпуск Текущий workflow не заливает /N/, но --stage-sets сравнивает их с Git, а --remote также включает их в общее сравнение. После замены существующего набора это блокировало бы последующий выпуск кода. В #22 разделить проверки: поставляемый код/статические ресурсы проверяются по manifest Git, runtime-наборы — по фактическому контракту 90 изображений и действующим ссылкам config, без требования импорта в Git. Проверки не выключаются; тестами доказывается, что корректная замена набора пропускается, повреждённый активный набор блокирует проверку, кодовой deploy не меняет config и /N/. Устаревшие требования обязательной синхронизации наборов в Git обновляются явно по #22. Админка выпускается отдельно от прелендов, с TLS на admin.zoomstage.online и четырьмя подключениями. Изменение UTM пользователем не вызывает commit/push/CI. Реальные production-настройки/наборы при установке не меняются. Проверочные записи — в выделенной тестовой цели/наборе с последующим контролируемым восстановлением; отсутствие доступа или непроверенный сценарий оставляет #22 открытой. ## Приёмка В Docker: контракт валидатора CPanel, JSON-типы/semantic-совместимость, патч только выбранных полей, конфликт и два одновременных сохранения, резерв/откат, разрыв связи, таймаут после записи, повтор задания. Локальная SFTP-цель проверяет настоящий протокол. ZIP: корректный набор, отсутствующий файл, размер/формат, лишний/повторный путь, traversal, лимиты, ошибка публикации и сохранение старого рабочего набора. В штатном браузере: вход, открыть/изменить/сохранить/перезагрузить конфиг; разные значения, выбор одного/двух доменов и только нужных полей; частичный отказ, повтор, конфликт и восстановление; ZIP и ошибка с последующей успешной загрузкой; управление подключениями. Desktop/mobile и матрица всех общих состояний/четырёх целей. На установленной админке: TLS/авторизация, чтение всех четырёх целей, безопасный реальный цикл записи/повторного чтения и загрузки на тестовых данных. Итог, версия, проверки и ограничения записываются в #22 и KB до закрытия задачи. ## Решения исполнителя и незавершённое На усмотрение исполнителя: PHP-библиотека SFTP, детали приватного файлового реестра, лимиты и хранение заданий, распараллеливание в пределах ресурсов. Выбор подтверждается тестами и совместимостью с существующим хостингом; установки на Windows-хост нет. Пока не выполнены: согласование этого проекта, реализация, проверки, настройка DNS/TLS, выдача ограниченных доступов и запуск. Секреты/возможности среды требуют фактической проверки; исторический успешный SFTP-вход не доказывает готовность центральной админки.