diff --git a/.tasks/STATUS.md b/.tasks/STATUS.md index ce1a818..e0d685d 100644 --- a/.tasks/STATUS.md +++ b/.tasks/STATUS.md @@ -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 diff --git a/.tasks/kupimknigi-deploy-snolla-0-42-0.md b/.tasks/kupimknigi-deploy-snolla-0-42-0.md index ca39aeb..438f897 100644 --- a/.tasks/kupimknigi-deploy-snolla-0-42-0.md +++ b/.tasks/kupimknigi-deploy-snolla-0-42-0.md @@ -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, отложен). diff --git a/host-stacks/vds-kzntsv/kupimknigi.compose.yml b/host-stacks/vds-kzntsv/kupimknigi.compose.yml new file mode 100644 index 0000000..9115599 --- /dev/null +++ b/host-stacks/vds-kzntsv/kupimknigi.compose.yml @@ -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