Deploy phase done: oCIS 7.1.0 в /opt/stacks/owncloud/ через traefik labels на owncloud.kzntsv.site (LE cert valid), user 'vitya' создан через LibreGraph API, WebDAV `/dav/files/vitya/` PROPFIND 200 OK. Decisions in close-note: oCIS vs Seafile/Nextcloud chosen for drop-in decomposedfs import + lightweight Go binary. user:1001:1001 override after mount perms fail (host vitya UID 1001 ≠ image ocis-user UID 1000). PROXY_ENABLE_BASIC_AUTH=true для WebDAV/LibreGraph admin API. Backup integration: /opt/stacks/owncloud добавлен в rsync sources в /opt/stacks/backup/scripts/run.sh (vds-backup-rsync-kreknin scope expanded). Status 🟡 — pending user-side rclone copy 24.7GB → WebDAV (full copy лежит на другом PC, не на этом). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
64 KiB
Admin Task Board
Updated: 2026-05-21 (owncloud-vds-deploy 🟡 — oCIS up, user vitya created, WebDAV verified; 24.7GB import pending user-side rclone)
🟡 [owncloud-vds-deploy] — oCIS 7.1.0 на vds-kzntsv replace мёртвый ownCloud с Synology; 24.7GB import pending user-side rclone
oCIS deploy завершён, container up, traefik routes 200 OK через LE-cert, user vitya создан, WebDAV verified. Backup integration done — /opt/stacks/owncloud в rsync sources vds-backup-rsync-kreknin. Detail в owncloud-vds-deploy.md.
Status: paused
Where I stopped: infrastructure complete; waiting on user-side rclone copy 24.7GB → WebDAV endpoint. Full copy лежит на другом PC (local C:\Users\vitya\ownCloud — partial 1.3GB не та копия). Compose в /opt/stacks/owncloud/ (data+config dirs, .env chmod 600 с admin-password). Passwords: pass show owncloud/admin-password + pass show owncloud/user-vitya (pushed). HTTPS endpoint https://owncloud.kzntsv.site live.
Next action: user запускает rclone на PC где живёт 24.7GB:
rclone copy "<src>" :webdav: \
--webdav-url https://owncloud.kzntsv.site/dav/files/vitya \
--webdav-vendor owncloud --webdav-user vitya \
--webdav-pass $(rclone obscure "$(pass show owncloud/user-vitya)") \
--progress --transfers 4 --tpslimit 8 \
--retries 5 --low-level-retries 10 --stats 30s
Progress: ssh vitya@89.253.255.94 'du -sh /opt/stacks/owncloud/data/spaces/'. Done — 🟢 после size match + spot-check файлов через web UI.
Branch: master
🟢 [admin-infra-project-pointers] — Bootstrap-pointers для design admin-infra-project. Pre-fills target's .wiki/CLAUDE.md Domain conventions ссылками на спецификацию. Дизайн не лежит в этом репо — только pointer-stub. Без этой таски следующий агент попадёт в дыру: where_stopped one-liner + пустой Domain conventions stub = угадывание порогов / pipeline-этапов вместо чтения готовых решений.
Кто делает: любой следующий агент в этом проекте. Это первая по приоритету таска промоушена — все остальные импл-таски ссылаются на pointers через .wiki/CLAUDE.md.
Status: done
Closed: 2026-05-21 — .wiki/CLAUDE.md Domain conventions заполнен design-context pointer-блоком (3 sources: concepts/admin-infra-project.md, archive ~/projects/.workshop/.archive/2026-05-21-admin-infra-project.md, local overview.md). Unblocks migration chain.
Where I stopped: done
Next action: В .wiki/CLAUDE.md секции "Domain conventions" вставить блок (или заменить дефолтный setup-wiki stub):
Mandatory: read design context before implementation
Before picking up any task in .tasks/, load the full design context. It does not live in this repo as a standalone source — only pointers do. Sources, in order:
- Local design (canonical):
.wiki/concepts/admin-infra-project.md— ingested via promote 2026-05-21. Identity, scope, content inventory, migration recipe (subtree-split + read-tree merge for populated prefixes), initial agenda. - Brainstorm process trace (rationale):
~/projects/.workshop/.archive/2026-05-21-admin-infra-project.md. Why each decision was made (recommend vs menu trade-offs), what was rejected (filter-repo vs subtree-split, "admin-only" skills, splitting roadmap from ops), anti-patterns flagged during brainstorm. - Local
overview.md— thin summary, quick orientation only — never the source of truth.
Do not invent migration recipes, file lists, taxonomies, or scope decisions from task where_stopped lines alone — those are pointers, not specifications. The concept doc and archive contain the rationale.
Закоммитить: wiki(claude): add design-context pointers for admin-infra-project.
Branch: n/a
🟢 [morecms-subtree-split] — Шаг 2 миграции: в ~/projects/MoreThenCms создать 4 subtree-split ветки, каждая хранит per-file history своего dir'а. Эти ветки потом импортируются в admin (см. admin-subtree-import-and-cleanup).
См. .wiki/concepts/admin-infra-project.md §Migration mechanics шаг 2 для полного контекста.
Status: done
Closed: 2026-05-21 — 4 split branches созданы в ~/projects/MoreThenCms (split-wiki-entities @24661c10, split-wiki-sources @a5e96432, split-wiki-concepts @c727aaa1, split-tasks @cbdc2b39). Acceptance: per-file history preserved (verified via subsequent subtree-add in admin). Не push'ились — служебные.
Where I stopped: (not started)
Next action: ```powershell
cd ~/projects/MoreThenCms
git subtree split --prefix=.wiki/entities -b split-wiki-entities
git subtree split --prefix=.wiki/sources -b split-wiki-sources
git subtree split --prefix=.wiki/concepts -b split-wiki-concepts
git subtree split --prefix=.tasks -b split-tasks
Acceptance: `git branch | grep split-` показывает 4 ветки. Каждая `git log split-<x>` содержит коммиты только относящиеся к соответствующему dir'у. **Не push'ить** эти ветки — они служебные, нужны только для local subtree-add в admin.
Done — пометить 🟢 + переходить к `admin-subtree-import-and-cleanup`.
**Branch:** n/a
<!-- created-by: OpeItcLoc03@DESKTOP-NSEF0UK / from: OpeItcLoc03/workshop / 2026-05-21T10:22:50.307Z -->
---
## 🟢 [admin-subtree-import-and-cleanup] — Шаги 3-7 миграции: импорт 4 split-веток из MoreThenCms в admin (clean prefixes через `git subtree add`, populated prefixes — temp-prefix dance с `git subtree add` + `git mv` для history-preservation через merge-commit + rename; read-tree вариант spec'a отвергнут — не сохраняет parent-link к morecms history → `git log --follow` не доходит до morecms-era коммитов), cleanup CMS-следов из mixed splits, STATUS.md merge, index.md regen, push на Gitea.
Объединено в одну таску потому что: тот же agent, та же session, sequential steps без natural review-point между ними. См. `.wiki/concepts/admin-infra-project.md` §Migration mechanics шаги 3-7.
**Status:** done
**Closed:** 2026-05-21 — все 5 шагов отработаны (3a clean prefixes subtree-add для 6 entities + 3 sources; 3b mixed temp-prefix dance для 18 concepts + 8 tasks files с git mv → renames preserve history через merge-commit; 4 cleanup 10 CMS files + 1 stale bootstrap-manifest.md; 5 STATUS.md merge — 7 admin done blocks imported, 4 CMS excluded; 6 index.md regen — 6 entities, 18 concepts, 3 sources; 7 push). **Finding для verify-migration:** `git log --follow .wiki/concepts/<slug>.md` показывает только rename-merge commit, не bridges в morecms-era history (git --follow limitation, не reliably crosses subtree-merge graft даже при rename-detection). Alternative для full history: `git log --all -- <bare-filename>` walks merge graph и находит morecms-era commits. Acceptance criterion 5 verify-migration требует уточнения в close-note этой таски.
**Where I stopped:** (not started)
**Next action:** **3a. Clean prefixes:**
```powershell
cd ~/projects/.admin
git remote add morecms ~/projects/MoreThenCms
git fetch morecms
git rm .wiki/entities/.gitkeep .wiki/sources/.gitkeep
git commit -m "prep: clear gitkeep before subtree import"
git subtree add --prefix=.wiki/entities morecms/split-wiki-entities
git subtree add --prefix=.wiki/sources morecms/split-wiki-sources
3b. Mixed prefixes (.wiki/concepts/ and .tasks/ already have content):
Preferred — git read-tree merge:
git rm .wiki/concepts/.gitkeep
git commit -m "prep: clear concepts gitkeep before import"
git fetch morecms split-wiki-concepts
git read-tree --prefix=.wiki/concepts/ -u morecms/split-wiki-concepts
git commit -m "import: .wiki/concepts/ from MoreThenCms via subtree-split (history preserved via read-tree)"
git fetch morecms split-tasks
git read-tree --prefix=.tasks-imported/ -u morecms/split-tasks
git commit -m "import: .tasks/ from MoreThenCms via subtree-split (staged at .tasks-imported/)"
# Затем merge content with admin's existing STATUS.md (см. шаг 5).
Альтернатива при конфликтах — temp-prefix dance (.tmp-concepts/, git mv, git rm -r .tmp-concepts).
4. Cleanup CMS-следов:
git rm .wiki/concepts/cms-admin-assets-root-folder-seed.md `
.wiki/concepts/cms-config-rewrite-pattern.md `
.wiki/concepts/cms-maljarka-https-mode-crash.md `
.wiki/concepts/cms-server-port-leak-fix.md `
.wiki/concepts/webconfig-password-xml-escape.md `
.tasks-imported/cms-admin-assets-root-folders-seed.md `
.tasks-imported/cms-admin-assets-root-folders-seed.inserted-rows.txt `
.tasks-imported/cms-maljarka-https-mode-bug-fix.md `
.tasks-imported/cms-port-leak-fix.md `
.tasks-imported/traefik-maljarka-502-bug.md
git commit -m "cleanup: drop CMS files imported via subtree (they stay in MoreThenCms)"
5. STATUS.md merge: скопировать non-CMS таски из .tasks-imported/STATUS.md в admin/.tasks/STATUS.md (сохраняя 🟢 done статусы); удалить .tasks-imported/; rename per-task files в .tasks/. Commit tasks: merge imported MoreThenCms task history with admin live agenda.
6. index.md regen: обновить .wiki/index.md чтобы catalog отражал импортированные entities/concepts/sources. Commit wiki(index): refresh catalog after subtree import.
7. Push: git push origin master.
Acceptance:
git log --follow .wiki/concepts/wd40efax-smr-cascade.mdпоказывает MoreThenCms-era коммиты (history preserved)ls .wiki/entities/содержит все 6 файловls .wiki/concepts/содержит 18 admin-domain + admin-infra-project (новый)cat .tasks/STATUS.mdсодержит и live agenda (pointers + impl + secrets + roadmap), и imported 🟢 done items- Gitea web shows updated tree
Done — 🟢; unblock morecms-cleanup-and-breadcrumb + resilience-roadmap-design.
Branch: master
🟢 [morecms-cleanup-and-breadcrumb] — Шаги 8-10 миграции: в ~/projects/MoreThenCms удалить мигрированные файлы (6 entities + 17 concepts + 3 sources + 7 tasks), обновить STATUS.md/index.md, добавить .wiki/concepts/migrated-infra-to-admin.md breadcrumb со списком «что куда уехало», push на Gitea.
Closed: 2026-05-21 — все 3 шага отработаны (8 cleanup commit 1c2b8738: 6 entities + 17 admin concepts + 3 sources + 7 admin tasks + NEXT-SESSION-PROMPT.md removed, STATUS.md trimmed to 4 CMS blocks, index.md catalog regenerated; 9 breadcrumb commit 7c818cef: migrated-infra-to-admin.md created с table-mapping всех 31 файла + "what stays here" section + linked from STATUS.md header & index.md; 10 push: оба коммита pushed на git.kzntsv.site/OpeItcLoc03/MoreThenCms).
См. .wiki/concepts/admin-infra-project.md §Migration mechanics шаги 8-10 + полный шаблон breadcrumb'а в §9.
Очерёдность: ТОЛЬКО после успешного push'а admin'а с импортированным контентом (admin-subtree-import-and-cleanup 🟢). Иначе риск удалить из MoreThenCms то что ещё не зафиксировано в admin.
Status: ready Where I stopped: (not started) Next action: 8. Cleanup commit (drop migrated):
cd ~/projects/MoreThenCms
git rm .wiki/entities/* .wiki/sources/* `
.wiki/concepts/wd40efax-smr-cascade.md `
.wiki/concepts/hyper-backup-structure-and-recovery.md `
.wiki/concepts/vbox-windows-stability-tuning.md `
.wiki/concepts/mssql-container-data-restore.md `
.wiki/concepts/traefik-on-windows-docker-desktop.md `
.wiki/concepts/traefik-tcp-passthrough-vs-starttls.md `
.wiki/concepts/traefik-file-watch-wsl2-broken.md `
.wiki/concepts/docker-host-loopback-detect.md `
.wiki/concepts/compose-bcrypt-escape-trap.md `
.wiki/concepts/portainer-2.21-admin-password-regression.md `
.wiki/concepts/db-tls-self-signed-via-traefik-raw-tcp.md `
.wiki/concepts/rusonyx-vps-onboarding-quirks.md `
.wiki/concepts/registry-gc-mount-and-modify-flag.md `
.wiki/concepts/verdaccio-prune-semantics.md `
.wiki/concepts/recovery-architecture-snapshot.md `
.wiki/concepts/future-resilient-architecture-goals.md `
.wiki/concepts/iis-migration-2026-05-19-postmortem.md `
.tasks/vds-kzntsv-bootstrap.md .tasks/vds-gc-cron.md `
.tasks/vds-backup-rsync-kreknin.md .tasks/vds-ntfy-push.md `
.tasks/nas-recovery.md `
.tasks/iis-on-host-migration.md .tasks/iis-traefik-dead-routes-cleanup.md
Manually edit .tasks/STATUS.md — оставить только CMS-domain блоки (cms-*, traefik-maljarka-502-bug, cms-maljarka-https-mode-bug-fix). Manually edit .wiki/index.md — удалить мигрированные entries из catalog.
Commit: migrate: drop infra content moved to OpeItcLoc03/admin (history preserved there via subtree split).
9. Breadcrumb: создать .wiki/concepts/migrated-infra-to-admin.md по шаблону в .wiki/concepts/admin-infra-project.md §9 (frontmatter + Migration table + "What stays here"). Также добавить запись в .wiki/index.md под Concepts.
Commit: wiki(concepts): add migrated-infra-to-admin breadcrumb.
10. Push: git push origin master.
Acceptance:
git log --oneline -3в MoreThenCms показывает 2 cleanup-коммита поверх masterls ~/projects/MoreThenCms/.wiki/entities/пустls ~/projects/MoreThenCms/.wiki/concepts/cms-*.mdпоказывает 4-5 CMS файлов (включая webconfig-password-xml-escape)- Gitea web для MoreThenCms показывает обновлённую
.wiki/concepts/migrated-infra-to-admin.md
Done — 🟢; unblock verify-migration.
Branch: n/a
🟢 [verify-migration] — Шаг 11 миграции: end-to-end sanity check после migration push'ей. Подтвердить что projects-meta cache видит admin's tasks, knowledge_search находит migrated content, history preserved (git log --follow), и admin'ская архитектура целостная.
Closed: 2026-05-21 — validation matrix отработана, миграция структурно целостная. Acceptance summary:
- ✅ 1: admin cache @11:00:45Z — 16 tasks total, 3 active/blocked (verify-migration active, secrets-manager-adopt blocked, admin-infra-project-review blocked). All 7 imported done tasks + admin-infra-project-pointers + impl-чейн присутствуют.
- ✅ 2: MoreThenCms cache — 4 tasks (cms-admin-assets-root-folders-seed, cms-port-leak-fix, traefik-maljarka-502-bug, cms-maljarka-https-mode-bug-fix). 0 active. Никаких infra-таск.
- ⚠ 3:
knowledge_searchищет только sharedprojects-wiki(15 страниц). Admin's.wiki/НЕ indexed by knowledge_search. Spec assumption mis-scoped — migration здесь ни при чём. Finding F2. - ⚠ 4: same as #3.
- ⚠ 5:
git log --follow .wiki/concepts/wd40efax-smr-cascade.mdпоказывает только rename-merge commit (c4041823). Полная morecms-era history reachable черезgit log --all -- wd40efax-smr-cascade.md→19422352 docs(.wiki): ingest NAS recovery session 2026-05-18/19. Git--followlimitation across subtree-merge graft. Finding F3. - ✅ 6: MoreThenCms
git log -- .wiki/concepts/wd40efax-smr-cascade.md→ последний commit =1c2b8738 migrate: drop infra content...(deletion), предыдущий = original ingest. History preserved with cleanup tail. - ⚠ 7: browser-test git.kzntsv.site/OpeItcLoc03/admin — user verification (agent не может).
Findings (not migration-blocking — verification surface issues):
- F1:
mcp__projects-meta__tasks_aggregate project: "OpeItcLoc03/admin"returns empty массив несмотря на 16 tasks в cache. Cache содержимое верное (провереноnode -eчтением~/.cache/projects-mcp/tasks.json). Tool quirk — likely owner whitelist (gitea_ownersв auth.toml не включаетOpeItcLoc03). Filter logic skips not-whitelisted owners даже при явном qualified name. Follow-up task: добавитьOpeItcLoc03вgitea_owners(related agenda task:migrate-auth-toml-per-machine). - F2: knowledge_search не покрывает project-level wikis. Чтобы admin's
.wiki/concepts/*.mdстали discoverable черезknowledge_search, нужны либо отдельныеknowledge_ingestциклы в sharedprojects-wiki, либо gitea-side index integration. Spec verify-migration acceptance criteria 3-4 переадресуется на отдельную follow-up task. - F3:
git log --followне bridges subtree-merge graft. Workaround:git log --all -- <bare-filename>для полной cross-repo history. Spec'у admin-infra-project.md §Migration mechanics нужно обновить acceptance criterion 5 на этот альтернативный command.
Migration structural integrity ✅ confirmed. Findings F1-F3 → отдельные follow-up tasks при необходимости (см. секцию «Post-verify findings» ниже).
См. .wiki/concepts/admin-infra-project.md §Migration mechanics шаг 11.
Status: blocked Where I stopped: (not started) Next action: Sync cache:
node ~/projects/.common/lib/projects-meta-mcp/dist/sync.js
Validation matrix:
mcp__projects-meta__tasks_aggregate project: "OpeItcLoc03/admin"— должен вернуть все live admin tasks ([admin-infra-project-pointers], impl-таски,[resilience-roadmap-design],[secrets-out-of-common],[secrets-manager-adopt], review-umbrella).mcp__projects-meta__tasks_aggregate project: "OpeItcLoc03/MoreThenCms"— НЕ должна возвращать infra-таски (vds-, nas-recovery, iis-). Должна показывать только CMS-domain ([cms-maljarka-https-mode-bug-fix]).mcp__projects-meta__knowledge_search query: "WD40EFAX SMR cascade" domain: "all"— должен находитьOpeItcLoc03/admin:.wiki/concepts/wd40efax-smr-cascade.md.mcp__projects-meta__knowledge_search query: "migrated infra admin" domain: "all"— должен находить MoreThenCms breadcrumb.cd ~/projects/.admin && git log --follow .wiki/concepts/wd40efax-smr-cascade.md— показывает MoreThenCms-era коммиты (proof history preserved).cd ~/projects/MoreThenCms && git log -p .wiki/concepts/wd40efax-smr-cascade.md— последний коммит = удаление (migrate:prefix).- Открыть
https://git.kzntsv.site/OpeItcLoc03/adminв браузере — wiki/tasks visible.
Findings, если есть, — отдельные follow-up tasks через mcp__projects-meta__tasks_create.
Done — 🟢 с close-note типа verified end-to-end: tasks+wiki visible in admin, MoreThenCms clean, history preserved.
Branch: n/a
🟢 [resilience-roadmap-design] — Развернуть placeholder .wiki/concepts/future-resilient-architecture-goals.md (мигрирует из MoreThenCms в admin-subtree-import-and-cleanup) в полноценный fault-tolerance roadmap. Естественная отправная точка для глобальной цели пользователя: «создать отказоустойчивое решение, чтобы такие проблемы как 2026-05-18 не повторялись».
Это design task (не impl): продукт — обновлённая concepts/future-resilient-architecture-goals.md + потенциально цепочка impl-тасок-children. См. concepts/admin-infra-project.md §Initial admin agenda E.1.
Status: done Closed: 2026-05-21 — roadmap expanded via workshop pass 1 (interactive session с user). Output:
- Doc
concepts/future-resilient-architecture-goals.mdрасширен новой секцией §Workshop pass 1 (per-service RTO/RPO matrix для 10 сервисов, CMS backup 2-фазный план, IIS migration track, 4 secondary topics с recommendations без impl-таск). Старый placeholder сохранён как §Pre-workshop placeholder для history. - Top-3 impl-tasks filed:
cms-stopgap-backup-daily⚪ (Фаза 1 — plug RPO=∞),mssql-minio-migration-to-vds⚪ (Фаза 2 enabler — achieves RPO 1ч),windows-hosting-vendor-research⚪ (design-таска для IIS-переезда). - 4 next-phase topics документированы без impl-task (создавать когда руки дойдут):
cloud-offsite-backup-yandex-object(defer пока kreknin off-site),monitoring-uptime-kuma-deploy(high-priority, желательно ДО следующего host-incident'а),runbook-coverage-matrix-design(после migrations),network-mwan3-4g-failover(defer пока провайдер стабилен). - Key user-decisions зафиксированы: CMS RTO 4ч / RPO 1ч (не 1ч/15мин — overkill); MSSQL+MinIO мигрируют на VDS (не Windows-side); MSSQL Always-On AG отвергнут (log shipping достаточно); IIS долгосрочно умирает с snolla-on-node, переходный — managed Windows hosting; cloud-offsite — Yandex Object Storage когда понадобится.
- Acceptance per spec (
user подтвердил план + concrete impl-tasks top-3 + документ committed) — ✅ выполнено.
Unblocks admin-infra-project-review (была последним blocker'ом).
Where I stopped: (done)
Next action: Прочитать pointers (через admin-infra-project-pointers). Затем:
-
Inputs read:
concepts/recovery-architecture-snapshot.md(текущее состояние request flow + SPOF list),concepts/future-resilient-architecture-goals.md(placeholder с rough goals),entities/*(что есть в стеке физически). -
Expand roadmap — заполнить:
- RTO/RPO targets per service (client websites, gitea, verdaccio, registry, ntfy, traefik, DB park). Recovery Time Objective vs Recovery Point Objective отдельно по каждому. Сейчас effective RTO для NAS-loss был ~15 часов (15h до восстановления через recovery VM), RPO = 1 day (Hyper Backup daily). Какой target ставим?
- 3-2-1 backup strategy — 3 копии, 2 разных media, 1 off-site. Сейчас: VDS-data → kreknin (1 off-site daily rsync ✅), но recovery-host data → ?, client sites content → ?, source code → gitea+kreknin-mirror?
- Multi-host strategy — клиентский прод сейчас на recovery-host (single point of failure). Опции: secondary IIS host (cold/warm standby), full migration на VDS (cms-on-VDS option), bare-metal колокация. Trade-offs стоимости / сложности / RTO.
- Monitoring stack — сейчас минимально: ntfy push при backup-completion, ручная проверка через ssh. Опции: Uptime Kuma / Prometheus+Grafana / Synology Active Insight / external (Pingdom/UptimeRobot). Цель — early-warning для cascading failures (типа SMR-deg которая привела к 2026-05-18).
- Runbook coverage — какие incident-сценарии должны иметь runbook'и (NAS-loss, VDS-loss, client-site-down, traefik-crash, cert-expiry, DB-corruption, ransomware-recovery). Какие уже есть фактически (post-mortem chronologies в
sources/), какие missing.
-
Output structure:
concepts/future-resilient-architecture-goals.md— обновленный (живой документ, не frozen).- Если roadmap большой — child concepts (
concepts/resilience-rto-rpo-targets.md,concepts/resilience-monitoring-stack.md, etc.) с link'ами из основного. - Impl-tasks для каждого road-map item — отдельные таски через
tasks_create(например[setup-uptime-kuma],[secondary-iis-host-cold-standby], etc.).
-
Constraints: roadmap не review автоматически — это living document. Acceptance: user (vitya) подтвердил план, есть concrete impl-tasks для top-3 priority items, документ committed.
Done — 🟢 с close-note: «roadmap expanded; N impl-tasks created for first wave». Branch: n/a
🟢 [secrets-out-of-common] — Этап 1 secret-management фикса: вынести ~/projects/.common/secrets/ в ~/.config/projects-secrets/ (вне git-tree). Не блокирует migration (независимый workstream).
Why это дыра:
.common/— git-tracked tree. Один неаккуратныйgit add .из wrong dir / отключение gitignore rule → leak в историю.- Synology Hyper Backup тащит весь
~/projects/→ секреты сидят в backup'ах на kreknin (и были на dead-DSM). - IDE indexing / LSP / Cursor / Copilot —
.envфайлы в workspace видны редактору; в зависимости от расширений могут уйти в cloud. - Любой
find ~/projects | xargs grep— даёт plain-text secrets.
Этап 1 — быстрый фикс, low-risk, обратимый. Этап 2 (secrets-manager-adopt) — стратегический (encrypted-at-rest через pass).
См. concepts/admin-infra-project.md §Initial admin agenda E.2.
Status: done Closed: 2026-05-21 — миграция отработана.
- 9 файлов скопированы в
~/.config/projects-secrets/:gitea-token.txt,interns.env,vds-kzntsv.env,kreknin.env,noreply-snolla-smtp.env(5 real secrets) + 3 examples + README. Real-files audit: найдено 6 (не 4 как в spec'е) — kreknin.env + noreply-snolla-smtp.env не были в исходном спецификации листинге. - Live code consumers (audit grep): только 2 —
~/projects/.common/lib/interns-mcp/interns_mcp/server.py(PATCH: env-overrideINTERNS_SECRETS_PATH→ fallback~/.config/projects-secrets/interns.env) +~/projects/meeting-room/meeting_room/config.py(symmetric).gitea-token.txt/vds-kzntsv.env/kreknin.env/noreply-snolla-smtp.env— manual reference only (никто не читает кодом). - Safety filter expanded:
interns-mcp/safety.pyALWAYS_ASK_PATTERNS добавил**/projects-secrets/**(canonical glob**/secrets/**не покрывает segmentprojects-secrets). - Skill updates (claude-skills repo): setup-interns 0.3.0 → 0.4.0 (MINOR — write target changed, gitignore-phase dropped), using-interns 0.2.0 → 0.2.1 (PATCH wording),
.wiki/concepts/interns-design.mdобновлён, dist/ rebuilt. - Verification:
python -c "from interns_mcp.server import SECRETS_PATH; print(SECRETS_PATH)"→C:\Users\vitya\.config\projects-secrets\interns.env, exists=True ✅. Full MCP smoke требует session restart (в текущей сессии MCP bound к старому коду). - Cleanup:
~/projects/.common/secrets/removed entirely (git rmfor.gitignore+interns.env.example; real .env-файлы и так были gitignored).ls ~/projects/.common/secrets/→ ENOENT ✅. - Commits:
OpeItcLoc03/common@0169358+OpeItcLoc03/claude-skills@ef3d38e. - Open follow-ups (not blocking):
- ⚠️
~/projects/meeting-room— pre-existing dirty state (13 staged + UU conflict в.tasks/STATUS.md, не моя работа). Мой editmeeting_room/config.pyсидит unstaged. Не коммитил. Нужно решение user: commit-after-unblock, manual stash, или discard.config.pyedit critical — без него meeting-room runner read'нёт несуществующий.common/secrets/interns.env, env vars не загрузятся, и${OLLAMA_CLOUD_API_KEY}placeholder останется unresolved вmeeting-room/config/config.yaml. - Doc/wiki references к
.common/secrets/остались в исторических файлах (.workshop/.archive/,vds-ops-mcp/.wiki/,MoreThenCms/.tasks/,books/.wiki/, etc.) — informational, не behavior. Bulk-update — отдельный chore-task если нужно. - Cross-machine: на других машинах (если есть) повторить шаги migrate (
mkdir -p ~/.config/projects-secrets/ + scp creds) + pullOpeItcLoc03/common+OpeItcLoc03/claude-skills.
- ⚠️
Unblocks secrets-manager-adopt (etap-2). Acceptance per spec — ✅ выполнено (см. шаги выше).
Where I stopped: (done)
Next action: 1. Audit: ls ~/projects/.common/secrets/ — какие файлы там лежат сейчас? Список ожидаемых из памяти:
interns.env— API keys для cheap LLM endpointsgitea-token.txt— admin-scoped Gitea token (admin-scope per memory)vds-kzntsv.env— VDS creds (ssh + DB + portainer + ntfy)- возможно другие
2. Audit потребителей:
~/projects/.common/lib/interns-mcp/— где читаетсяinterns.env? Grep поinterns.envилиdotenvcalls.~/projects/.common/lib/projects-meta-mcp/— где читается token? Часто это~/.config/projects-mcp/auth.tomlотдельно (см. setup-projects-meta skill); но возможны cross-refs.~/.claude.jsonmcpServers.*— где ENV/args ссылаются на.common/secrets/*?~/projects/.common/secrets/vds-kzntsv.env— кто его читает (scripts? local docs only?).
3. Migration:
mkdir -p ~/.config/projects-secrets
cp -r ~/projects/.common/secrets/* ~/.config/projects-secrets/
chmod 600 ~/.config/projects-secrets/* # paranoid; Windows ACL отдельно
4. Update consumers: для каждого identifier'а из шага 2 — поменять path на абсолютный ~/.config/projects-secrets/<file> или принять env-override (рекомендуется env-override: легче тестировать на других машинах).
5. Verify: в чистой сессии claude --reload + проверить что mcp__interns__* и mcp__projects-meta__* всё ещё работают.
6. Cleanup .common/secrets/:
- Удалить (
rm -rf ~/projects/.common/secrets/) - НЕ оставлять stub-файлы или README — это вектор для regression'а.
- Git:
cd ~/projects/.common && git add -A && git commit -m "secrets: move out of common (now at ~/.config/projects-secrets/)"если.commongit-tracked.
7. Cross-machine note: other machines (если есть) — повторить шаги 3-5 при первой возможности (вписать как note в close).
Acceptance: ls ~/projects/.common/secrets/ returns ENOENT, MCP servers still work, no .env references to .common/secrets/ в коде/configs.
Done — 🟢; unblock secrets-manager-adopt.
Branch: n/a
🟢 [secrets-manager-adopt] — Этап 2 secret-management: внедрить pass (gpg-based password-store) — encrypted-at-rest secrets + cross-machine sync через private Gitea repo с encrypted blobs.
Альтернатива — Bitwarden CLI (cloud vault, audit log). Recommend pass для one-user setup — нет cloud-dependency, gpg native, encrypted git-syncable.
Why этап 2 нужен: после secrets-out-of-common (этап 1) секреты лежат plaintext в ~/.config/projects-secrets/. Этап 1 убирает риски 1+3 (git leak + IDE indexing), но не риск 4 (любой filesystem read даёт plaintext) и не риск 2 (Hyper Backup на kreknin всё ещё тащит plaintext если ~/.config/ в scope, что зависит от backup config). pass закрывает оба — secrets зашифрованы на диске, расшифровка только в RAM при pass show.
См. concepts/admin-infra-project.md §Initial admin agenda E.3.
Status: done Closed: 2026-05-21 — encrypted-at-rest store live + cross-machine sync ready.
Components installed:
- gpg key: RSA 4096, no expiration, fingerprint
0CB0B0190149295E8012B438E969C2C24FE3F59E, uidVictor Kuznetsov <vitya.kuznetsov@gmail.com>. User-managed passphrase. - pass v1.7.4: manual clone
https://git.zx2c4.com/password-store→~/.local/src/password-store/, symlinked at~/.local/bin/pass(PATH'е уже был~/.local/bin). Deps: gpg ✅, git ✅, getopt ✅.treeотсутствует (cosmetic;pass lsпадает — non-critical). - gpg-agent config:
~/.gnupg/gpg-agent.conf→pinentry-program C:/Program Files/Git/usr/bin/pinentry-w32.exe+default-cache-ttl 2592000(30 days) +max-cache-ttl 2592000. Один passphrase prompt в 30 дней (или после reboot).
Pass-store layout (5 entries):
| Pass path | Source plaintext | Type |
|---|---|---|
interns/ollama-cloud-api-key |
interns.env OLLAMA_CLOUD_API_KEY |
single value |
gitea/admin-token |
gitea-token.txt |
single value |
vds-kzntsv/full-env |
vds-kzntsv.env (whole file) |
multiline dotenv |
kreknin/full-env |
kreknin.env (whole file) |
multiline dotenv |
snolla-smtp/full-env |
noreply-snolla-smtp.env (whole file) |
multiline dotenv |
Consumer integration:
mcp__interns__*—~/.local/bin/interns-mcp-launcher.shwrapper:export OLLAMA_CLOUD_API_KEY="$(pass show interns/ollama-cloud-api-key)"; exec python -m interns_mcp.server. Wired в~/.claude.jsonmcpServers.interns(command: bash.exe,args: [/c/.../launcher.sh],env.INTERNS_PYTHON: /c/.../python.exe). Backup~/.claude.json.bak-pre-pass-20260521-144943.meeting-roomCLI — config.py читает env-override (если установлен) → fallback на~/.config/projects-secrets/interns.env(теперь нет). User pattern:export OLLAMA_CLOUD_API_KEY=$(pass show interns/ollama-cloud-api-key)перед meeting-room invocation. Documented в~/.config/projects-secrets/README.md.
Cross-machine sync:
- Private Gitea repo
OpeItcLoc03/password-store-private(private=true) created via API. URL:https://git.kzntsv.site/OpeItcLoc03/password-store-private.git. pass git init+ remote add origin + push → 7 commits pushed (1 init + 5 inserts + 1 base).- Recovery на новой машине: install
pass,gpg --import privkey.asc,git clone <url> ~/.password-store,pass show <any>для cache-warm. Documented в README.
Cleanup plaintext: ~/.config/projects-secrets/ — удалены 5 secret files (interns.env, gitea-token.txt, vds-kzntsv.env, kreknin.env, noreply-snolla-smtp.env). Остались marker README (rewritten под pass-pattern), .gitignore, 2 examples. Acceptance per spec ✅ — "пуст или содержит только README".
Verification:
- ✅
pass show interns/ollama-cloud-api-key→ 57-char OLLAMA value (matches original interns.env) - ✅ Wrapper smoke:
timeout 3 bash ~/.local/bin/interns-mcp-launcher.sh </dev/null→ EXIT=0, no startup error - ✅ All 5 entries decrypt without re-prompt (gpg-agent cache warm)
- ✅
pass git status→ clean, up to date with origin/master - ⚠️ Full
mcp__interns__bulk_text_readsmoke требует Claude Code restart (текущая сессия bound к старому Python процессу — у него env уже cache'нут).
Open follow-ups:
- meeting-room WIP unblock: etap-1 edit
meeting_room/config.pyсидит unstaged рядом с pre-existing dirty state (UU conflict в.tasks/STATUS.md+ 13 staged files не моя работа). Required for runtime correctness — без edit'а meeting-room ищет несуществующий~/projects/.common/secrets/interns.env. Опционально: добавить subprocess-pass fallback в config.py (pass show с timeout) для transparent integration без manual export. Решение user'а. - setup-interns SKILL update (next task candidate): v0.4.0 описывает plaintext-
.envwrite path как canonical. После etap-2 canonical — pass-based wrapper. Нужен SKILL bump 0.4.0 → 0.5.0 (MINOR): добавить gpg+pass prerequisite check, мигрировать Phase 5 write наpass insert, Phase 6 register wrapper-bash command. Большое обновление — отдельная task'а черезtasks_create. - New endpoints in
interns/config.yaml: добавить новый<NAME>→pass insert interns/<name-kebab>+ добавитьexport <NAME>="$(pass show interns/<name-kebab>)"в wrapper-launcher.sh. Pattern documented в README. - VDS secrets read on demand: non-interns secrets (vds/kreknin/smtp) —
pass show <path>/full-envдля просмотра,eval "$(pass show <path>/full-env | grep -v '^#')"для source в shell. Pattern documented в README.
Acceptance per spec: ✅ all 4 criteria met (~/.config/projects-secrets/ clean of secrets, consumers wired (wrapper + meeting-room pattern documented), pass git status clean, encrypted blobs в Gitea private repo).
Commits:
~/.password-store/(OpeItcLoc03/password-store-private): 7 commits pushed~/.claude.json: edited locally (config, not git-tracked beyond bak file)- New files:
~/.local/bin/interns-mcp-launcher.sh,~/.gnupg/gpg-agent.conf, README rewritten at~/.config/projects-secrets/ - This STATUS.md update committed in OpeItcLoc03/admin
Where I stopped: (done) Next action: 1. Pre-install — gpg setup (Windows):
- Install Gpg4win (https://www.gpg4win.org/) или через Scoop:
scoop install gpg. gpg --full-generate-key— выбрать RSA 4096, без expiration ИЛИ 2-year expiration с rotation reminder.gpg --list-secret-keys— захватить fingerprint.
2. Install pass:
- MSYS2:
pacman -S pass(если есть MSYS2) - Scoop:
scoop install pass - Manual: pass is bash script — clone https://git.zx2c4.com/password-store/ и положить на PATH.
3. Initialize store:
pass init <gpg-fingerprint>
# Creates ~/.password-store/.gpg-id
4. Migrate secrets:
- Для каждого file/var в
~/.config/projects-secrets/:pass insert <category>/<name>→ вводим plaintext, pass сохраняет как~/.password-store/<category>/<name>.gpg
- Примеры:
pass insert gitea/admin-tokenpass insert vds-kzntsv/ssh-passwordpass insert vds-kzntsv/portainer-passwordpass insert interns/openai-keypass insert interns/anthropic-key
- Сохранить mapping (какой
.envkey какойpass-path) —concepts/secrets-pass-mapping.mdingest в admin wiki.
5. Update consumers — заменить direct file reads на shell-out calls:
interns-mcpconfig: вместоOPENAI_API_KEY=<plain>в env-файле →OPENAI_API_KEY=$(pass show interns/openai-key)в wrapper-скрипте startup.~/.claude.jsonmcpServers.*env: если поддерживает command-eval —pass show ...; иначе wrapper-script.- Альтернатива —
pass-aware loader script~/.config/projects-secrets/load.shкоторый populate'ит env vars из pass при session start.
6. Cross-machine sync: initialize private Gitea repo OpeItcLoc03/password-store-private (visibility=private), push ~/.password-store/. На каждой машине: clone + gpg --import master key + работает.
7. Cleanup plaintext: удалить ~/.config/projects-secrets/* (содержимое мигрировано в pass). Оставить пустой dir + README указывающий на pass.
8. Verify: в чистой сессии все MCP / scripts работают через pass-resolved secrets.
Acceptance: ls ~/.config/projects-secrets/ пуст или содержит только README, все consumers работают, pass git status clean, encrypted blobs в Gitea private repo.
Done — 🟢; secret-management dyra closed. Blocker: secrets-out-of-common Branch: n/a
🟢 [admin-infra-project-review] — Code-review checkpoint для брейнсторма admin-infra-project (промоушен 2026-05-21).
Closed: 2026-05-21 — review pass executed from .workshop/ cwd по explicit user request (нормально должен бы из ~/projects/.admin/). All 8 impl-tasks verified против spec acceptance criteria через 4 параллельных verification subagent'а: (A) migration completeness — admin 6 entities / 3 sources / 18 concepts; MoreThenCms cleanup чистый; breadcrumb table 28 entries полная; (B) history preservation — git log --all -- <bare> достаёт MoreThenCms-era коммиты (23 для wd40efax-smr-cascade, 51 для vds-kzntsv-bootstrap), --follow ограничен subtree-merge graft (matches F3); git fsck чистый; 4 split-branches в MoreThenCms не push'нуты как и планировалось; (C) secrets etap-1 — ~/projects/.common/secrets/ ENOENT, нет grep-references; secrets etap-2 — 5 entries в ~/.password-store/ декриптятся, wrapper ~/.local/bin/interns-mcp-launcher.sh wired в ~/.claude.json, OpeItcLoc03/password-store-private synced (7 commits), gpg fingerprint 0CB0B019…59E, 30-day gpg-agent cache; (D) commits-vs-spec — все ~30 admin коммитов мапятся на spec steps, archive→spec refinement (read-tree → temp-prefix dance) задокументирован coherently, нет admin-* скилов в claude-skills (anti-pattern избежан), CLAUDE.md 10 lines + follow tdd-criteria отсутствует.
No new findings. F1–F3 из [verify-migration] остаются documented там: F1 (tasks_aggregate project: "OpeItcLoc03/admin" empty — likely projects-meta-mcp gitea_owners whitelist bug, не admin defect), F2 (knowledge_search не indexes project-level wikis — spec assumption error в verify-migration criteria 3-4, не impl defect), F3 (git log --follow не bridges subtree-merge graft; workaround git log --all -- <bare-filename> подтверждён working).
Subagent A false-positive caught: breadcrumb-таблица была флагнута как incomplete (8 listed / 11 admin task files), но 3 разницы (cms-stopgap-backup-daily, mssql-minio-migration-to-vds, windows-hosting-vendor-research) — admin-native таски от resilience-roadmap-design workshop pass 1, не migration-targets. Direct read breadcrumb-файла подтвердил полноту (28 entries).
Process note: Workshop CLAUDE.md §«Агент в .workshop/ сам код-ревью не делает» нарушен по user override. Следующий review-цикл лучше гонять из cd ~/projects/.admin/ для clean CLAUDE.md / MCP binding и для соблюдения «не имплементер»-принципа на process-level (хотя current reviewer не был имплементером ни по одной из 8 импл-таск).
User confirmed close by inspection: "Close review as no-new-findings (Recommended)".
Спецификация: .wiki/concepts/admin-infra-project.md (ingested 2026-05-21).
Pre-impl bootstrap: admin-infra-project-pointers — заполнил .wiki/CLAUDE.md Domain conventions design-context pointer'ами. Без неё review бы читал stub.
Импл-таски (review против их acceptance criteria): morecms-subtree-split, admin-subtree-import-and-cleanup, morecms-cleanup-and-breadcrumb, verify-migration, resilience-roadmap-design, secrets-out-of-common, secrets-manager-adopt.
Кто делает: не имплементер. Следующая сессия в этом проекте (другая модель / другой день / другой агент) поднимает таску с чистым контекстом. «Я только что это написал» bias = главный риск.
Чек-лист ревью:
- Прочитать спецификацию
concepts/admin-infra-project.md(acceptance criteria каждой импл-таски). git log --onelineshipped-коммитов в~/projects/.admin/и~/projects/MoreThenCms/(по migrate:/cleanup:/wiki:/tasks: префиксам в commit-message).- Для migration-цепочки:
git log --followна парах файлов admin VS MoreThenCms — history preserved per-file?- Нет ли CMS-файлов в admin (cleanup сработал)?
- Нет ли admin-файлов в MoreThenCms (cleanup сработал)?
cat MoreThenCms/.wiki/concepts/migrated-infra-to-admin.md— breadcrumb корректный, все listings соответствуют реальности?
- Для
verify-migration— повторно прогнать его validation matrix; нет ли регрессий после resilience/secrets работ? - Для
resilience-roadmap-design— roadmap расширен по существу (RTO/RPO с цифрами, не «TBD»; concrete impl-tasks для top-3) ИЛИ остался stub-<TBD>-placeholder fake-completion'ом? - Для
secrets-out-of-common—ls ~/projects/.common/secrets/точно пуст? Git history.common/не содержит leak'нутых secrets в недавних коммитах? - Для
secrets-manager-adopt—pass showactually works для всех migrated entries?~/.config/projects-secrets/пуст или README-only? - Сверить дизайн-decisions из спецификации со shipped state. Любое отклонение от §Migration mechanics / §Initial admin agenda / §Identity — flag.
- Findings — отдельные follow-up tasks (
<topic>-<gap>-fixили подобное) черезtasks_create.
Закрытие: только когда все findings зафайлены ИЛИ ревьюер подтвердил «нет findings» в close-note.
Status: done
Where I stopped: (done)
Next action: Прочитать pointers (.wiki/CLAUDE.md §Domain conventions) → спецификацию (concepts/admin-infra-project.md). Для каждой импл-таски: git show <commit>, прогнать acceptance criteria из её next_action, сверить с design-decisions в спецификации. Findings → новые follow-up tasks через mcp__projects-meta__tasks_create. См. чек-лист в description выше.
Note: review не обязан проверять acceptance таск-children из roadmap-design (cms-stopgap-backup-daily, mssql-minio-migration-to-vds, windows-hosting-vendor-research) — review скопирует только design-task'у roadmap-design саму, проверка её output'а: roadmap расширен по существу (RTO/RPO с цифрами не «TBD») + top-3 impl-tasks filed.
Branch: n/a
⚪ [cms-stopgap-backup-daily] — Фаза 1 CMS backup. Plug текущую дыру RPO=∞ для CMS прод (sites + MSSQL + MinIO на windows-recovery-host). Ежедневный rsync на kreknin до пока MSSQL/MinIO не переедут на VDS через mssql-minio-migration-to-vds (тогда списываем этот pipeline).
Это временное решение — не строить ничего изощрённого. Cron через Windows Task Scheduler + rsync + ssh-pipe. Достигаемый RPO = 24ч (не target 1ч, но лучше чем ∞).
Status: ready
Where I stopped: (not started)
Next action: См. cms-stopgap-backup-daily.md — acceptance + key files + open questions. Order: (1) verify MinIO data dir location через docker inspect minio, (2) write PowerShell backup script с тремя ногами (mssql/sites/minio) + ntfy push, (3) test smoke recovery на MSSQL backup, (4) wire через Windows Task Scheduler daily 03:00 MSK, (5) document в .wiki/concepts/cms-stopgap-backup-pipeline.md. Spawn'd by [resilience-roadmap-design] workshop pass 1 2026-05-21.
Branch: n/a
⚪ [mssql-minio-migration-to-vds] — Фаза 2 CMS backup. Перенести MSSQL контейнер + MinIO с windows-recovery-host на vds-kzntsv. Achieves target RPO 1ч через интеграцию с существующим vds-backup-rsync-kreknin pipeline (tx log backups каждые 60 мин в существующий rsync→kreknin). Снимает SPOF с домашней машины для критических CMS-данных.
После завершения — списать cms-stopgap-backup-daily cron на windows-host.
Status: ready
Where I stopped: (not started)
Next action: См. mssql-minio-migration-to-vds.md — full acceptance (8 items) + risks + open questions. Major task (1-2 недели realistic). Разбить на sub-phases: (a) MSSQL container deploy на VDS + restore from backup, (b) connection string change + smoke 8 hosts, (c) MinIO migration через mc mirror, (d) backup pipeline integration в /opt/stacks/backup/scripts/run.sh. Pre-cutover benchmark обязателен (admin assets UI / search / catalogs) — WAN latency 10-30ms vs localhost. Spawn'd by [resilience-roadmap-design] workshop pass 1 2026-05-21.
Branch: n/a
⚪ [windows-hosting-vendor-research] — Design-таска (1 день). Выбрать вендора managed Windows hosting для будущего переезда IIS с windows-recovery-host (домашней машины). Output: 1-pager с recommended vendor + cost estimate + migration recipe outline.
Это переходный трек до завершения snolla node-rewrite'а (после которого IIS не нужен вообще). Не файлим impl-таску миграции до этой research'и — vendor выбираем сначала.
Status: ready
Where I stopped: (not started)
Next action: См. windows-hosting-vendor-research.md — constraints + candidates + acceptance. Steps: (1) research 4 candidates (Rusonyx / Selectel / FirstVDS / Beget), (2) fill comparison table по criteria (RDP / .NET 4.8 / IIS 10 / public IP / cost / SLA / reviews), (3) write top-1 recommendation с trade-off justification, (4) cost estimate monthly + one-time, (5) document в .wiki/concepts/windows-hosting-vendor-comparison-2026.md. Не file follow-up impl-task iis-migration-to-managed-windows-hosting — пусть future-agent file'нёт когда vendor выбран. Spawn'd by [resilience-roadmap-design] workshop pass 1 2026-05-21.
Branch: n/a
Imported from MoreThenCms — 2026-05-21 subtree-split migration
Полное содержимое .tasks/STATUS.md из MoreThenCms на момент 2026-05-21, CMS-domain блоки исключены (остались в MoreThenCms): cms-admin-assets-root-folders-seed, cms-port-leak-fix, traefik-maljarka-502-bug, cms-maljarka-https-mode-bug-fix. История per-file сохранена через subtree-split + temp-prefix merge.
🟢 [vds-kzntsv-bootstrap] — VDS поднят, gitea/verdaccio/registry мигрированы (3/3 phases done 2026-05-20)
Status: done (2026-05-20 вечер — все 3 заявленные фазы закрыты)
Where I stopped: Phase 1 + Phase 2 завершены ✅. VDS 89.253.255.94 / vds.kzntsv.site Ubuntu 24.04 upgraded через VNC. sudo vitya (NOPASSWD) + ssh-key + hardened sshd (key-only) + ufw 22/80/443 + DB-порты + fail2ban + docker 29.5.1 + buildx + compose. Traefik v2.11 на traefik.vds.kzntsv.site (basicAuth vitya:Pryakhin9). Portainer CE 2.21.5 на portainer.vds.kzntsv.site — админ-пароль был принудительно изменён на Pryakhin9-VDS-2026 (18 chars) из-за hard min-12-char policy в Portainer 2.21+ (regression от 2.20). API key получен и сохранён в vds-kzntsv.env. 4 DB-стека (Postgres 16, MariaDB 11.4, Mongo 7, Redis 7) подняты с self-signed TLS, доступны снаружи через traefik raw-TCP passthrough на <db>.vds.kzntsv.site:<port> (HostSNI(*) — traefik tls.passthrough+SNI не работает с STARTTLS-протоколами PG/MariaDB; rawTCP forward, DBs терминируют TLS сами). Все DB passwords (PG/Maria/Mongo/Redis) — strong random hex16, сохранены в vds-kzntsv.env.
Open questions: LE certs для DBs (сейчас self-signed → клиент verify-skip; permanent fix позже через lego sidecar extract из traefik acme.json).
Next action: Phase 3 миграция с kreknin ВСЯ DONE ✅. 3.1 gitea (132 repos, 4 users, v1.25.5 на git.kzntsv.site). 3.2 verdaccio (8.6G storage, 2063 packages, secret 32 chars). 3.3 registry — отказались от миграции старых 35G images (user: «новых наделать могу»), fresh install на registry.kzntsv.site + Joxit UI на registry-ui.vds.kzntsv.site (DELETE_IMAGES=true для GUI cleanup, REGISTRY_STORAGE_DELETE_ENABLED для API delete). Auth vitya:Pryakhin9 (см. vds-kzntsv.env). Follow-up tasks: vds-gc-cron, vds-backup-rsync-kreknin, vds-ntfy-push.
Branch: master
🟢 [iis-on-host-migration] — attempt 2 close-out: 36h soak passed, 8/8 наших sites зеленые
Status: done (2026-05-21 close-out). Detail: Phase 11 в iis-host-migration-2026-05-19.
Close-out evidence: traefik Up 38h (zero restarts), w3wp 8.8h (scheduled pool recycle ~29h default, не crash), 8/8 наших sites вернули Microsoft-IIS/10.0 через full traefik HTTPS chain (emspb/snolla/on.snolla/pilorama98/labtools.ru/labtools.pro/tandemmebel/kupimknigi). Маljarka/sestech/ics-artmaterials оказались off-infra (DNS снят / parked / external nginx) — не наша инфра, не regression. Новая follow-up task ⚪ iis-traefik-dead-routes-cleanup (низкий приоритет — почистить yml для 3 dead доменов).
VM savestate: done 2026-05-21 05:13 MSK (45.6s, VMState=saved). Savestate file 1.73 GB (C:\Users\vitya\VirtualBox VMs\snolla-recovery\Snapshots\2026-05-21T05-12-43-636491200Z.sav). VBoxHeadless процессы освободили ~4 GB private memory. Resume: VBoxManage startvm snolla-recovery --type headless (~30 сек если понадобится). Disk delete (unregistervm --delete, ~95 GB) — позже через неделю uptime.
Atomic revert (unchanged): Get-ChildItem C:\Users\vitya\projects\docker\diskstation\traefik\data\custom\*.yml.bak-pre-attempt2-2026-05-19 | %{ Copy-Item $_.FullName -Destination ($_.FullName -replace '\.bak-pre-attempt2-2026-05-19$','') -Force }; Move-Item C:\Users\vitya\projects\docker\diskstation\traefik\data\custom\stostayer.yml.disabled C:\Users\vitya\projects\docker\diskstation\traefik\data\custom\stostayer.yml -Force -EA SilentlyContinue; Move-Item C:\Users\vitya\projects\docker\diskstation\traefik\data\custom\oldstostayer.yml.disabled C:\Users\vitya\projects\docker\diskstation\traefik\data\custom\oldstostayer.yml -Force -EA SilentlyContinue; docker restart traefik
Branch: master
🟢 [iis-traefik-dead-routes-cleanup] — sestech + isc-artmaterials disabled, maljarka оказалась live
Status: done (2026-05-21 ~05:42 MSK; ~20 мин работы). Result:
sestech.yml→.disabled(backup.bak-pre-dead-routes-cleanup-2026-05-21). DNSsestech.ru/www.sestech.ru → 31.31.205.163= parking provider, наш traefik больше не отвечает (public requests идут на parking host через DNS).isc-artmaterials.yml→.disabled(backup created). DNSics-artmaterials.com/www → 87.236.16.28 = external nginx-reuseport WP-хостинг, public traffic не через нас.- Maljarka — НЕ disabled — оказалось yml route'ит
maljarka.tandemmebel.ru(subdomain тандеммебели), не голыйmaljarka.ru. DNS → 94.19.247.14 = наш IP, IIS backend отвечает 200 OK ("Малярка от Тандеммебель", 43KB). Live route, не dead. Изначальная task'а ошиблась с hostname. Smoke regression: 4 live hosts (emspb/on.snolla/www.tandemmebel/kupimknigi) → Microsoft-IIS/10.0 без regression. File-provider auto-reload, traefik restart не понадобился. Side finding:maljarka.tandemmebel.ruчерез traefik HTTPS → 502 Bad Gateway, хотя backend (host.docker.internal:8089 + Host header) возвращает 200 OK. Конфиг yml identical к работающемуtandemmebel.yml. Live bug. Новая follow-up ⚪ tasktraefik-maljarka-502-bug(CMS-domain — остаётся в MoreThenCms). Atomic revert:Move-Item C:\Users\vitya\projects\docker\diskstation\traefik\data\custom\sestech.yml.disabled C:\Users\vitya\projects\docker\diskstation\traefik\data\custom\sestech.yml -Force; Move-Item C:\Users\vitya\projects\docker\diskstation\traefik\data\custom\isc-artmaterials.yml.disabled C:\Users\vitya\projects\docker\diskstation\traefik\data\custom\isc-artmaterials.yml -ForceBranch: master
🟢 [vds-gc-cron] — weekly GC armed для verdaccio + registry на VDS
Status: done (2026-05-21 00:21 MSK; ~1ч работы). Детали в vds-gc-cron.md.
Result: /etc/cron.d/vds-gc armed — Sun 03:00 MSK registry-gc.sh, Sun 03:30 MSK verdaccio-prune.sh. Scripts в /opt/stacks/gc/scripts/ (notify.sh, registry-gc.sh, verdaccio-prune.sh+verdaccio-prune.js). Logs в /var/log/vds-gc/. Notify через ntfy vds-ops.
Verdaccio prune real run: 8.5G → 6.8G (freed 1.7G), 7021 packages scanned, 1551 modified, 4524 tgz deleted, 0 errors, 73 locally-published versions защищены (@snollajs/* + similar — detected via _distfiles[tgzName] absent). Atomic JSON rewrite (tmp + rename) + _rev bump.
Registry GC smoke: alpine v1+v2 pushed → DELETE manifest → GC freed 61M (whole tree, since both tags pointed одну digest). Empty-storage guard added (first run на свежем registry — /var/lib/registry/docker/registry/v2/repositories отсутствует → skip+min-prio notify, не FAIL).
Atomic revert: ssh vitya@89.253.255.94 'sudo rm /etc/cron.d/vds-gc; sudo systemctl restart cron; sudo rm -rf /opt/stacks/gc /var/log/vds-gc'
Branch: master
🟢 [vds-backup-rsync-kreknin] — daily VDS→kreknin live, smoke green, cron armed
Status: done (2026-05-20 → 2026-05-21 00:00 first-run завершён успешно). Детали в vds-backup-rsync-kreknin.md.
Result: rsync --link-dest pipeline /opt/stacks/backup/scripts/run.sh под cron 0 5 * * * (root) → kreknin /volume1/NetBackup/vds-kzntsv/<DATE>/ + symlink latest. DB dumps (pg/maria/mongo/redis), system config (/etc/ssh, ufw, hosts, docker), ssh keys, /opt/stacks data. Notification dual-channel: email через msmtp+Yandex (/etc/msmtprc) + ntfy publish на vds-backup topic. Retention 7 daily snapshots. Smoke run done — 71,867 files / 11.74G в 21m27s, exit 0. Cron service installed (apt install cron — Ubuntu 24.04 не имел его) + enabled. Next run автоматически 2026-05-21 05:00 MSK.
SPOF gap status: closed for VDS — full restore from kreknin возможен (DB dumps + конфиги + ssh keys).
Open: phone-side smoke (user verifies ntfy push пришёл из реального backup run).
Atomic revert: ssh vitya@89.253.255.94 'sudo systemctl stop cron; sudo rm /etc/cron.d/vds-backup; sudo apt-get remove -y cron msmtp msmtp-mta; sudo rm -rf /etc/msmtprc /opt/stacks/backup /var/log/vds-backup'
Branch: master
🟢 [vds-ntfy-push] — self-hosted ntfy.vds.kzntsv.site live, phone-verified
Status: done (2026-05-20 вечер; ~30 min работы). Detail в vds-ntfy-push.md.
Result: ntfy v2.11.0 на ntfy.vds.kzntsv.site, LE cert (R12, valid до 2026-08-18), admin user vitya / Pryakhin9 (deny-all дефолт, admin role → rw to all), топики vds-backup + vds-ops. Phone-verified — оба push'а пришли в Android ntfy app (screenshot 22:54). Creds в ~/projects/.common/secrets/vds-kzntsv.env + /opt/stacks/ntfy/.env (chmod 600).
Integration ready for: vds-backup-rsync-kreknin (publish status на vds-backup), monitoring scripts (на vds-ops).
Atomic revert: ssh vitya@89.253.255.94 'cd /opt/stacks/ntfy && docker compose down -v && cd .. && rm -rf ntfy' + remove ntfy entries из vds-kzntsv.env.
Branch: master
🟢 [nas-recovery] — клиентские сайты восстановлены, работают из публичного интернета
Status: done (2026-05-19 ~10:00 MSK — 15 часов работы) Final state: OpenWRT NAT → traefik 2.6.6 (host:8000/4443) → VirtualBox VM snolla-recovery (IIS + CMS) + docker-стек на хосте (MSSQL/MinIO/ES/imgproxy/nginx). 13 client routes, 40 LE certs валидны. Проверено: пользовательский клиент из публичного интернета открывает snolla.com, pilorama98.ru, labtools.ru/pro, tandemmebel.ru, emspb.ru. Backup pull: C:\nas-recovery\vm-sites\ (~11 GB inetpub/wwwroot + stayer/) — на случай если VM снова станет нестабильной. Open issues (минор):
- X-Forwarded-Proto/Host: CMS делает redirect с портом 4443 в URL — нужно добавить middleware в traefik или включить trust в IIS.
- MinIO/Azure storage — пользователь упомянул "не так всё", ждём пояснение.
- docker-сокет проброс в traefik — daemon connection error (некритично, file-provider routing работает).
- VM в bridged-WiFi была нестабильной → переехали на NAT + port forwards.
- acme.json renewal через HTTP-01 фейлится для доменов с DNS не на нашем IP — нужно переключить на DNS-01 через REGRU (creds в env уже). Branch: master