feat: единая админка runtime-конфигов и indpic (#22)
deploy-preland / deploy zoomstage.online (push) Successful in 1m1s
deploy-preland / deploy zoomstage.online (push) Successful in 1m1s
This commit is contained in:
1 parent
5b6b2d2053
commit
9515c1c62b
52 files changed
+2459
-34
No files matched your search
@@ -0,0 +1,98 @@
|
||||
# Админка прелендингов — preland#22
|
||||
|
||||
Отдельное PHP-приложение для `admin.zoomstage.online`. Формы редактируют фактические
|
||||
`config.json`, выбранные поля применяются к одному или нескольким доменам. ZIP indpic
|
||||
проверяется по контракту CPanel и доставляется на выбранные хостинги. Изменение контента
|
||||
не требует Git/push/deploy; `admin/` не входит в публичную поставку прелендингов.
|
||||
|
||||
Спецификация и план — `docs/superpowers/{specs,plans}/2026-10-25-preland22-*` в репозитории,
|
||||
копии и фактический статус — в базе знаний, основной реестр — preland#22.
|
||||
|
||||
## Состав и доступы
|
||||
|
||||
`compose.yaml` запускает web и отдельный worker из одного неизменяемого образа. Нужны
|
||||
PHP8.3, ZIP, Imagick с AVIF/WebP/JPEG и phpseclib3 из зафиксированного Composer lock.
|
||||
На Windows ничего устанавливать не требуется: сборка и проверки выполняются Docker.
|
||||
|
||||
На сервере `/srv/preland-admin`: `compose.yaml`, `.env` с `ADMIN_IMAGE`, закрытый
|
||||
`secret.env`, `state/`, `secrets/` и `deploy/`. В `secret.env` задаются `ADMIN_USERNAME`
|
||||
и `ADMIN_PASSWORD_HASH`; bcrypt-значение заключается в одинарные кавычки, чтобы Compose
|
||||
не интерполировал `$`. Пароль хешируется через `bin/password-hash.php` со stdin.
|
||||
В HTTP Secure-cookie включена по умолчанию; `ADMIN_COOKIE_SECURE=0` разрешена только
|
||||
на изолированном HTTP-стенде.
|
||||
|
||||
UID/GID приложения — 997:987. Приложение получает приватный state и ровно два local
|
||||
mount: `/targets/zoompixel.ru`, `/targets/zoomstage.online`. Весь `/srv/preland`, Docker
|
||||
socket, root SSH key и база основного сайта в приложение не передаются. Права публикации
|
||||
на каждом корне проверяются реальным временным файлом/rename при проверке подключения;
|
||||
нельзя включать запись до успешной проверки.
|
||||
|
||||
Два REG.RU-хостинга подключаются SFTP/SSH с их обычными ограниченными учётными записями.
|
||||
Нужны абсолютный корень, host key либо SHA256 fingerprint, пароль или приватный ключ,
|
||||
доступный через stdin CLI `bin/target-import.php`. Секрет хранится 0600 в приватном state,
|
||||
по API не возвращается. На удалённом хосте нужен `php` CLI >=8.1 с `fsync`; удалённый
|
||||
Imagick не нужен. Замена реквизитов сбрасывает проверку подключения.
|
||||
|
||||
## Работа через формы
|
||||
|
||||
1. Выбрать исходный домен: данные и SHA-версия читаются с его хостинга.
|
||||
2. Изменить поля. Отмечаются только введённые поля; можно явно выбрать группу/всю форму.
|
||||
3. Отметить домены и нажать «Применить к выбранным». Каждый домен использует собственную
|
||||
прочитанную версию и сохраняет свои остальные значения. После сохранения перечитать домен.
|
||||
4. В журнале проверить отдельные статусы. Успешные цели не повторяются. Конфликт требует
|
||||
перечитать данные; после неизвестного результата повтор сначала сверяет фактический хеш.
|
||||
5. В indpic выбрать ZIP либо проверить уже загруженную SFTP-папку. Новый набор сам не
|
||||
меняет default/веса. Чтобы назначить новый номер indpic default, он должен присутствовать
|
||||
в таблице весов — можно с весом0. Это действующее правило resolver, а не вес трафика.
|
||||
|
||||
Номера — 1–9, ZIP содержит папку номера и ровно90 изображений установленных форматов/
|
||||
размеров; лимит8МиБ на файл,64МиБ распакованного набора. При нулевой сумме весов rnd
|
||||
использует первый ключ weights по порядку config.json; только cons использует default.
|
||||
Имена numeric/legacy UTM адаптируются отдельно для каждой цели, конфликтующие aliases
|
||||
блокируются. Удаление набора из реестра оставляет файлы; используемый номер удалить нельзя.
|
||||
|
||||
## Каталог групп и приватная публикация
|
||||
|
||||
`deploy/export-catalog.php` выполняется внутри существующего API-контейнера минимальным
|
||||
Yii bootstrap, в read-only DB-транзакции. Он экспортирует только номера/названия degr/tp/cons,
|
||||
не выдавая приложению доступ к БД. `deploy/refresh-catalog.sh` запускается host cron раз
|
||||
в минуту от root. Подготовка/проверка/chown происходят в root-only `secrets/`, затем
|
||||
`mv -fT` заменяет фиксированный `state/catalog.json` без следования ссылке назначения.
|
||||
Снимок действует180секунд только для совпадающего основного host. Недоступный/старый
|
||||
каталог даёт явную пометку непроверенного существования групп, а не выдуманный список.
|
||||
|
||||
Резервы и journal локального транспорта хранятся в приватном state. Для exact bind mount
|
||||
папка подготовки `.preland-admin-staging` создаётся внутри корня с0700; публичный веб-сервер
|
||||
другого UID обязан получать403 и через внешний origin, и через прямой loopback Apache.
|
||||
При наличии nginx-правила deny оно служит дополнительной защитой. Одной надежды на
|
||||
`.htaccess` недостаточно: AllowOverride может быть выключен. Каталог активного `/N/` —0755,
|
||||
файлы0644. SFTP использует приватную sibling-папку вне webroot.
|
||||
|
||||
Переключение каталогов имеет два rename и durable journal. При аварии upload-child
|
||||
supervisor сразу пытается восстановить полный прежний/новый набор под тем же lock;
|
||||
при полном перезапуске это делает следующая операция транспорта. Неподтверждённый
|
||||
результат остаётся unknown. Это восстановление после прерывания, а не обещание отсутствия
|
||||
краткого окна между двумя rename. При недоступном SSH восстановление нельзя подтвердить.
|
||||
|
||||
## Сборка, проверки и выпуск
|
||||
|
||||
```sh
|
||||
docker build -t preland-admin:<git-sha> -f admin/Dockerfile admin
|
||||
docker run --rm --entrypoint composer -v "$PWD:/work:ro" -w /work/admin preland-admin:<git-sha> test
|
||||
docker run --rm --entrypoint bash -v "$PWD:/work:ro" preland-admin:<git-sha> -c 'sed "s/\r$//" /work/admin/tests/catalog-publish.sh | bash'
|
||||
```
|
||||
|
||||
Дополнительные Docker проверки: `tests/backend-sftp.Dockerfile` — настоящий SSH/SFTP,
|
||||
`tests/backend-worker.php` — цикл с паузой65секунд, `tests/ui-*.cjs` — реальные browser
|
||||
сценарии. Последние выполняются только на disposable целях; они изменяют и восстанавливают
|
||||
настройки. `NODE_PATH=/e2e/node_modules`, `CHROMIUM_PATH` задаёт браузер имеющегося e2e-образа.
|
||||
|
||||
Для production подготовить отдельный TLS/nginx по `deploy/nginx.conf`, импортировать
|
||||
проверенные подключения, сохранить резерв состояния, указать точный image в `.env`, затем
|
||||
`docker compose up -d`. Проверить web/worker health, вход, четыре чтения, безопасный реальный
|
||||
цикл сохранения/перечитывания, ZIP и публичные изображения. Не заменять runtime-конфиги
|
||||
Git-снимком. Для отката приложения вернуть прежний `ADMIN_IMAGE`; state и контент сохраняются.
|
||||
Возврат контента выполняется отдельно через резерв и CAS, не через старый Docker-образ.
|
||||
|
||||
Фактические production-команды, версии, ограничения, свидетельства UI и статус подключения
|
||||
четырёх доменов фиксируются в preland#22 и KB; этот README сам не доказывает завершение выпуска.
|
||||
Reference in new issue
Block a user