deploy(kupimknigi): staging стек 21 (новый) → 9608ff6 (snolla 0.42.0) — smoke GREEN, паритет prod

[kupimknigi-deploy-snolla-0-42-0] 🟢 done. Собран на VDS, Portainer-стек 21 создан
(env verbatim из стека 20), контейнер healthy. Staging-smoke с VDS: / 200==prod,
H1 идентичен, тема-ассеты 200, форма+canonical паритет. Cutover=operator-gated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-05 10:31:33 +03:00
parent 76f52661ca
commit 84f4852f7f
3 changed files with 78 additions and 7 deletions

View File

@@ -48,11 +48,11 @@ _Updated: 2026-05-26 — заведена `bookva-tenant-cutover-prep` ⚪ (7-st
_Updated: 2026-05-25 (`iis-migration-to-ruvds` 🟢 closed Phase 1 per user decision — 9/24 hostnames live на RUVDS, source IIS оставлен running. `migrate-elasticsearch-to-books-vds` 🟢 closed ранее сегодня. 16 IIS hostnames + LE renewal pipeline + decommission — descoped в Closure note, не отдельные tracker tasks.)_
## [kupimknigi-deploy-snolla-0-42-0] — VDS-staging образ kupimknigi.spb.ru на snolla@0.42.0 (одностраничник, финал тиража). Per-task: `kupimknigi-deploy-snolla-0-42-0.md`.
## 🟢 [kupimknigi-deploy-snolla-0-42-0] — VDS-staging образ kupimknigi.spb.ru на snolla@0.42.0 (одностраничник, финал тиража). Per-task: `kupimknigi-deploy-snolla-0-42-0.md`.
**Status:** ready — заведена workshop 2026-07-05 (код закрыт, re-review PASS, docker-валидация GREEN, build sha `9608ff6`)
**Where I stopped:** (not started)
**Next action:** build `9608ff6` на VDS → стек Portainer → staging-smoke `/` vs бой `kupimknigi.spb.ru`. Cutover=operator-gated. См. per-task.
**Status:** done — 2026-07-05. ✅ Собрал `registry.kzntsv.site/kupimknigi:9608ff6` (digest `ac7f846`, 583MB) на VDS из sha 9608ff6 (snolla 0.42.0/core 0.24.0/data 0.14.1), запушил. Создал **новый Portainer-стек Id 21 `kupimknigi`** (POST create/standalone, env verbatim 8/8 из стека 20 — тот же тенант) → контейнер **healthy** сразу, running==9608ff6. Staging-host kupimknigi.vds.kzntsv.site.
**Where I stopped:** GREEN. Staging-smoke с VDS пройден: `/`→200==prod; H1 «Скупка старых книг в Санкт-Петербурге…» идентичен prod; robots.txt 200 (healthcheck); тема-ассет `/themes/ef2c663c…/css/toolbox.css`→200 (MinIO); форма `action="/callback-order"` в HTML; callback-роуты паритет prod (`/callback-order/`→301 canonical, `/callback-order`→404 POST-only); байты 17717≈prod 17672. Форму не сабмитил (POST=реальное письмо клиенту) — роут зарегистрирован==prod, достаточно.
**Next action:** — (закрыто). Cutover=operator-gated отдельный шаг (kupimknigi DNS на RUVDS IIS 80.64.31.36, майская миграция; таргет/порядок разрулить с оператором). RUVDS=rollback, не тронут.
**Weight:** needs-claude · **Notify:** OpeItcLoc03/workshop
<!-- created-by: workshop / 2026-07-05 -->

View File

@@ -26,8 +26,20 @@ Live DNS flip **НЕ трогать** без отмашки оператора.
- **Notify:** OpeItcLoc03/workshop (оркестратор — «его сайт = workshop»)
- Deploy-source dev: `victor/kupimknigi.spb.ru`.
**Status:** ready — заведена workshop 2026-07-05 (код закрыт, re-review PASS, docker-валидация GREEN)
**Where I stopped:** (not started)
**Next action:** build `9608ff6` на VDS → стек → staging-smoke `/` vs бой.
**Status:** done — 2026-07-05 (admin). GREEN.
**Where I stopped:** закрыто, все гейты зелёные.
**Next action:** — Cutover=operator-gated отдельный шаг.
## Completed steps (2026-07-05, admin)
- [x] Пин верифицирован: sha `9608ff6` резолвит snolla 0.42.0 (package.json + yarn.lock), Dockerfile OK, порт 5000, healthcheck=robots.txt. production.json запечён (siteId E924A354/siteUrl kupimknigi.spb.ru/DB/imgproxy/minio). Консюмер-пин на месте (не было tandemmebel-блокера).
- [x] snolla 0.42.0 в verdaccio подтверждён (ранее в сессии).
- [x] Build на VDS `registry.kzntsv.site/kupimknigi:9608ff6` (digest `ac7f846`, 583MB, BUILD_EXIT=0), push OK.
- [x] Создал НОВЫЙ Portainer-стек **Id 21 `kupimknigi`** (POST create/standalone/string, endpointId=1, env verbatim 8/8 из стека 20 — тот же snolla-тенант). Контейнер healthy сразу, running==9608ff6.
- [x] Staging-smoke с VDS GREEN: `/`→200==prod; H1 «Скупка старых книг в Санкт-Петербурге…» идентичен prod; robots.txt 200; тема-ассет toolbox.css→200 (MinIO); форма action="/callback-order" в HTML; callback-роуты паритет prod (`/callback-order/`→301, `/callback-order`→404 POST-only); байты 17717≈17672.
- [x] compose source-of-truth: `host-stacks/vds-kzntsv/kupimknigi.compose.yml` (staging-host, боевой Host только в cutover-комменте).
- [x] Таска 🟢 done, notify workshop.
## Decisions log
- 2026-07-05: **CLOSED 🟢.** Тривиальный одностраничник, деплой чистый, без блокеров. Форму не сабмитил (POST=реальное письмо клиенту) — роут зарегистрирован==prod + отрендерен, достаточно для staging. Cutover остаётся operator-gated (kupimknigi DNS на RUVDS IIS, майская миграция — таргет/порядок с оператором). Follow-up (общий тиражу): Dockerfile печёт VERDACCIO_TOKEN в ARG/ENV → build-secret (парный фикс с dev, отложен).
<!-- created-by: workshop / 2026-07-05 / dev-source victor/kupimknigi.spb.ru HEAD 9608ff6 -->

View File

@@ -0,0 +1,59 @@
# kupimknigi — прод-фронт kupimknigi.spb.ru (snolla-приложение, server-side Liquid, node) на vds-kzntsv (89.253.255.94).
#
# STAGING-FIRST. Source-of-truth этого compose — admin-репо; применяется через Portainer
# API/UI (VDS-rule: стеки через Portainer, не ssh+compose).
#
# Модель: монолит @snollajs/snolla (0.42.0) / core (0.24.0) / data (0.14.1) — читает БД-контент
# MoreThenCms (mssql.kzntsv.site) + server-side Liquid render. Ассеты из MinIO (minio.kzntsv.site)
# через imgproxy (imgproxy.kzntsv.site). ПРОСТОЙ ОДНОСТРАНИЧНИК: Pages=1 (`/`), Forms=1 (`/callback-order` POST).
# Каталога/стора/блога/фида/редиректов НЕТ. node-config: NODE_ENV=production → production.json + ENV-override.
# siteId=E924A354-0377-4E1E-80C6-2EB0194AA55F, siteUrl=https://kupimknigi.spb.ru (БЕЗ www — www мёртв) — в production.json (запечён).
#
# Образ собирается АДМИНОМ на VDS из victor/kupimknigi.spb.ru/deploy/Dockerfile (build-arg VERDACCIO_TOKEN,
# @snollajs/* из verdaccio.kzntsv.site). Тег = git-sha монорепы kupimknigi.spb.ru (9608ff6).
#
# Домен: STAGING — kupimknigi.vds.kzntsv.site (под wildcard *.vds.kzntsv.site, cert LE HTTP-01 авто).
# Cutover live kupimknigi.spb.ru — ОТДЕЛЬНЫЙ gated шаг: бой сейчас на RUVDS IIS (80.64.31.36, майская iis-migration).
# DNS/порядок cutover разрешает ОПЕРАТОР отдельно. План отката = revert DNS → RUVDS. RUVDS не тронут.
# ⚠️ Боевой Host-rule добавлять ТОЛЬКО ПОСЛЕ flip DNS (иначе LE HTTP-01 упадёт на RUVDS → rate-limit).
#
# Runtime egress (наружу из proxy-сети): mssql.kzntsv.site:1433, minio.kzntsv.site:443,
# imgproxy.kzntsv.site:443, smtp.yandex.ru:465 (форма callback-order).
#
# Секреты — env на VDS (Portainer stack env), НЕ в образ, НЕ в git. Значения ${...} инжектит Portainer
# из stack-переменных (те же 8 общего snolla-тенанта, verbatim из labtools/tandemmebel). Контракт
# (custom-environment-variables.json): DB_USER DB_PASSWORD IMGPROXY_KEY IMGPROXY_SALT
# S3_ACCESS_KEY_ID S3_SECRET_ACCESS_KEY SMTP_USER SMTP_PASSWORD
services:
kupimknigi:
container_name: kupimknigi
image: registry.kzntsv.site/kupimknigi:9608ff6 # git-sha victor/kupimknigi.spb.ru (snolla 0.42.0 / core 0.24.0 / data 0.14.1)
restart: unless-stopped
environment:
NODE_ENV: production
TZ: Europe/Moscow
# PORT не переопределяем — образ дефолтит 5000 (EXPOSE 5000, healthcheck на robots.txt)
# --- runtime-секреты (значения из Portainer stack env; НЕ хранить тут) ---
DB_USER: ${DB_USER}
DB_PASSWORD: ${DB_PASSWORD}
IMGPROXY_KEY: ${IMGPROXY_KEY}
IMGPROXY_SALT: ${IMGPROXY_SALT}
S3_ACCESS_KEY_ID: ${S3_ACCESS_KEY_ID}
S3_SECRET_ACCESS_KEY: ${S3_SECRET_ACCESS_KEY}
SMTP_USER: ${SMTP_USER}
SMTP_PASSWORD: ${SMTP_PASSWORD}
networks:
- proxy
labels:
traefik.enable: "true"
traefik.http.routers.kupimknigi.entrypoints: websecure
# STAGING-RULE. Cutover: после flip DNS сменить на Host(`kupimknigi.spb.ru`) (БЕЗ www — мёртв)
# и убрать staging-хост. RUVDS IIS 80.64.31.36 — rollback, не тронут.
traefik.http.routers.kupimknigi.rule: Host(`kupimknigi.vds.kzntsv.site`)
traefik.http.routers.kupimknigi.tls.certresolver: letsEncrypt
traefik.http.services.kupimknigi.loadbalancer.server.port: "5000"
networks:
proxy:
external: true