Clone-adapted from .wiki/concepts/portainer-stack-management-vds.md § Migration script.
Diffs from VDS-infra version:
- PORTAINER_URL = portainer.kzntsv.site
- Auth via X-API-Key (PAT works, no JWT fallback needed)
- DIR prefix /usr/docker/<stack> (not /opt/stacks/<stack>)
- Down step via `docker rm -f` by compose-project label
(bypasses docker-compose v1 ContainerConfig bug entirely; no compose binary on path required)
- Refuses traefik/portainer migration (management plane)
Idempotent: delete-then-create against existing stack by name on endpoint 1. Re-runs are safe.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Acceptance:
- 3 scripts (VDS bash + RUVDS ps1 + windows-host ps1) синхронизированы под
unified push + email format (commit 73ad6dd0).
- VDS deployed + smoke ntfy+email ✓.
- RUVDS deployed + smoke ntfy+email ✓.
- windows-host smoke + deploy — closed-by-inspection per user direction
«все ок»: parser-check достаточно, deploy.ps1 готов для self-deploy
elevated PS у user'а. Без deploy сегодня ночью 03:00 MSK прогон в
STAROM format'е (cosmetic, не functional regression).
Также атомарный revert (`.bak-pre-unify` на каждом хосте) задокументирован
в .tasks/unify-backup-notifications.md § Closed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Stale prompt-file от попытки iis-on-host-migration 2026-05-19 — таска
уже 🟢 закрыта, файл устарел. Также содержит 4 plaintext password'а
(MSSQL SA conn-strings + snolla/stayer DB users + VM admin) — leaked
в git history с 2026-05-21 (`c55cb119`). User accept risk без rotation /
history-rewrite (private gitea, ограниченный pull-access).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3 host-pipelines (VDS bash, RUVDS+windows-host ps1) had drifted formats:
ntfy title `VDS backup OK $D` vs `RUVDS backup OK ($D)`, tags
`white_check_mark` vs `green_circle`, email subject `[VDS] backup OK` vs
`RUVDS backup -- SUCCESS`. Phone-side фильтрация и desktop reading
ломались за счёт inconsistency.
Unified to:
- ntfy push: title `<HOST> backup OK <date>`, body
`<duration_human>, size=<>, snapshots=<>, dest=kreknin:<>`,
tags `green_circle` (OK) / `red_circle` (FAILED).
- email: subject `[<HOST>] backup <STATUS> <date>` (STATUS=OK|FAILED),
body — structured Date/Duration/Size/Snapshots/Source/Dest/Components/Log.
Failure body extends with `Tail (last 40 lines)`.
Also imports VDS `run.sh` into repo as `scripts/vds-backup-rsync-kreknin/`
— closes drift из общего `scripts/<slug>/` pattern (RUVDS+windows-host
уже жили там; VDS жил только на /opt/stacks/backup/scripts/).
Deploy status:
- VDS: deployed via scp + sudo install, sha256=27b09ca272bb, smoke ntfy+email ✓
- RUVDS: deployed via scp + Move-Item, sha256=f3bb57a86af5, smoke ntfy+email ✓
- windows-host: deploy.ps1 + smoke-notify.ps1 готовы в scripts/, **pending
elevated PS у user'а** (ACL=SYSTEM+Administrators, не пишется без UAC).
Spec + decisions + completed: .tasks/unify-backup-notifications.md.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pulls in `session handoff: read on start, write on end` so the
session-handoff skill (installed via claude-skills) activates in this
project. Inserted between `pull remote before work` and
`follow project discipline` — session-lifecycle clustering, mirrors
claude-skills CLAUDE.md and project-bootstrap's canonical template.
Refs OpeItcLoc03/claude-skills [session-handoff-existing-projects-upgrade].
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
STATUS.md cleanup:
- 25 🟢 closed task blocks moved to new .tasks/ARCHIVE.md (append-only
history; per-task <slug>.md остаются in-place в .tasks/ root).
- STATUS.md now 6 KB instead of 78 KB — board показывает только active
(🔴/🟡), ready (⚪), blocked (🔵).
- Header refreshed с current scope summary.
Re-scope: cms-stopgap-backup-daily → windows-host-fallback-backup-daily
- Original spec: "временный stop-gap до migration MSSQL/MinIO на VDS"
- Reality (2026-05-24): MSSQL+sites уже мигрированы и прикрыты backup'ами
(vds-backup-rsync-kreknin 🟢 + ruvds-backup-daily-kreknin 🟢)
- New purpose (user-decision): windows-host остаётся warm-standby для DR
(failover при потере VDS/RUVDS), backup pipeline нужен чтобы failover не
возвращал stale state.
- Also: CMS image-rendering хардкодит imgproxy.kzntsv.site через DLL →
windows-host MinIO/imgproxy — active dependency даже после primary
cutover, не "standby". Backup критично для image-pipeline DR.
- Tool: rclone same pattern как ruvds-backup-daily-kreknin 🟢
iis-migration-to-ruvds scope narrow:
- tandemmebel.ru + www.tandemmebel.ru EXCLUDED из cutover (user-decision)
- Остаются на windows-IIS:8089 неопределённо
- Cert на RUVDS уже импортирован, HTTPS binding existing — idle, traffic
не пойдёт пока DNS не flipped. Source IIS snolla site нельзя
decommission'ить полностью пока tandemmebel на нём же (catch-all).
- Scope теперь 24 hostnames для migration (вместо 26).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add dual-channel notifications — ntfy (already there) + email via
Send-MailMessage / Yandex SMTP, mirroring VDS msmtp pipeline.
Email: noreply@snolla.com -> vitya.kuznetsov@gmail.com.
Verified delivered (DKIM pass, SPF pass) via run #2 + manual smoke.
Settings sourced from C:\sites\snolla\Web.config <mailSettings> (Yandex
SMTP), cross-checked against pass-store snolla-smtp/full-env. Same
creds, same account as VDS backup msmtp uses.
SMTP port: 587 STARTTLS, NOT 465 implicit-TLS:
.NET SmtpClient / Send-MailMessage support only STARTTLS. Yandex
accepts both; we use 587 for native PS tooling. VDS msmtp uses 465
implicit-TLS — both work, different tools.
Size in email: switched from `rclone size --json | ConvertFrom-Json`
(parses fail when rclone NOTICE stderr leaks into stdout) to local
Get-ChildItem on C:\sites\snolla. Instant, no JSON dance.
setup.ps1: ned params for SMTP creds + OPS_NOTIFY_EMAIL; config.env
template extended.
README.md: notifications section split into ntfy + email subsections,
new SMTP-port + size-calc decisions in Decisions log.
Run #2 (12:30:03) and run #3 (12:33) both produced email delivery
receipts in user inbox.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Создаю задачу пока [iis-migration-to-ruvds] в soak window. Закрывает
Open-question "Backup strategy для RUVDS IIS" из migration task.
Pattern параллель [vds-backup-rsync-kreknin] 🟢 — daily backup → kreknin
synology, 7 daily snapshots retention, ntfy на vds-backup topic.
Differences vs VDS:
- Win Server 2025 Core → rclone single-binary, не rsync (no cygwin/WSL)
- Task Scheduler SYSTEM-account, не cron-root
- 04:30 MSK (за 30 мин до VDS backup чтобы не пересекать uplink)
- Backup scope: C:\sites\snolla + applicationHost.config + IIS native
Backup-WebConfiguration + cert store PFX export + sshd config
Decisions log в task file: tool=rclone (rejected restic encrypted-dedupe
как overkill для transitional setup, robocopy-over-SMB fragile);
SYSTEM-principal mirrors VDS root-cron pattern; PFX export pass=temp
'pfximport' (TODO: pass-equivalent на Windows когда найдём).
Open questions для решения user'а: when to start (recommend сейчас, не
ждать full cutover), kreknin SSH ACL add pubkey to authorized_keys
(требует user action).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Session 2026-05-23 evening → 2026-05-24: full snolla site migration
windows-recovery-host → RUVDS Win Server 2025 Core, partial DNS cutover для
1 prod hostname (kupimknigi.spb.ru), оставшиеся 24 hostnames pending.
What's live on RUVDS:
- snolla IIS site catch-all *:80: + 25 HTTPS SNI bindings (1 per hostname,
LE certs от 2026-04-23 / valid до 2026-07-22)
- 8.66 GB / 44725 files transferred via scp после ISP-block discovery
- ApplicationPoolIdentity + ACL grant verified
- HTTP/2 auto-negotiated, MSSQL/imgproxy/MinIO connectivity OK from RUVDS
Findings (Decisions log в task file для деталей):
1. Outbound 445 блокирует home ISP (не RUVDS FW) — `windows-server-2025-core-bootstrap.md`
SMB-section deprecated, SSH/scp = canonical transfer-метод.
2. Home network HTTP-middlebox mangles Host header в outbound external HTTP —
тест с source даёт garbled response; тест с VDS (третья сеть) даёт корректный.
3. traefik acme.json → IIS PFX recipe: extract base64 cert+key per cert →
openssl pkcs12 -export → Import-PfxCertificate + AddSslCertificate by
thumbprint with SslFlags=1 (SNI). Reusable, потенциально новый concept.
4. IIS 10 на Win Server 2025 говорит HTTP/2 by default через TLS.
5. 4 hostnames (maljarka.tandemmebel.ru + 3 rimiz) → 502/404 на RUVDS;
на source IIS:8089 возвращают 200 default-page. Pre-existing CMS-tenant
config gap, не migration defect.
Scripts added:
- scripts/iis-migration-to-ruvds/01-ruvds-bootstrap.ps1 (idempotent)
- scripts/iis-migration-to-ruvds/02-source-transfer.ps1 (не использовался —
SMB не работает; оставлен как reference)
- scripts/iis-migration-to-ruvds/README.md
Cleanup done:
- Plaintext PFX/PEM keys в C:\Users\vitya\iis-backup-pre-ruvds\certs\ удалены
(PFX import на RUVDS уже сделан, source-of-truth = traefik acme.json).
- `.secrets/` уже удалён ранее в этой session (см. предыдущий commit).
Source state: IIS:8089 + traefik routes ALIVE — rollback ready. Decommission
после 1-week soak с RUVDS как live prod.
Не push'нуто — ждёт user grant per project-discipline Rule 4.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Temp admin (2026-05-23 09:37-18:08) начал импл iis-migration-to-ruvds,
не закончил bootstrap, упал на UNC robocopy (exit 16) и dropped tree dirty.
Session recovery:
- secrets leak fix: `.secrets/ruvds-iis.env` → `pass show ruvds-iis/full-env`
(etap-2 discipline restored). `.secrets/` + `*.env` + `*-log.txt` + `*-size.txt`
added to `.gitignore` чтобы не повторилось.
- root cause зафиксирован: TCP/445 closed по дефолту на fresh Win Server 2025
Core + SMB share не создан → UNC robocopy не работает без RUVDS bootstrap.
- new concept `windows-server-2025-core-bootstrap.md` — default-blockers
table + transfer-методов матрица (RDP-redirect / SMB / WinRM / SFTP) +
bootstrap-чеклист 12 шагов. Recommendation = SMB inbound с source-IP
whitelist.
- task ⚪ → 🟡 paused с concrete next-step (capacity audit, transfer-method
confirm, RUVDS bootstrap, backup source, recreate IIS sites + conn-string
swap, pilot kupimknigi + DNS swap).
- Open question raised: source 11 sites сумма vs RUVDS 30 GB HDD — capacity
blocker possible (snolla одна 8.66 GB).
Не push'нуто — ждёт user grant per project-discipline Rule 4.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
User selected RUVDS (Windows Server 2025 Core, 2GB RAM, 30GB HDD) outside research process.
Vendor decision made, migration task created as ready.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
User: «у меня видны задачи всего из 4 проектов, нет .common, stostayer.new и пр.»
Quick ops-action: ручное расширение board_viewer_repos в
/opt/stacks/board-viewer/auth.toml до ~18 репо (по памяти Gitea owner
namespace list). Заодно fix опечатки: OpeItcLoc03/books → victor/books;
выкинуть OpeItcLoc03/projects-meta-mcp (это субдир .common/lib/).
Restart build-контейнера → next-tick 5 мин подтянет всё → user видит
workshop + common + stostayer.new + остальные.
Long-term (auto-discovery через org-list) — отдельная code-таска
board-viewer/[board-viewer-whitelist-auto-discovery], round2 candidate.
Эта quick-win не блокируется ничем, ship'ается параллельно.
User clarification: «у все должно быть общее представление, где что живёт,
а у админа — полное представление, на чём всё едет».
Расширение scope существующей таски (создана несколькими минутами ранее
с single-page подходом):
- Deliverable A — light в projects-wiki/concepts/infrastructure-inventory.md
(audience: все агенты, разрабы, босс). Канонические hostnames + IP-map +
anti-aliases. Mental map для design-conversations.
- Deliverable B — heavy в .admin/.wiki/concepts/infrastructure-stack.md
(audience: только админ). Per-stack: версии, internal IPs, volumes,
depends-on graph, backup paths, DR runbook pointers. На чём всё едет.
Probing-фаза общая, потом split по level of detail. A и B cross-references.
Триггер — incident 2026-05-22 в .workshop-сессии: агент ляпнул
gitea.kzntsv.site (canonical = git.kzntsv.site), плюс перепутал
client-IP в traefik access-логах с destination-IP, и построил
неверный root-cause для board-viewer 404.
User: "никакого gitea.kzntsv.site нет, есть только git.kzntsv.site,
нужна инвентаризация чтобы и боссы и агенты и разрабы знали железо".
Таска: единая страница в projects-wiki/concepts/infrastructure-inventory.md
с canonical hostnames, IP-картой, anti-aliases, pointers в bootstrap-concept'ы
каждой машины. Pointer из .admin/.wiki/CLAUDE.md.
Ops-handoff из ~/projects/board-viewer/.tasks/[board-viewer-cron-deploy]:
dev-проект сдал code-complete (артефакты deploy/ + smoke против real Gitea),
оставшиеся pending — DNS / build+push / VDS bootstrap / smoke — это ops-сторона.
Per новое правило workshop CLAUDE.md §5 — таски с ops acceptance criteria
(DNS, docker stack, traefik, systemd, etc.) живут в .admin, не в app-проекте.
User confirmed imgproxy.kzntsv.site занят другим сервисом на другом сервере
(не наш scope). VDS imgproxy уже на imgproxy.vds.kzntsv.site (live).
CMS audit 2026-05-22 не нашёл refs на imgproxy/kzntsv/minio в:
- snolla source code (recursive grep)
- Admin/ templates
- bin/MoreThenCms.Modules.Imgproxy.dll strings (только namespace literal)
- MoreThenCms DB SiteSettings + ModuleProperties
- Public HTML rendering (всё relative /images/ + /themes/)
DLL deployed но не wired в active flow — vestigial или invoked через
Azure storage SDK (AccountName=snolla;AccountKey=... connection string
в snolla/Web.config — Azure-compat доступ к MinIO с неустановленным
endpoint). Identification реального consumer'а — отдельная audit-задача
перед source decommission.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>