11 KiB
preland#22 — план реализации единой админки
Спецификация: ../specs/2026-10-25-preland22-admin-design.md; основной реестр preland#22. Владелец 25.10 поручил выполнение командой до production без повторного подтверждения. Метод: writing-plans, dispatching-parallel-agents для независимых файловых областей, TDD, систематическая диагностика при сбоях, независимое review и verification-before-completion. Работа в уже изолированном wt/preland21; исходные checkout/ветки не переключаются.
Цель: безопасно редактировать поля runtime-конфигов и публиковать indpic на выбранных доменах. Архитектура: отдельное PHP-приложение admin/, прямые local/SFTP+SSH-адаптеры, приватный файловый реестр/очередь заданий, повторное использование CPanel indpic UI/валидатора. Стек: PHP8.3, phpseclib3, Imagick/ZIP, Apache, отдельный CLI-worker, Docker, nginx/TLS. Python используется в инструментах QA/инфраструктуры, Yii2 — источник совместимого контракта, новые прикладные микросервисы без функциональной причины не добавляются.
Общие ограничения и карта поверхности
- Русский интерфейс/документация, все поля config через формы, JSON-editor отсутствует.
- Четыре начальные цели, произвольный дальнейший реестр; .online кроме stage не включать.
- Изменения только выбранных полей/целей, конфликты версий, резерв вне webroot, атомарная публикация и повторное чтение, статусы/повтор каждой цели независимо.
- Секреты только вне Git/webroot; ключ root приложению не передаётся.
- indpic1–9, ZIP и 90файлов проверяются действующим валидатором CPanel.
- Сохранить runtime config и /N/ при кодовом deploy; guard runtime проверяет контракт, а статические ресурсы остаются привязаны к manifest Git.
- Все зависимости/тесты в Docker. Browser plugin not available: реальный UI в Docker Playwright.
- Карта UI: login, домены/подключения, настройки/доп.поля, выбор целей/полей, задания/частичный успех/конфликт/повтор, резерв/восстановление, indpic ZIP/SFTP/default.
Общий HTTP-контракт для независимой реализации
Все ответы JSON: {ok:true,...} либо {ok:false,error:"понятный текст"}; безопасные HTTP-коды. POST/PUT/DELETE требуют header X-CSRF-Token после login; multipart также использует header.
- POST /api/login {username,password}; GET /api/state → {csrf,user,targets}; POST /api/logout.
- targets имеют id,name,domain,environment,type(local|sftp),host,port,user,root,host_key, enabled,has_secret; сервер никогда не возвращает secret/private_key.
- POST /api/targets {target:{...},secret?:string}; DELETE /api/targets {id}; POST /api/targets/test {id} проверяет подключение и безопасные пути.
- GET /api/config?target=id → {config,version,warnings,sets}; version=SHA256 текущего файла.
- POST /api/apply {targets:[{id,version}],changes:[{path:[string...],value:any,delete?:bool}]} → {job}; версии каждой цели берутся её собственным чтением, не от исходного домена.
- GET /api/jobs?id=id → {job}; без id → {jobs}; POST /api/jobs/retry {id,targets:[id...]} → {job}. job={id,status,results:[{target,status,message,version?}],...}; статусы queued,running, success,error,conflict,unknown; статус задания queued,running,completed.
- GET /api/backups?target=id → {backups:[{id,created_at}]}; POST /api/restore {target,id,version} → {job}.
- GET /api/sets?target=id → {sets:[{number,name,exists,default,in_use}],version}; POST /api/sets/upload multipart file,number,name,targets(JSON-массив id) → {job}; POST /api/sets/check {targets:[id],number} → {job}; POST /api/sets/register аналогично +name; POST /api/sets/name {target,number,name}; POST /api/sets/delete {target,number}; default задаётся /api/apply по path utm/indpic/default и текущей version. Технические расширения контракта допустимы с синхронизацией агентов и записью в #22.
Задача 1 (#22): серверная логика и файловый контракт
Владелец: backend (Yii2 senior/PHP senior, security/transport). Файлы: admin/src/, admin/public/index.php, admin/bootstrap.php, admin/bin/, admin/composer.json/lock, admin/tests/backend*.php; не менять UI/Docker/CI.
- RED: выбранный patch сохраняет поля/типы, чужая версия не затирается, массовая ошибка одной цели не откатывает другие, резерв восстанавливается по версии.
- Реализовать auth/CSRF, защищённый реестр соединений, транспорт local и SFTP/SSH, серверные задания/worker, конфиги/валидацию/историю и HTTP-контракт выше.
- Перенести IndpicSetStorage с атрибуцией; проверять ZIP до доставки, затем хеши, публикацию/откат; регистрацию SFTP-набора, имена/default/удаление из реестра.
- GREEN в Docker, реальные подключения через локальную SFTP-цель, auth/error/race/ZIP tests.
Задача 2 (#22): интерфейс на основе CPanel
Владелец: frontend senior, дизайнер, верстальщик. Файлы: admin/views/dashboard.php, admin/public/assets/, admin/tests/ui.cjs. Вход public/index.php рендерит dashboard.php для обычных URL; API выше.
- Форма входа, домены, редактор всех config-полей и UTM, один/несколько выбранных доменов и только изменённые поля; версии до редактирования, без silent overwrite.
- Таблица/действия indpic копируют CPanel, включая ZIP/SFTP и понятное окно проверки.
- Подключения/история/резерв, задания/частичные ошибки/повтор, loading/error/recovery; безопасный текстовый вывод любых серверных полей, desktop/mobile/keyboard.
- Реальные browser сценарии login→чтение→ввод→выбор2целей→применить→reload; ошибка/восстановление/ZIP; сохранить screenshot и console evidence вне repo.
Задача 3 (#22): runtime guard и доставка
Владелец: DevOps/QA (независимо от admin/). Файлы: bin/release-assets.php, новый bin/check-runtime-sets.php, tests/check-runtime-sets.php, .gitea/workflows/deploy.yml, AGENTS.md/CLAUDE.md/README.md только относящиеся части.
- RED: корректно заменённый runtime-набор не требует Git; повреждённый активный набор/невалидный default выявляется; общая проверка статики не ослабевает.
- Изменить --stage-sets/--remote на контрактную проверку runtime /N/ и manifest только кода/поставляемых ресурсов; admin/ и приватные файлы не входят в preland releaseFiles.
- GREEN в Docker + старые preland tests/manifest; документация обновляет #11 явно.
Задача 4 (#22): интеграция, инфраструктура и приёмка
Владелец: ведущий агент (Senior DevOps/Linux/Windows, QA и release). Файлы: admin/Dockerfile, admin/compose.yaml, admin/deploy/, admin/README.md, локальные output/preland22/; KB Спеки/Планы/Инфраструктура и индекс.
- Создать образ/локальный стенд и SSH/SFTP fixture, запустить backend/guard тесты.
- Реальный UI-клик в Docker Playwright 1440/390: все общие состояния и контракты из спецификации, с отдельными read/save/conflict/partial/retry/ZIP свидетельствами.
- Независимое review всего diff; исправить существенные замечания, повторить затронутые сценарии, подготовить rollback и неизменяемую версию образа.
- Настроить admin.zoomstage.online DNS/TLS/nginx, ограниченные local mount/SFTP доступы, секреты в приватном состоянии, отдельный worker; текущий трафик не прерывать.
- Проверить на установленной админке вход/чтение всех4целей, реальный безопасный write/read/ZIP/error/recovery с возвратом исходных runtime; никаких ложных PASS.
- Опубликовать код и KB, занести итог/проверки/версии/ограничения в #22, закрыть только после завершения. Неисполненные обязательные сценарии оставить открытыми.
Особое внимание review
- Разные версии/типы/legacy-alias четырёх файлов и потеря неизвестных полей — тест задачи1.
- Таймаут после фактической записи/обновление страницы — задания/повтор задачи1+2.
- Повреждённый ZIP/размер/traversal/лимит/ошибка активации — задача1 и UI задачи2.
- Подмена пути/host key, утечка пароля, CSRF/сессия и незавершённые задания — задача1/4.
- Runtime-изменения не должны блокировать выпуск или публиковать admin-секреты — задача3/4.