tasks: import board-viewer-vds-deploy from dev-project [board-viewer-vds-deploy]

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-проекте.
This commit is contained in:
2026-05-22 16:05:50 +03:00
parent adcd8bda1f
commit 65c6ad9eea
2 changed files with 67 additions and 0 deletions

View File

@@ -10,6 +10,16 @@ _Updated: 2026-05-22 (Сессия завершена. MSSQL Express 2022 live
🔵 Blocked — waiting on external input 🔵 Blocked — waiting on external input
--> -->
## ⚪ [board-viewer-vds-deploy] — поднять `board.kzntsv.site` (docker-compose stack за traefik basic-auth)
**Status:** ready
**Where I stopped:** (not started — handoff из dev-проекта `~/projects/board-viewer/`, артефакты `deploy/` code-complete + smoke-verified)
**Next action:** DNS A-record `board.kzntsv.site` → VDS IP; затем `docker build -f deploy/Dockerfile.build -t registry.kzntsv.site/board-viewer-build:latest . && docker push …` на dev-машине; затем bootstrap `/opt/stacks/board-viewer/` на VDS — см. полный чек-лист в `board-viewer-vds-deploy.md` (Pending ops actions) и `~/projects/board-viewer/deploy/README.md`.
**Branch:** n/a
<!-- created-by: OpeItcLoc03@DESKTOP-NSEF0UK / from: .workshop / 2026-05-22 / handoff: ~/projects/board-viewer/.tasks/board-viewer-cron-deploy.md -->
---
## 🟢 [owncloud-vds-deploy] — oCIS 7.1.0 на vds-kzntsv live, 25 044 объектов / 26 GB ## 🟢 [owncloud-vds-deploy] — oCIS 7.1.0 на vds-kzntsv live, 25 044 объектов / 26 GB
**Closed:** 2026-05-22 — import complete. 99.97% (22.2 GB / 25 038 objs) залито rclone'ом за ~2.5 ч (3.35 MiB/s uplink). Оставшиеся 6 файлов (4.04 GB) — 4× .pat ~221 MB + 2× .seospider 1.55+1.7 GB — упали с 502 (later 500) на каждой попытке rclone из-за 60-секундного timeout где-то в HTTP stack (Go http.Client.Timeout в reva v2.27 datagateway, **не** traefik). Workaround: throwaway sftp-only ssh-key → агент scp'ит в `/tmp/oc-import/` на VDS → c VDS curl PUT loopback'ом через traefik в правильные oCIS пути (local network 142 MB/s — все 6 файлов залиты за 28 секунд total). Все PROPFIND size match. Throwaway-key revoked, staging cleaned. **Closed:** 2026-05-22 — import complete. 99.97% (22.2 GB / 25 038 objs) залито rclone'ом за ~2.5 ч (3.35 MiB/s uplink). Оставшиеся 6 файлов (4.04 GB) — 4× .pat ~221 MB + 2× .seospider 1.55+1.7 GB — упали с 502 (later 500) на каждой попытке rclone из-за 60-секундного timeout где-то в HTTP stack (Go http.Client.Timeout в reva v2.27 datagateway, **не** traefik). Workaround: throwaway sftp-only ssh-key → агент scp'ит в `/tmp/oc-import/` на VDS → c VDS curl PUT loopback'ом через traefik в правильные oCIS пути (local network 142 MB/s — все 6 файлов залиты за 28 секунд total). Все PROPFIND size match. Throwaway-key revoked, staging cleaned.

View File

@@ -0,0 +1,57 @@
# board-viewer-vds-deploy
## Goal
Поднять статическую HTML-доску `board-viewer` (read-only kanban over Gitea API) на VDS под `board.kzntsv.site`. Двухсервисный docker-compose stack (cron-loop build + nginx serve) за traefik с basic-auth. Periodic regen каждые ~5 мин внутри build-контейнера.
Артефакты deploy/ написаны и валидированы в dev-проекте `~/projects/board-viewer/deploy/`. Эта таска — чисто ops-handoff: DNS, image build/push, bootstrap stack, smoke.
## Source dev-project
- Repo: `~/projects/board-viewer/``https://git.kzntsv.site/OpeItcLoc03/board-viewer.git`
- Artefacts (HEAD-of-master, code-complete):
- `deploy/docker-compose.yml` — стек на `proxy` network, traefik labels
- `deploy/Dockerfile.build` — node:22-alpine + cron-loop entrypoint
- `deploy/nginx.conf` — static serving + Cache-Control
- `deploy/auth.toml.example` — шаблон Gitea token + repo whitelist
- `deploy/.env.example` — шаблон `BOARD_VIEWER_USERS` (basic-auth bcrypt, с `$$`-escape)
- `deploy/README.md` — полный One-time setup + Day-to-day + DR
- Compose syntax валидирован (`docker compose config`)
- Smoke против real Gitea (78 records, 4 repos) — `node --experimental-strip-types src/cli.ts` производит `dist/index.html + dist/static/`
## Pending ops actions
- [ ] **DNS:** A-record `board.kzntsv.site` → VDS IP (где живёт DNS — Cloudflare / namecheap)
- [ ] **Build & push image:** на dev-машине из корня репо:
`docker build -f deploy/Dockerfile.build -t registry.kzntsv.site/board-viewer-build:latest .`
`docker push registry.kzntsv.site/board-viewer-build:latest`
- [ ] **Bootstrap `/opt/stacks/board-viewer/` на VDS:**
- скопировать `docker-compose.yml` + `nginx.conf` из репо
- `cp auth.toml.example auth.toml`, вписать реальный Gitea token + `board_viewer_repos` list
- `cp .env.example .env`, сгенерировать `htpasswd -nbB viewer 'PASS'`, escape каждый `$``$$`, вписать в `BOARD_VIEWER_USERS`
- `chmod 600 auth.toml .env`
- [ ] `sudo docker compose pull && sudo docker compose up -d`
- [ ] **Smoke:**
- `curl -I https://board.kzntsv.site/` → 401
- `curl -I -u viewer:'PASS' https://board.kzntsv.site/` → 200
- `sudo docker compose logs --tail=200 build` → видна строка `wrote /output/index.html (N records from M repos)`
## Acceptance criteria
- DNS `board.kzntsv.site` резолвится в VDS IP
- Traefik route на `board.kzntsv.site` с basic-auth middleware (creds из `.env`)
- Build-контейнер крутится без рестартов, каждые `BOARD_TICK_SEC` (default 300s) обновляет `/output/index.html`
- Web-контейнер раздаёт `dist/` через nginx; 401 без креды, 200 с
- В password manager сохранены: `viewer` password + Gitea token (на случай DR)
## Decisions log
- 2026-05-22: ownership transferred from `~/projects/board-viewer/.tasks/[board-viewer-cron-deploy]` (dev-проект, code-complete) на `.admin/.tasks/` per новое правило workshop CLAUDE.md §5 (domain-промоушены с ops-acceptance → target=.admin). Slug изменён `cron-deploy``vds-deploy` для cross-project ясности.
## Notes
- Mechanism — docker-compose stack (не systemd timer); гомогенно с existing VDS pattern (Gitea, registry, ntfy). Cron-loop = `while true; do node cli.ts; sleep ${BOARD_TICK_SEC}; done` внутри build-контейнера.
- Rate-limit: 4 repos × ~2 Gitea API calls каждые 5 мин = ~24-100 calls/period, токенизированный Gitea не упрётся.
- DR-сценарий — см. `deploy/README.md` секция «Disaster recovery». No persistent state — каждый render fresh из Gitea.
<!-- created-by: OpeItcLoc03@DESKTOP-NSEF0UK / from: .workshop / 2026-05-22 / handoff: board-viewer/.tasks/board-viewer-cron-deploy.md -->