# Admin Task Board _Updated: 2026-08-16 (15) — ⚪ **[llm-router-failover-proxy] заведена** (по запросу vitya через snolla). LLM-роутер/failover-прокси для pi: алиасы deepseek-flash/deepseek-pro поверх 3 free-роутеров (teamorouter/orcarouter/anymodel) + официальный DeepSeek платным fallback'ом. Приоритет free → провайдерский → платный. Деплой — решение админа (рекомендация заказчика: локально winsw). Спека: `.tasks/llm-router-failover-proxy.md` + письмо в инбокс._ _Updated: 2026-08-16 (14) — 🟢 **[sched-fnf-04-embedded-alerts] ACCEPTED — F&F цикл закрыт.** Приёмка №4 (14:40Z): замечаний нет. Итоги sched: 6 багов/пробелов → 6 фич (exports-map 0.1.2, @sched/ui serve 0.1.1 + токен-бокс, validateConfig 0.12.2, ntfy basic 0.12.2, pollTimeoutMs 0.1.4). Версии: core 0.12.2 / daemon 0.1.4 / ui 0.1.1 / mcp 0.1.1, сьют 363 ✓. У них дальше: storage-сплит (по фидбеку) + полировка доков; раунд 2 согласован: docs-review после storage-сплита + полировки (пинг от sched, формат делал/ожидал/получил/раздел, фокусы: quick-start все пути, 07.storage, 10.cli, 13.ui) _Updated: 2026-08-16 (13) — 🟢 **[sched-fnf-03-async-poll] ACCEPTED + 🟡 [sched-fnf-04-embedded-alerts] DONE (репорт отправлен).** Приёмка №3 (14:31Z): pollTimeoutMs проброшен в daemon (0.1.4, +pollIntervalMs, CLI --poll-timeout), доки 10.cli.md/05.protocol.md. №4 embedded (финальная): createEngine+internal runner+sqlite+syncTasks в одном скрипте — реальная проверка свежести бэкапов kreknin по SSH (vds-kzntsv 12.4h / books-vds 11.4h → succeeded; порог 1h → failed «STALE backups»); retry 3x (a1 fail → a2 fail → a3 succeed, triggerTask не ретраится — доки честны); createAlerts ntfy **basic auth работает** («[sched] backup-freshness failed» в топике). Цикл F&F закрыт, замечаний нет. Репорт: `victor/sched/.agents/inbox/2026-08-16T14-36-01Z-admin-fnf-04-report.md`._ _Updated: 2026-08-16 (12) — 🟢 **[sched-fnf-02-docker-runner] ACCEPTED + 🟡 [sched-fnf-03-async-poll] DONE (репорт отправлен).** Приёмка №2 (14:24Z): оба замечания стали фичами — validateConfig-хук (allowlist на load, abort при старте, core 0.12.2) + ntfy basic auth (user+password в createAlerts, daemon 0.1.3), сьют 362 ✓. №3 async/poll: свой воркер (:8293) envelope accepted+poll — happy path queued→running(50)→succeeded (progress 100, 3.5s), timeout-кейс hung → failed «poll timeout after 15000ms» (через createEngine, т.к. daemon не пробрасывает pollTimeoutMs — замечание в репорт). Фиксы №2 подтверждены (abort на load + ntfy basic в коде). Репорт: `victor/sched/.agents/inbox/2026-08-16T14-27-54Z-admin-fnf-03-report.md`._ _Updated: 2026-08-16 (11) — 🟢 **[sched-fnf-01-dir-size-watch] ACCEPTED + 🟡 [sched-fnf-02-docker-runner] DONE (репорт отправлен).** Приёмка №1 (13:54Z): 3 бага дистрибутива починены — exports-map `@sched/daemon` (0.1.2), UI в `@sched/ui` 0.1.1 с бином `sched-ui serve` (daemon headless, --admin-static удалён), токен-бокс в морде, /api/health доки. №2 docker-runner: one-shot alpine:3.20 `wget --spider` на pilorama98.ru → ntfy sched-fnf, exit code → status (0=succeeded / 1=failed+алерт). Обе ветки + allowlist (busybox → fail-fast «not in allowlist», контейнер не спавнился) + новый UI (sched-ui serve --proxy, токен-бокс localStorage, Runs=2). Репорт: `victor/sched/.agents/inbox/2026-08-16T14-17-55Z-admin-fnf-02-report.md`. 2 замечания: allowlist проверяется на dispatch не на load (доки 03.tasks.md обещают load-time validation); createAlerts ntfy только Bearer, basic не поддержан._ _Updated: 2026-08-16 (10) — 🟡 **[sched-fnf-01-dir-size-watch] DONE (репорт отправлен, жду приёмки).** F&F sched №1 выполнен: custom runner `dirSizeWatch` (createDaemon, @sched/core 0.12.1 + @sched/daemon 0.1.1 из verdaccio, стенд `.tmp/sched-fnf-01/`), задача «раз в 6ч размер C:\sites\snolla\App_Data → ntfy sched-fnf, алерт при >1MB». Обе ветки проверены: 1MB-порог → `⚠️ THRESHOLD EXCEEDED` (priority 5) в ntfy, 100MB-порог → обычное сообщение (37.5 MB). Run succeeded в истории, admin UI отрендерен (скриншот ui.png). **3 косяка доки/дистрибутива в репорт sched:** (1) `03.custom.md` импортирует `createDaemon` из `@sched/core` — его там нет (живёт в `@sched/daemon/dist/daemon.js`, пакет без main/exports); (2) published `@sched/daemon` не содержит `sched-ui.bundle.js` — admin UI 404 из коробки, нужен `uiBundlePath`; (3) морда не передаёт token в веб-компоненты — при SCHED_ADMIN_KEY UI показывает unauthorized, ввести ключ негде. Репорт: `victor/sched/.agents/inbox/2026-08-16T13-21-11Z-admin-fnf-01-report.md`._ _Updated: 2026-08-16 (9) — 🟢 **[pilonuxt-restart-cache-volume-price] DONE.** По запросу прогера (письмо 14:40Z): после перезаливки volume_price (`38c26c7` + admin-api 0.11.0) часть карточек не показывала цену за м³ — content-api держал старый viewModel в памяти контейнера (в БД `voulme_price: 38000` массив, во фронте null). Рестарт контейнера (стек 16, образ `64c2539` без пересборки) → кэш сброшен. Verify мимо LAN-DNS: `/shop/products/imitaciya-brusa-podnyatyj-vors-20-145-6000` 200, `volume_price: 38000` в payload + «Цена за м³» + 38 000 в HTML; категории skandinavskaya-doska/imitaciya-brusa/brus/doska 200, регресс `/`/`/services` 200 + `/services/building` 404. Отписано прогеру (14:55Z)._ _Updated: 2026-08-16 (8) — 🟢 **[deploy-pilonuxt-admin-api-0110] DONE.** Релиз snolla `@snolla/admin-api` 0.11.0 (array-canon: Content=массив, ruling vitya; + D6 dirty-flag). Монорепа HEAD `64c2539` (admin-api 0.10.1→0.11.0, yarn.lock; core 0.26.7). Миграция объектных строк уже выполнена прогером (БД чиста, dry-run идемпотентно). Build из монорепы, push напрямую, Portainer PUT стек 16 (`pullImage:true`, Env:0). Verify мимо LAN-DNS: `/catalog/skandinavskaya-doska` + `/catalog/imitaciya-brusa` 200 0×500 (6+6 товаров), карточки podnyatyj-vors 200, embedded admin-api `/admin/api/health` 200, регресс `/`/`/catalog`/`/catalog/brus`/`/services` 200 + `/services/building` 404. Откат: стек 16→`1128ddc`. Source-of-truth compose актуализирован (`64c2539`)._ _Updated: 2026-08-16 (7) — 🟢 **[deploy-pilonuxt-core-0267-fix] DONE.** Фикс snolla `@snolla/core` 0.26.7 (fillViewModel flat-object normalize — чинит 500 на 10 новых товарах). Монорепа HEAD `1128ddc` (yarn.lock core 0.26.6→0.26.7). Build из монорепы, push напрямую, Portainer PUT стек 16 (`pullImage:true`, Env:0). Verify мимо LAN-DNS: `/catalog/skandinavskaya-doska` 200 0×500 **6 товаров** (3 гладких + 3 podnyatyj-vors), `/catalog/imitaciya-brusa` 200 0×500 **6 товаров** (4 старых + 2 podnyatyj-vors), карточки 3 сэмпла все 200 0×500, регресс `/`/`/catalog`/`/services`/`/catalog/brus` 200 + `/services/building` 404. Откат: стек 16→`f876e70`. Source-of-truth compose актуализирован (`1128ddc`). _Updated: 2026-08-16 (6) — 🔵 **[pilonuxt-new-products-500] ROOT CAUSE найден — баг snolla, ждём фикс.** Прогер подтвердил инспекцией боевой MSSQL: admin-api при create пишет `Products.Content` плоским объектом, `@snolla/core` viewModels читает только массив `[{name,value}]` → `_.find(contentFields, f=>f.name)` падает (viewModels/index.js:419). Сломаны только 10 новых товаров (create через admin-api; update-путь merge'ит в existing-массив — старые живы). Письмо snolla отправлено прогером (фикс: create → 'array' + defensive normalize в core). Рестарт/деплой не нужен. Ожидание: фикс snolla ИЛИ миграция Content 10 товаров в массив (MSSQL, сам прогер) → тогда verify категорий/карточек на проде. Ack отправлен (12:05Z)._ _Updated: 2026-08-16 (5) — 🔴 **[pilonuxt-restart-new-products-500] рестарт НЕ помог — серверный краш.** По запросу прогера (письмо 09:05Z): залил 10 новых товаров через loader (скандинавская доска, имитация бруса поднятый ворс, рейки скрытые), просил рестартнуть стек 16 для подхвата. Рестарт выполнен (Portainer, контейнер running, uptime 2s). Verify: `/catalog/skandinavskaya-doska` + `/catalog/imitaciya-brusa` → HTTP 200, но **500 внутри** (NuxtError, `Request failed with status code 500`); остальные категории (doska/brus/brusok/reyka/terrasnaya-doska) + `/` целы. Логи: `TypeError: Cannot read properties of undefined (reading 'name')` в `@snolla/core viewModels/index.js:419` (`_.find(x=>x.name)` на undefined) через `getProductViewModel` — missing-field у нового товара из заливки, НЕ кэш. Отписано прогеру с уликами (09:15Z); ждём фикс данных/кода → деплой или рестарт по его отмашке._ _Updated: 2026-08-16 (4) — 🟢 **[deploy-pilonuxt-catalog-img-fix-2] DONE.** Фикс прогера `f876e70` (origin/master, 1 файл `categories.json`): оставшиеся 3 плейсхолдера каталога заменены эталонными imgproxy-фото из CMS (list_image → 800×800) — Доска обрезная `ylD4trDVXa…` (было `/images/1.webp`), Доска строительная `qqUyT37cNrf…` (`/images/2.webp`), Брус/брусок/рейка `CGyNTUwB7iY…` (`/images/3.webp`). Build из монорепы, push напрямую, Portainer PUT стек 16 (`pullImage:true`, Env:0). Verify мимо LAN-DNS: `/catalog` 200 + `/` 200, `src=/images/[123].webp` → **0 вхождений**, 25 imgproxy-refs, все 3 новых фото на месте; регресс `/services` 200, `/services/building` 404, `/catalog/brus` 200, `/catalog/antiseptirovannye-pilomaterialy` 200. Заглушки каталога закрыты полностью. Откат: стек 16→`24a13da`. Source-of-truth compose актуализирован (`f876e70`). _Updated: 2026-08-16 (3) — 🟢 **[deploy-pilonuxt-catalog-img-fix] DONE.** Фикс прогера `24a13da` (origin/master, 1 файл `categories.json`): тайлы «Брус антисептированный» (мета «Брус, брусок, рейка» + «Антисептированные пиломатериалы») переведены с плейсхолдера `/images/2.webp` на imgproxy-фото `TGTqrE8…` (как у «Брус, брусок сухой антисептированный»). Build из монорепы, push напрямую, Portainer PUT стек 16 (`pullImage:true`, Env:0). Verify мимо LAN-DNS: `/catalog` 200, оба тайла `src=/imgproxy/TGTqrE8…`, заглушки нет; `/` 200; оставшиеся 3 плейсхолдера (обрезная 1.webp / строительная 2.webp / брус-брусок-рейка 3.webp) намеренно не тронуты (заметка прогера — заменят при отмашке владельца + эталонные URL); регресс: `/services` 200, `/services/building` 404, `/catalog/brus` 200. Откат: стек 16→`40806b1`. Source-of-truth compose актуализирован (`24a13da`). _Updated: 2026-08-16 (2) — 🟢 **[deploy-pilonuxt-services-404-fix] DONE.** Фикс прогера `40806b1` (origin/master): `services/[slug].vue` — `await useAsyncData` до рендера + setup-time `throw createError(404)` вместо lazy `usePage`+watchEffect (мягкий 200 подтверждён прогером локально). Build из монорепы, push напрямую, Portainer PUT стек 16 (`pullImage:true`, Env:0). Verify мимо LAN-DNS: `/services/building` → **404** (тело «Услуга не найдена»), `/services/nope` → 404, `/services/painting` → 200, `/` → 200 («каркасн» 0), `/services` → 200, регресс 8 живых услуг все 200. Follow-up на SEO не нужен. Откат: стек 16→`340c0e7`. Source-of-truth compose актуализирован (`40806b1`). _Updated: 2026-08-16 — 🟢 **[deploy-pilonuxt-frame-house-removal] DONE.** Запрос прогера pilorama98 (письмо в `.agents/inbox/2026-08-16T07-13-00Z-pilorama98.md`): передеплой стека 16 на `340c0e7` (монорепа; `25aaacf` — код: выпил «Строительство каркасных домов», баннер-фикс главной, h2-catalog v-html fix, services-404; `340c0e7` — вики). Build из монорепы (secret verdaccio_token, тег `340c0e7`), push напрямую (499 не случился), Portainer PUT стек 16 (`pullImage:true`, env запечён в compose — Env:0). Контейнер на `340c0e7` running. Smoke мимо LAN-DNS (`--resolve 89.253.255.94`): `/` 200 без «каркасн», баннер «Окрашивание древесины» один (alt «Новая услуга: окрашивание древесины»), h2-разделы каталога 8 видны; `/services` 200 без «каркасн», 8 карточек (без building); `/services/painting`+`/services/planing` 200 без упоминаний. ⚠️ **Finding прогеру:** `/services/building` рендерил 404-контент, но HTTP-статус **200** (watchEffect-бросок после фиксации Nitro-статуса, мягкий 404) — фикс пришёл следом (`40806b1`, задеплоен). Откат: стек 16→`8b7e8c4`. Source-of-truth `host-stacks/vds-kzntsv/pilonuxt.compose.yml` актуализирован._ _Updated: 2026-08-14 — 🟢 **[snolla-mailer-per-recipient-send] DONE (деплой+приёмка).** Тирож на mailer 0.9.0 (per-recipient loop): pilonuxt 8b7e8c4 + 7 env-сайтов web@0.44.0 (83513ef/0cd20fc/698d5f5/3f6f0c4/ccd620c/a649bcf/4aaa175), data единый 0.15.1. Попутный фикс: `mailSettings.from=noreply@snolla.com` в production.json env-сайтов (550 not-owned) → e-16513832@yandex.ru. Приёмка: pilorama98 #2498 (3 письма) + kupimknigi #516 (2 письма) — messageId, 0 ошибок; mailer 0.9.0 во всех 8 контейнерах. Спека: `.tasks/snolla-mailer-per-recipient-send.md`._ _Updated: 2026-08-14 — 🟢 **[snolla-smtp-send-monitor-vds] DONE** (по запросу vitya). Монитор SMTP-отправки snolla-сайтов задеплоен на VDS: `/root/snolla-smtp-monitor/monitor.py` (smtp-auth + weekly real-send + parity Portainer env 7 стеков) + cron 08:00 MSK; негатив-тест пройден (535 → ntfy-alert HTTP 200); parity зелёный после роллаута SMTP. Копия: `.admin/scripts/snolla-smtp-monitor/`. Попутно: msmtp на VDS (бэкап-отчёты) переведён на новые креды + From в run.sh (был мёртвый noreply@snolla.com)._ _Updated: 2026-08-13 — 🟢 **[stostayer-web-deploy-0-3-23] CLOSED.** Запрос их прогера (письмо в `.agents/inbox/2026-08-13T08-43-41Z-stostayer-new.md`): calculator-баннер про цены при покупке запчастей + фикс краша (snolla loadCity/loadSite) + стек-фикс легаси (vue/vuex/vue-router/mariadb явные deps, nmHoistingLimits). Образ `stostayer-web:0.3.23` (коммиты `e5f7bd6`+`7e51cbf`+`d49b4bb`) собран (нюанс: offline-build не прошёл — в `.yarn/cache` нет linux-бинарей esbuild/rollup, собрал с временным `VERDACCIO_TOKEN` ARG/ENV), запушен 1 попыткой (слои already-exists → бана нет), стек Portainer 16 передеплоен 0.3.22→0.3.23 (HTTP=200, env re-supply). Verify с хоста: Focus II → 200 + баннер «актуальны при приобретении запасных частей», регресс `/`+ремонтная → 200, Focus IV (exactPrices=0) → баннера нет + алерт «уточняйте у мастеров» (всё по письму). Контейнер Up, RestartCount=0, логи чистые. Откат: PUT на 0.3.22. Ранбук обновлён (прод-тег, build-нюансы, порт :9000 в Portainer API). Всё: `.tasks/stostayer-web-deploy-0-3-23.md` + `.wiki/concepts/stostayer-web-deploy-runbook.md`._ _Updated: 2026-08-10 — 🟡 **[kreknin-repair-md3-rebuild] ребилд идёт, бэкапы ВОЗВРАЩЕНЫ.** Утро: vitya на месте, кабели перетыкнуты (sdb WD-WX32D12L8HTE вернулся, SMART PASSED, все 3 HDD на 6 Gbps), md3 rebuild старт 07:57 (`mdadm --add /dev/md3 /dev/sdb3`), md0/md1 починены (системные разделы добавлены во все 4 диска — «зелёные» в DSM), win10 resolved (RuToken re-enum, кнопка «Игнорировать»). **~11:40 отключение электричества в деревне** → NAS лёг (роутер/WAN жив — на UPS). Возврат 16:20: md3 собрался деградированным `[_UU]`, **sdb3 сам не вернулся** (прогресс rebuild НЕ переживает power-loss — контрольной точки нет), повторён `mdadm --add /dev/md3 /dev/sdb3` → recovery с 0.0%, ETA ~4-5 дн (разгон 3→10-25МБ/с). md0/md1 все 4 диска `[UUUU]` (утр. ремонт пережил ребут), md2/VMM здоров. **Бэкапы возвращены 2026-08-10 18:00 по указанию vitya (ДО ребилда — ребилд фоновый):** cron раскомментирован (vds-kzntsv 05:00 + books-vds 06:00), ручные прогоны ПОДТВЕРЖДЕНЫ на kreknin (vds-kzntsv 2026-08-10 66G / books-vds 15G, latest→08-10, 7 снапшотов у обоих). Находка: books-vds не доезжал до kreknin с 08-05 (08-06..08-09 + 08-10 06:05 rsync падал — timed out/no route; другой триггер не найден); застрявший ES-снапшот `daily-2026-08-10` удалён. Осталось: дождаться ребилда md3 → `btrfs scrub /volume1` → monitor на ребилд активен. Всё: `.tasks/kreknin-repair-md3-rebuild.md` + `.wiki/entities/kreknin-synology.md`._ _Updated: 2026-08-04 — 🔵 **[coord-loader-admin-api-client] координатор.** Я (admin) назначен координатором таски pilorama98 `loader-migrate-to-admin-api-client` (перевод `apps/loader` с прямого DB на `@snolla/admin-api-client` от snolla). Письма-интро отправлены обоим (pilorama98 — report готовности, snolla — краткое описание клиента). Предпосылка S1: **ApiKeys DDL прогнана на обоих боевых SNOLLA** (vds `MoreThenCms` + stostayer `stostayer`) — таблица + индексы + FK, RC=0, verify зелёный. См. `coord-loader-admin-api-client.md`._ _Updated: 2026-08-03 (2) — 🟢 **[labtools.ru cylindrical] CLOSED.** Фикс core 0.26.5 (store-only content-page резолвер) НЕ чинил: labtools — catalog-модуль (store отсутствует), linked-item provider = legacy `LinkedCatalogProductsProvider`. Реализован полный диспетчер `viewModels/linkedItemResolver.js` (порт `ILinkedEntitiesProvider`): dispatch по provider-строке → catalog (CatalogsService.findProductById) / blog (findPostByGlobalId) / page (getPageById) / store (fallback). core 0.26.6 published (verdaccio), 263/263. labtools yarn.lock → 0.26.6 (d263e1c), стек 17 redeploy (env 8/8, pullImage), **LIVE GREEN**: cylindrical 0 empty href/src, 8 карточек гидратированы (round-xrf/vacuum-ir/…), остальные страницы 200. Таска snolla закрыта. Rollback = `0dc0b4e`._ _Updated: 2026-08-02 — ⚪ **[kreknin-repair-md3-rebuild] заведена.** Xpenology kreknin деградед после продувки компрессором 2026-07-31: sdb выпал (md3 `[_UU]`), кабели sda/sdc срыв. **Rescue полный DONE 2026-08-02** (USB 2TB `/mnt/rescue`, 1.1TB: netbackup/*.tar включая diskstation_1.hbk 430G + userdata 5 шар Алексея), массив за 2 суток чтения — 0 новых ошибок. sdd/VM-том восстановлен (md2, `/volume2` rw). **Ежедневные бэкапы DISABLED** (vds-kzntsv 05:00 + books-vds 06:00, cron закомментированы, `.bak.20260731`). Осталось: power-off → перетык SATA (sda/sdc свежие, sdb питание+data) → Repair md3 (реборн) → вернуть бэкапы. Всё: `.tasks/kreknin-repair-md3-rebuild.md` + `.wiki/entities/kreknin-synology.md`._ _Updated: 2026-07-31 (2) — 🟢 **variant-cache bucket fix.** maljarka portfolio фото 500 → root cause: v3 minio-split перевёл сайты на vds MinIO 2025, но `variant-cache` bucket не создали там (был только на старом minio.kzntsv.site/books-vds 2020). snolla sharp-pipeline (`variantCache.js` DEFAULT_NAMESPACE=`variant-cache`) → NoSuchBucket → 500 на ALL sharp gallery-images ВСЕХ 6 v3 сайтов с 2026-07-30 (тихо — v3-gate проверял theme CSS из `themes` bucket (themeFiles, без sharp), не gallery-image URLs). Fix: `mc mb vds/variant-cache` (пустой, кэш регенерируем). После: maljarka portfolio 34/34 → 200 image/webp, full-size 920x600 200, tandemmebel logs NoSuchBucket ушли. **minio-split Track A gap** — при endpoint-flip проверять ВСЕ runtime-buckets (`galleries`/`themes`/`assets`/`variant-cache`), и gate должен хитить gallery-image URL. Memory `variant-cache-bucket-missing-on-vds-2025`._ _Updated: 2026-07-31 — 🟢 **[maljarka-vds-restore] CLOSED.** `maljarka.tandemmebel.ru` восстановлен как 7-й сайт тиража snolla на VDS. Сайт был потерян 2026-07-21 при декоммишне RUVDS IIS (единственный публичный хост maljarka; в v3 тираж не входила, осталась на RUVDS). DNS перебросили на VDS, но `Host()`-правила + snolla-app с siteId `A2476738` не было → traefik 404. Аудит 21.07 «VDS=200» = false-positive с локального IIS воркстейшна. **Контент цел** в shared `MoreThenCms` DB (5 Pages, 4 StaticPages, тема Reversal `4881FC7F` уже в MinIO themes bucket). Восстановление = клон `victor/on.snolla.com` → `victor/maljarka.tandemmebel.ru` (snolla 0.43.2/aws-sdk v3), swap siteId `A2476738`+siteUrl, `layout.liquid` **byte-identical** рендеру локального .NET-admin (43730B, sha256 match, `{{ item.content }}` inline — content пуст), error-страницы Reversal-бренд. Build на VDS (`7f03d67`, digest df4e3642, regen yarn.lock под переименованный workspace), throwaway-staging :5081 gate GREEN (byte-parity `/`, 4 staticpages 200 sizes==DB, theme asset 200 103320B, unpublished 404 parity), Portainer стек **Id 23** (node create-stack, НЕ PS — кириллица), env 8/8 shared, mem_limit 512m, `Host(maljarka.tandemmebel.ru)`. DNS уже VDS → LE issued on first hit (CN=maljarka.tandemmebel.ru, YR1, до 2026-10-29). Live smoke GREEN: `/` 200 43730B byte-identical, title «Малярка от Тандеммебель», 4 staticpages 200, theme asset 200, robots/sitemap 200. **Тираж 7/7**: labtools(17)/emspb(18)/labtools-pro(19)/tandemmebel(20)/kupimknigi(21)/on-snolla(22)/maljarka(23). Runbook: `maljarka-vds-deploy-runbook`. Rollback = образ-тег в registry (RUVDS DECOMM, не DNS)._ _Updated: 2026-07-20 (2) — 🟢 **[snolla-local-admin-restore] CLOSED.** Локальный .NET-админ поднят: selective tar-copy `C:\sites\snolla\` ~100MB с RUVDS (исключил stale App_Data 8.76GB — assets/galleries/themes теперь в MinIO), Web.config уже → `mssql.kzntsv.site,1433` Catalog=MoreThenCms (user `snolla`) + MinIO S3 drop-in (ключи реальные, placeholder_count=0). Elevated setup `scripts/local-snolla-admin-restore/setup-local-snolla-admin.ps1` (ASCII-only, PS5.1 BOM-less-safe): AppPool `snolla` (.NET v4.0, AppPoolIdentity, recycle@200MB), IIS site `*:80` catch-all, ACL `IIS AppPool\snolla:(OI)(CI)(M)`, hosts-override `127.0.0.1 <6 aliases>.snolla.com`, FW block inbound 80. Smoke GREEN: `tandemmebel/labtools/labtoolspro/emspb/kupimknigi/on .snolla.com/admin/account/login` → 200, реальная MoreThenCms-логинформа (`