62 lines
4.4 KiB
Markdown
62 lines
4.4 KiB
Markdown
# board-viewer-cron-deploy
|
||
|
||
## Goal
|
||
|
||
Деплой статической HTML-доски на VDS под доменом `board.kzntsv.site`. Periodic regen через systemd timer ~5 мин. Traefik label для роутинга. DNS A-запись. Basic-auth через traefik (не in-app).
|
||
|
||
**TDD posture:** под carve-out «infrastructure / declarative» из `tdd-criteria`. Acceptance проверяется по факту deploy + curl, не unit-тестами. systemd unit-файлы и traefik labels — декларативные конфиги, не код.
|
||
|
||
## Key files
|
||
|
||
- `deploy/docker-compose.yml` — двухсервисный стек (build + web) на `proxy` network
|
||
- `deploy/Dockerfile.build` — build-image (node:22-alpine + cron-loop entrypoint)
|
||
- `deploy/nginx.conf` — static serving с Cache-Control
|
||
- `deploy/auth.toml.example` — шаблон Gitea token + board_viewer_repos
|
||
- `deploy/.env.example` — шаблон BOARD_VIEWER_USERS с правилом `$$` escape
|
||
- `deploy/README.md` — DNS / image build / bootstrap / smoke / DR steps
|
||
|
||
**Замечание:** acceptance изначально упоминал systemd timer, но user выбрал docker-compose stack (consistent с существующим VDS pattern Gitea/registry/etc.). Mechanism: `while true; do node cli.ts; sleep 300; done` внутри `board-viewer-build` контейнера. Логи через `docker compose logs`, не journalctl. Эффект тот же — каждые 5 мин regen.
|
||
|
||
## Acceptance criteria
|
||
|
||
- DNS `board.kzntsv.site` → VDS IP (Cloudflare / namecheap / wherever DNS живёт).
|
||
- Traefik route: `board.kzntsv.site` → static file serving из `/var/www/board-viewer/`.
|
||
- Basic-auth на traefik (middleware), креды из `.htpasswd`.
|
||
- systemd timer крутится каждые 5 мин, успешно дёргает reader + render, пишет в `/var/www/board-viewer/index.html`.
|
||
- Логи systemd видны через `journalctl -u board-viewer.service`.
|
||
- Health check: `curl -u user:pass https://board.kzntsv.site/` → HTML с актуальной доской.
|
||
- README.md описывает install steps (для disaster-recovery: «как поднять с нуля на новой машине»).
|
||
|
||
## Decisions log
|
||
|
||
- 2026-05-22: task создан промоушеном; carve-out из TDD под инфра (declarative configs).
|
||
- 2026-05-22: auth = traefik basic-auth, не in-app (фиксировано в дизайне).
|
||
- 2026-05-22: deploy-mechanism = docker-compose stack (рекомендация принята); systemd timer заменён на cron-loop внутри build container'а. Гомогенно с existing VDS pattern (Gitea, registry, ntfy).
|
||
- 2026-05-22: basicauth.users inline через env_file, `$$` escape для compose interpolation. Не нужно касаться traefik stack'а (mounting htpasswd в traefik потребовало бы изменения соседнего стека).
|
||
|
||
## Open questions
|
||
|
||
- [x] Host: VDS Rusonyx (тот же, где Gitea+traefik). Network `proxy`, путь `/opt/stacks/board-viewer/` — verified via vds-ops inspect of gitea container.
|
||
- [x] Multi-user basic-auth: схема поддерживает (comma-separated), но MVP — single user.
|
||
- [x] Rate-limit: 4 repos × ~2 calls/repo (STATUS.md fetch + commit log per task slug) каждые 5 мин = ~24-100 calls. Token'изированный Gitea не упрётся.
|
||
|
||
## Completed steps
|
||
|
||
- [x] docker-compose.yml с двумя сервисами и traefik labels
|
||
- [x] Dockerfile.build для cron-loop image
|
||
- [x] nginx.conf для static serving
|
||
- [x] auth.toml.example + .env.example + README.md с полным install path
|
||
- [x] .gitignore исключает реальные `auth.toml` и `.env`
|
||
- [x] compose syntax validated via `docker compose config`
|
||
|
||
## Pending (user-side actions)
|
||
|
||
- [ ] DNS A-record `board.kzntsv.site` → VDS IP
|
||
- [ ] `docker build && docker push` на dev-машине → `registry.kzntsv.site/board-viewer-build:latest`
|
||
- [ ] Bootstrap `/opt/stacks/board-viewer/` на VDS + заполнить `auth.toml` и `.env`
|
||
- [ ] `docker compose up -d` + smoke `curl -u user:pass https://board.kzntsv.site/`
|
||
|
||
## Notes
|
||
|
||
Зависит от `board-viewer-html-render` — нужен артефакт для деплоя (хотя бы placeholder). Можно стартовать параллельно с DNS-записью (она прогревается).
|