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-проекте.
4.1 KiB
4.1 KiB
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— стек наproxynetwork, traefik labelsdeploy/Dockerfile.build— node:22-alpine + cron-loop entrypointdeploy/nginx.conf— static serving + Cache-Controldeploy/auth.toml.example— шаблон Gitea token + repo whitelistdeploy/.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_reposlistcp .env.example .env, сгенерироватьhtpasswd -nbB viewer 'PASS', escape каждый$→$$, вписать вBOARD_VIEWER_USERSchmod 600 auth.toml .env
- скопировать
sudo docker compose pull && sudo docker compose up -d- Smoke:
curl -I https://board.kzntsv.site/→ 401curl -I -u viewer:'PASS' https://board.kzntsv.site/→ 200sudo 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 сохранены:
viewerpassword + 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.