promote: workshop/board-viewer brainstorm → concepts + 5 tasks
- concepts/board-viewer.md (design, promoted from .workshop) - .tasks/STATUS.md + 5 per-task files: - board-viewer-pointers (pre-impl, status=ready) - board-viewer-gitea-reader (impl, TDD, status=ready) - board-viewer-html-render (impl, TDD, blocker=gitea-reader) - board-viewer-cron-deploy (impl, infra carve-out, blocker=html-render) - board-viewer-review (umbrella, status=blocked) TDD-mode embedded in impl-tasks per follow tdd-criteria trigger in CLAUDE.md. MCP write-side workaround per memory reference_projects_meta_resolveTarget_bug.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,21 +1,51 @@
|
|||||||
# Task Board
|
# Task Board
|
||||||
_Updated: 2026-05-22_
|
_Updated: 2026-05-22_
|
||||||
|
|
||||||
|
## ⚪ [board-viewer-pointers] — pre-impl: fill Domain conventions with design-context pointers
|
||||||
|
**Status:** ready
|
||||||
|
**Where I stopped:** только что промочен дизайн из `.workshop/.brainstorm/board-viewer.md` в `concepts/board-viewer.md`; `.wiki/CLAUDE.md` ещё содержит дефолтный setup-wiki stub в Domain conventions, без ссылок на дизайн.
|
||||||
|
**Next action:** вставить блок «Mandatory: read design context before implementation» в `.wiki/CLAUDE.md` Domain conventions (готовый текст в `board-viewer-pointers.md`), коммит `wiki(claude): add design-context pointers for board-viewer`, push.
|
||||||
|
**Branch:** master
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚪ [board-viewer-gitea-reader] — Gitea API reader → normalized task structure
|
||||||
|
**Status:** ready
|
||||||
|
**Where I stopped:** дизайн зафиксирован, реализация не начата. Это первая импл-таска, остальные impl-таски зависят от её типов.
|
||||||
|
**Next action:** прочитать `board-viewer-pointers.md` next-action блок → выполнить `board-viewer-pointers` сначала; затем стартовать с TDD по контракту в `board-viewer-gitea-reader.md`.
|
||||||
|
**Blocker:** board-viewer-pointers (нет Domain conventions с указанием на спецификацию)
|
||||||
|
**Branch:** master
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚪ [board-viewer-html-render] — render 5-col kanban from normalized structure
|
||||||
|
**Status:** ready
|
||||||
|
**Where I stopped:** ждёт `board-viewer-gitea-reader` (использует его типы).
|
||||||
|
**Next action:** после ready-стейта reader'а — TDD по контракту в `board-viewer-html-render.md`.
|
||||||
|
**Blocker:** board-viewer-gitea-reader
|
||||||
|
**Branch:** master
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚪ [board-viewer-cron-deploy] — systemd timer + traefik + DNS on VDS
|
||||||
|
**Status:** ready
|
||||||
|
**Where I stopped:** ждёт `board-viewer-html-render` (нужен артефакт для деплоя).
|
||||||
|
**Next action:** после готового HTML-рендера — добавить traefik label, DNS A-запись `board.kzntsv.site`, systemd timer на ~5 мин, basic-auth через traefik. См. `board-viewer-cron-deploy.md`.
|
||||||
|
**Blocker:** board-viewer-html-render
|
||||||
|
**Branch:** master
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔵 [board-viewer-review] — review checkpoint (umbrella)
|
||||||
|
**Status:** blocked
|
||||||
|
**Where I stopped:** дизайн зафиксирован, импл ещё не начата.
|
||||||
|
**Next action:** дождаться 🟢 у всех blocker-тасок (включая `board-viewer-pointers`). Прочитать спецификацию `.wiki/concepts/board-viewer.md`. Для каждой импл-таски: `git log --oneline`, прогнать тесты, сверить с acceptance criteria. Findings → follow-up tasks через `mcp__projects-meta__tasks_create`.
|
||||||
|
**Blocker:** board-viewer-pointers; board-viewer-gitea-reader; board-viewer-html-render; board-viewer-cron-deploy
|
||||||
|
**Branch:** master
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Add one block per task, sorted by priority. Use the emoji status legend below.
|
|
||||||
Per-task deep context lives in .tasks/<task-slug>.md (created on demand by using-tasks).
|
|
||||||
|
|
||||||
Block format:
|
|
||||||
|
|
||||||
## 🔴 [task-slug] — short description
|
|
||||||
**Status:** active
|
|
||||||
**Where I stopped:** one sentence — the exact thought or action interrupted
|
|
||||||
**Next action:** one concrete step to resume immediately
|
|
||||||
**Blocker:** (only if blocked) what is preventing progress
|
|
||||||
**Branch:** git branch name
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Status legend:
|
Status legend:
|
||||||
🔴 Active — only one at a time
|
🔴 Active — only one at a time
|
||||||
🟡 Paused — in progress, resumable
|
🟡 Paused — in progress, resumable
|
||||||
|
|||||||
44
.tasks/board-viewer-cron-deploy.md
Normal file
44
.tasks/board-viewer-cron-deploy.md
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
# 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
|
||||||
|
|
||||||
|
- (TBD) `deploy/board-viewer.service` — systemd one-shot unit (runs reader + render → writes to `/var/www/board-viewer/`)
|
||||||
|
- (TBD) `deploy/board-viewer.timer` — systemd timer (OnUnitActiveSec=5min)
|
||||||
|
- (TBD) `deploy/docker-compose.yml` фрагмент или `deploy/traefik-labels.yaml` — traefik label для статики
|
||||||
|
- (TBD) `deploy/README.md` — install steps + DNS record requirements
|
||||||
|
- (TBD) `deploy/auth/htpasswd` — basic-auth credentials (gitignored, with `.htpasswd.example`)
|
||||||
|
|
||||||
|
## 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 (фиксировано в дизайне).
|
||||||
|
|
||||||
|
## Open questions
|
||||||
|
|
||||||
|
- [ ] Хост: VDS Rusonyx (тот, где уже Gitea + traefik) или отдельная машина? — VDS, рядом с git.kzntsv.site (см. дизайн).
|
||||||
|
- [ ] Multi-user basic-auth или single creds? — пока single, поскольку single-user проект.
|
||||||
|
- [ ] Rate-limit на Gitea API: 5-мин тик * N репо * M файлов — оценить, не упрётся ли. Gitea дефолт ~60 req/min anon, токенизированный сильно выше — должно хватить с запасом.
|
||||||
|
|
||||||
|
## Completed steps
|
||||||
|
|
||||||
|
- [ ] (фиксируется при выполнении)
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
Зависит от `board-viewer-html-render` — нужен артефакт для деплоя (хотя бы placeholder). Можно стартовать параллельно с DNS-записью (она прогревается).
|
||||||
59
.tasks/board-viewer-gitea-reader.md
Normal file
59
.tasks/board-viewer-gitea-reader.md
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
# board-viewer-gitea-reader
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
|
||||||
|
Модуль, который через Gitea API читает `.tasks/STATUS.md` + per-task `<slug>.md` файлы из всех релевантных репо (`OpeItcLoc03/agenda` + per-project репо из `~/.config/projects-mcp/auth.toml::gitea_owners`) и нормализует в типизированную структуру для рендера.
|
||||||
|
|
||||||
|
Это первая импл-таска. Остальные импл-таски (`board-viewer-html-render`, `board-viewer-cron-deploy`) зависят от типов, которые этот модуль публикует.
|
||||||
|
|
||||||
|
**TDD-mode:** обязательно по `follow tdd-criteria` триггеру в `.wiki/CLAUDE.md`. Сначала тесты на нормализацию пар фикстур (STATUS.md + per-task.md) → потом реализация. Не модифицировать assert'ы во время реализации без `[test-modify: ...]` маркера в commit subject.
|
||||||
|
|
||||||
|
## Key files
|
||||||
|
|
||||||
|
- (TBD) `src/gitea-reader.{ts,py}` — main reader module
|
||||||
|
- (TBD) `src/types.{ts,py}` — exported task structure
|
||||||
|
- (TBD) `tests/fixtures/` — sample STATUS.md + per-task.md pairs from real repos
|
||||||
|
- (TBD) `tests/gitea-reader.test.{ts,py}` — TDD assertions
|
||||||
|
|
||||||
|
## Acceptance criteria
|
||||||
|
|
||||||
|
- **Output contract:** массив объектов с полями:
|
||||||
|
```
|
||||||
|
{
|
||||||
|
slug: string,
|
||||||
|
project: string, // repo name (e.g. "board-viewer", "books")
|
||||||
|
project_owner: string, // gitea owner (e.g. "OpeItcLoc03")
|
||||||
|
status: "open" | "in_progress" | "paused" | "blocked" | "done",
|
||||||
|
status_emoji: "⚪" | "🟡" | "🟣" | "🔴" | "🟢",
|
||||||
|
title: string, // from STATUS.md block H2 after slug
|
||||||
|
where_stopped: string | null,
|
||||||
|
next_action: string | null,
|
||||||
|
blocker: string | null,
|
||||||
|
branch: string | null,
|
||||||
|
last_commit_iso: string | null, // from Gitea API, latest commit touching the task file
|
||||||
|
raw_url: string, // Gitea raw URL to per-task <slug>.md for drawer lazy-fetch
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- **Inputs:** список репо из конфига (env var или TOML).
|
||||||
|
- **Auth:** Gitea token из `~/.config/projects-mcp/auth.toml::gitea_token` (admin scope, читает любой репо).
|
||||||
|
- **Robustness:** репо без `.tasks/` → пропустить молча (не ошибка). `.tasks/STATUS.md` без emoji-блоков → пустой массив для этого проекта.
|
||||||
|
- **Tests:** фикстуры из ≥3 реальных репо (board-viewer, books, .workshop), assertions покрывают: нормальный case, status без per-task.md (только STATUS.md block), per-task без записи в STATUS.md (legacy), blocked-таски с `Blocker:` строкой.
|
||||||
|
- **Single language:** один из TS / Python. Выбор — за имплементером (TS легче переиспользует с HTML-рендером в одном процессе; Python проще читать конфиг).
|
||||||
|
|
||||||
|
## Decisions log
|
||||||
|
|
||||||
|
- 2026-05-22: task создан промоушеном; контракт фиксирован — это публичный API для html-render.
|
||||||
|
|
||||||
|
## Open questions
|
||||||
|
|
||||||
|
- [ ] TS or Python? (повлияет на структуру cron-deploy).
|
||||||
|
- [ ] Owner-фильтр: брать репо из `gitea_owners` целиком или whitelist? Возможно нужен `board_viewer_repos` отдельным полем в auth.toml.
|
||||||
|
- [ ] Кэшировать ответы Gitea API локально между cron-тиками? (опт.: rate-limit, hot-reload).
|
||||||
|
|
||||||
|
## Completed steps
|
||||||
|
|
||||||
|
- [ ] (фиксируется при выполнении)
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
NB: исходный буфер упоминал `mcp__projects-meta__tasks_aggregate` как возможный источник — **это ложная развилка**, MCP недоступен HTTP-сервису. Только прямой Gitea API. См. `.wiki/concepts/board-viewer.md` секцию «Implementation note».
|
||||||
48
.tasks/board-viewer-html-render.md
Normal file
48
.tasks/board-viewer-html-render.md
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
# board-viewer-html-render
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
|
||||||
|
Рендер 5-колоночного kanban-board из нормализованной структуры (продукт `board-viewer-gitea-reader`). Статический HTML + минимальный клиент-сайд JS для фильтра / drawer / refresh-таймера. Без write-side, без realtime.
|
||||||
|
|
||||||
|
**TDD-mode:** обязательно по `follow tdd-criteria`. Снапшот-тесты на HTML-output из фиксированных reader-фикстур. Не модифицировать assert'ы без `[test-modify: ...]` маркера. Визуальная отделка (CSS) — под carve-out «visual CSS», но логика рендера (распределение по колонкам, age-расчёт, drawer-привязка) — TDD.
|
||||||
|
|
||||||
|
## Key files
|
||||||
|
|
||||||
|
- (TBD) `src/render.{ts,py}` — main renderer
|
||||||
|
- (TBD) `templates/board.html` — template (Mustache / Jinja / template literals — выбор имплементера)
|
||||||
|
- (TBD) `static/board.css`, `static/board.js` — styling + filter/drawer client-side
|
||||||
|
- (TBD) `tests/render.test.{ts,py}` — snapshot tests
|
||||||
|
|
||||||
|
## Acceptance criteria
|
||||||
|
|
||||||
|
- **5 колонок** по статусам: ⚪ open / 🟡 in-progress / 🟣 paused / 🔴 blocked / 🟢 done. Названия колонок — emoji + слово.
|
||||||
|
- **Карточка:**
|
||||||
|
- title (truncate на 80 chars в default-view),
|
||||||
|
- project badge (e.g. `books`, `board-viewer`),
|
||||||
|
- owner (если есть) — pill,
|
||||||
|
- age — относительное (`3d`, `2w`, `5mo`) от `last_commit_iso`,
|
||||||
|
- last-commit-marker — короткий hash или дата.
|
||||||
|
- **Группировка по проекту** — toggle вверху: «по статусам» (5 колонок × проекты внутри) vs «по проектам» (per-project колонки × статусы внутри).
|
||||||
|
- **Поиск/фильтр** — клиент-сайд input: substring по `slug`, `title`, `project`; multi-select по статусам.
|
||||||
|
- **Per-card drawer** — клик по карточке → side panel с full markdown из per-task `<slug>.md` (lazy-fetch из `raw_url`). Markdown рендерится клиент-сайд (e.g. `marked` для TS, `markdown-it` для Py-side-rendered).
|
||||||
|
- **Refresh-таймер** видно в header: «refreshed Xm ago, next in Ym» (data attribute из generation timestamp).
|
||||||
|
- **Output:** один `index.html` файл + sidecar `static/`. Открывается локально без сервера для smoke-test.
|
||||||
|
- **Tests:** snapshot-тесты на 3 reader-фикстуры (пустая доска / 1-2 таски / N≥10 тасок). Snapshots checked-in.
|
||||||
|
|
||||||
|
## Decisions log
|
||||||
|
|
||||||
|
- 2026-05-22: task создан промоушеном; зависит от `board-viewer-gitea-reader` контракта.
|
||||||
|
|
||||||
|
## Open questions
|
||||||
|
|
||||||
|
- [ ] Markdown-renderer: client-side (`marked`) или server-side (Jinja с pre-rendered HTML вшито в data-attr)? Client-side проще — но добавляет ~50KB JS.
|
||||||
|
- [ ] CSS framework: ничего (raw CSS) / Pico / Tailwind via CDN? Минимализм — за raw. Раздёргать через первый прототип.
|
||||||
|
- [ ] Архивные таски (🟢 done старше N дней) скрывать по умолчанию? Toggle?
|
||||||
|
|
||||||
|
## Completed steps
|
||||||
|
|
||||||
|
- [ ] (фиксируется при выполнении)
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
Стиль: минимализм без аватарок/гифок/анимаций. Это инструмент глядеть на доску, не дашборд для презентации. Whitespace + типографика.
|
||||||
57
.tasks/board-viewer-pointers.md
Normal file
57
.tasks/board-viewer-pointers.md
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
# board-viewer-pointers
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
|
||||||
|
Pre-impl bootstrap: заполнить `.wiki/CLAUDE.md` секцию «Domain conventions» pointer-блоком на спецификацию. Дизайн не лежит в этом репо целиком — только pointer-stub. Без этой таски следующий агент попадёт в дыру: dense `where_stopped` one-liner + пустой Domain conventions stub = угадывание архитектуры вместо чтения готовых решений.
|
||||||
|
|
||||||
|
**Кто делает:** любой следующий агент в этом проекте. Это **первая** по приоритету таска промоушена — все импл-таски ссылаются на pointers через `.wiki/CLAUDE.md`.
|
||||||
|
|
||||||
|
## Key files
|
||||||
|
|
||||||
|
- `.wiki/CLAUDE.md` — Domain conventions section
|
||||||
|
- `.wiki/concepts/board-viewer.md` — canonical design (target of pointer)
|
||||||
|
- `~/projects/.workshop/.archive/2026-05-22-board-viewer.md` — brainstorm rationale (target of pointer)
|
||||||
|
|
||||||
|
## Acceptance criteria
|
||||||
|
|
||||||
|
- `.wiki/CLAUDE.md` содержит блок «Mandatory: read design context before implementation» в Domain conventions (см. Next action ниже — дословный текст).
|
||||||
|
- Коммит с message `wiki(claude): add design-context pointers for board-viewer`.
|
||||||
|
- Push в `origin/master`.
|
||||||
|
|
||||||
|
## Next action (готовый блок для копирования в `.wiki/CLAUDE.md` Domain conventions)
|
||||||
|
|
||||||
|
Заменить существующий комментарий-stub в секции `## Domain conventions` на следующий блок:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
### 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 fully — only pointers do. Sources, in order:
|
||||||
|
|
||||||
|
1. **Canonical design:** `.wiki/concepts/board-viewer.md`. Architecture decisions, scope, MVP feature list, anti-patterns (hermes-style, Gitea Projects), trade-offs.
|
||||||
|
2. **Brainstorm process trace (rationale):** `~/projects/.workshop/.archive/2026-05-22-board-viewer.md`. Why each decision was made, what was rejected and why, clarifying note that `mcp__projects-meta__*` is not callable from HTTP service.
|
||||||
|
3. **Local `overview.md`** — quick orientation summary; never source of truth.
|
||||||
|
|
||||||
|
Do **not** invent thresholds, taxonomies, container topology, or pipeline stages from task `where_stopped` lines alone — those are pointers, not specifications.
|
||||||
|
|
||||||
|
### TDD posture
|
||||||
|
|
||||||
|
Per `follow tdd-criteria` trigger in this CLAUDE.md: impl-tasks `board-viewer-gitea-reader` and `board-viewer-html-render` are TDD. `board-viewer-cron-deploy` falls under the infrastructure carve-out (declarative systemd / traefik / DNS — verify by deploy + curl, not unit tests). Mark each impl commit accordingly.
|
||||||
|
```
|
||||||
|
|
||||||
|
После вставки: коммит, push.
|
||||||
|
|
||||||
|
## Decisions log
|
||||||
|
|
||||||
|
- 2026-05-22: pointers task создан промоушеном из `.workshop/.brainstorm/board-viewer.md` (workshop-promote-brainstorm).
|
||||||
|
|
||||||
|
## Open questions
|
||||||
|
|
||||||
|
- [ ] (нет — pointer-блок самодостаточен)
|
||||||
|
|
||||||
|
## Completed steps
|
||||||
|
|
||||||
|
- [ ] (фиксируется при выполнении)
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
Pointer-таска намеренно тривиальная — её существование защищает следующего агента от чтения stub'а вместо спецификации. Не объединять с импл-тасками.
|
||||||
54
.tasks/board-viewer-review.md
Normal file
54
.tasks/board-viewer-review.md
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
# board-viewer-review
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
|
||||||
|
Code-review checkpoint для брейнсторма `board-viewer` (промоушен 2026-05-22).
|
||||||
|
|
||||||
|
**Спецификация:** `.wiki/concepts/board-viewer.md`.
|
||||||
|
**Pre-impl bootstrap:** `board-viewer-pointers` (заполнил `.wiki/CLAUDE.md` Domain conventions — без него review бы читал stub).
|
||||||
|
**Импл-таски (review против их acceptance criteria):** `board-viewer-gitea-reader`, `board-viewer-html-render`, `board-viewer-cron-deploy`.
|
||||||
|
|
||||||
|
**Кто делает:** **не имплементер.** Следующая сессия в этом проекте (другая модель / другой день / другой агент) поднимает таску с чистым контекстом. «Я только что это написал» bias = главный риск.
|
||||||
|
|
||||||
|
## Key files
|
||||||
|
|
||||||
|
- `.wiki/concepts/board-viewer.md` — canonical design
|
||||||
|
- `.tasks/board-viewer-*.md` — acceptance criteria per impl-task
|
||||||
|
- `~/projects/.workshop/.archive/2026-05-22-board-viewer.md` — brainstorm rationale
|
||||||
|
|
||||||
|
## Acceptance criteria (для самого ревью)
|
||||||
|
|
||||||
|
- Прочитана спецификация целиком.
|
||||||
|
- `git log --oneline` shipped-коммитов (по slug или scope в commit-message) сверен с acceptance criteria каждой импл-таски.
|
||||||
|
- Для каждой импл-таски: прогнан соответствующий тест-suite, проверено что тесты реально доходят до своих веток (не coverage-illusion).
|
||||||
|
- Сверены дизайн-decisions со shipped-кодом: контракт reader → render, статика + cron на VDS, отсутствие write-side.
|
||||||
|
- Findings зафайлены как follow-up tasks (`board-viewer-<gap>-fix` или подобное) через `mcp__projects-meta__tasks_create`, либо ревьюер подтвердил «нет findings» в close-note.
|
||||||
|
|
||||||
|
## Чек-лист ревью (poll-выполнения)
|
||||||
|
|
||||||
|
- [ ] reader: контракт публичных полей сохранён (не сужен, не расширен молча)
|
||||||
|
- [ ] reader: фикстуры покрывают edge cases (legacy без per-task.md, blocked с blocker-строкой)
|
||||||
|
- [ ] render: snapshot-тесты обновлены вместе с изменениями (не закоммичен код без апдейта snapshot)
|
||||||
|
- [ ] render: визуально не AI-generic, минимализм соблюдён
|
||||||
|
- [ ] cron-deploy: systemd unit + timer проверены `systemctl status`, не только запущены
|
||||||
|
- [ ] cron-deploy: basic-auth проверена `curl` с верными / неверными кредами
|
||||||
|
- [ ] auth scope: пушится ли токен в публичный репо случайно? (`grep -r "02a14e" deploy/` должен быть пуст)
|
||||||
|
- [ ] disaster recovery: README.md в deploy/ достаточен чтобы поднять с нуля?
|
||||||
|
|
||||||
|
## Decisions log
|
||||||
|
|
||||||
|
- 2026-05-22: review-task создан промоушеном; status=blocked, blocker = все 4 импл-таски.
|
||||||
|
|
||||||
|
## Open questions
|
||||||
|
|
||||||
|
- [ ] (заполняется ревьюером по ходу)
|
||||||
|
|
||||||
|
## Completed steps
|
||||||
|
|
||||||
|
- [ ] (фиксируется при выполнении)
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
**Закрытие:** только когда все findings зафайлены ИЛИ ревьюер подтвердил «нет findings» в close-note.
|
||||||
|
|
||||||
|
**TDD-immutability:** если ревью обнаружит модифицированные assert'ы без `[test-modify: ...]` маркера в commit subject — это нарушение `follow tdd-criteria`, finding обязателен.
|
||||||
105
.wiki/concepts/board-viewer.md
Normal file
105
.wiki/concepts/board-viewer.md
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
---
|
||||||
|
title: Board viewer — design
|
||||||
|
type: concept
|
||||||
|
date: 2026-05-22
|
||||||
|
status: promoted
|
||||||
|
source: .workshop/.archive/2026-05-22-board-viewer.md
|
||||||
|
sources:
|
||||||
|
- https://hermes-agent.nousresearch.com/docs/user-guide/features/kanban
|
||||||
|
- https://hermes-agent.nousresearch.com/docs/user-guide/features/kanban-tutorial
|
||||||
|
- .tasks/STATUS.md per-project emoji-словарь (⚪🟡🟣🔴🟢)
|
||||||
|
- mcp__projects-meta__tasks_aggregate (текстовый кросс-проектный вид)
|
||||||
|
---
|
||||||
|
|
||||||
|
# Board viewer — визуал прогресса по таскам
|
||||||
|
|
||||||
|
## Контекст
|
||||||
|
|
||||||
|
Сейчас визуала прогресса по таскам нет — есть только текстовые формы: `.tasks/STATUS.md` per-project с emoji-легендой (⚪ open / 🟡 in-progress / 🟣 paused / 🔴 blocked / 🟢 done) и `mcp__projects-meta__tasks_aggregate` поверх Gitea-репо `OpeItcLoc03/agenda`. Цель — визуальная kanban-доска для глаз.
|
||||||
|
|
||||||
|
## Что увидено у hermes-agent
|
||||||
|
|
||||||
|
Их kanban — не «доска», а **execution engine**:
|
||||||
|
|
||||||
|
- SQLite-DB `~/.hermes/kanban.db` как SoT.
|
||||||
|
- 6 колонок: `triage / todo / ready / running / blocked / done` (+ `archived`).
|
||||||
|
- Dispatcher каждые 60s спавнит workers, workers общаются с доской через тулсы (`kanban_show`, `kanban_heartbeat`, `kanban_complete`, `kanban_block`).
|
||||||
|
- Decomposer auto-fans `triage` → `todo` через специальный профиль.
|
||||||
|
- Circuit-breaker: 2 фейла подряд → auto-block.
|
||||||
|
- Web-dashboard с drag-drop, multi-select, run-history per task.
|
||||||
|
- CLI: `hermes kanban create/show/runs/decompose/watch/notify-subscribe`.
|
||||||
|
- REST API `/api/plugins/kanban/`.
|
||||||
|
- Single-host by design (cite: «~/.hermes/kanban.db is a local SQLite file ... Running a shared board across two hosts is not supported»).
|
||||||
|
|
||||||
|
Это **мультиагентский оркестратор**, где kanban — UI-слой. **Это другой кейс**, чем наш — выделили в отдельный буфер `agent-orchestration-without-user.md` (там идёт самостоятельное обсуждение).
|
||||||
|
|
||||||
|
## Решение: read-only HTML kanban-viewer над Gitea API, хостинг на VDS
|
||||||
|
|
||||||
|
**Что:** маленький HTTP-сервис на VDS (рядом с Gitea, traefik уже там), который читает Gitea API напрямую (`OpeItcLoc03/agenda` + per-project репо) и рендерит 5-колоночную доску по emoji-словарю: ⚪ open / 🟡 in-progress / 🟣 paused / 🔴 blocked / 🟢 done.
|
||||||
|
|
||||||
|
**Где:** домен `board.kzntsv.site` за traefik, рядом с `git.kzntsv.site`.
|
||||||
|
|
||||||
|
**Как обновляется:** cron-тик каждые ~5 мин, перегенерация статической HTML. Realtime не нужен — таски меняются раз в сессию.
|
||||||
|
|
||||||
|
**SoT не меняется:** `.tasks/<slug>.md` + `STATUS.md` в каждом проекте, Gitea `agenda` репо как backend. Markdown остаётся grep-able, git-blameable, скилы `using-tasks`/`setup-tasks` не ломаются.
|
||||||
|
|
||||||
|
**Размер:** ~200-300 LOC сервис + traefik label + cron-таймер.
|
||||||
|
|
||||||
|
## Implementation note — почему Gitea API, а не MCP
|
||||||
|
|
||||||
|
В исходном брейнсторме предполагалось «дергает `mcp__projects-meta__tasks_aggregate` или читает Gitea API напрямую». **Это ложная развилка:** `mcp__projects-meta__*` доступен только внутри Claude Code-контекста, у HTTP-сервиса этой шины нет. Реальный единственный путь — **прямой Gitea API** (`GET /api/v1/repos/OpeItcLoc03/agenda/contents/...`) с тем же admin-токеном из `~/.config/projects-mcp/auth.toml`. По сути — переписываем кусок логики `tasks_aggregate` поверх HTTP, не «дёргаем готовое».
|
||||||
|
|
||||||
|
## Почему не hermes-стиль
|
||||||
|
|
||||||
|
Hermes kanban — это execution engine. Dispatcher спавнит workers, агенты heartbeat'ят, circuit-breaker блокирует таску после 2 фейлов, decomposer фанаут'ит triage→todo автоматически. Это нужно когда у тебя автономный fleet агентов работает без человека. У нас другой паттерн: **визуальный прогресс** ≠ оркестрация. Импортировать их dispatcher/worker модель ради UI-слоя — купить большой движок ради картинки.
|
||||||
|
|
||||||
|
Тема «автономные cross-project агенты» обсуждается отдельно в `agent-orchestration-without-user.md`. Если она дойдёт до промоушена — там может появиться execution engine, и viewer станет естественной мордой к нему. **Viewer от него не зависит**: над `.tasks/*.md` он работает уже сейчас.
|
||||||
|
|
||||||
|
## Почему не Gitea Projects
|
||||||
|
|
||||||
|
Gitea Projects работает поверх **issues** одного репо. Чтобы он стал нашей доской — надо мигрировать `.tasks/<slug>.md` → Gitea issues как первичный носитель. Цена:
|
||||||
|
|
||||||
|
- ❌ убивается markdown grep по проекту,
|
||||||
|
- ❌ ломаются скилы `using-tasks`/`setup-tasks`, которые ждут per-task `.md` файлы,
|
||||||
|
- ❌ git-история per-task переезжает в БД Gitea, не в `git log`.
|
||||||
|
|
||||||
|
Слишком высокая цена ради drag-drop.
|
||||||
|
|
||||||
|
## Trade-offs честно
|
||||||
|
|
||||||
|
| Минус | Что значит |
|
||||||
|
|---|---|
|
||||||
|
| read-only | drag-drop статуса нет; меняем через редактирование `.md` (как сейчас) |
|
||||||
|
| 5-мин лаг | не realtime; ок для таск-доски, не ок для лога инцидентов |
|
||||||
|
| зависит от Gitea API | если Gitea упадёт — доска показывает stale (но это уже catastrophic incident) |
|
||||||
|
|
||||||
|
Drag-drop **разблокируется автоматически** когда починим `projects-meta` write-side bug cluster — см. memory `reference_projects_meta_resolveTarget_bug.md`. Это уже в плане работ по `projects-meta`, не блокер этого проекта.
|
||||||
|
|
||||||
|
## Что внутри viewer'а — MVP
|
||||||
|
|
||||||
|
- **5-колоночный board** по статусам (без `triage`/`ready` — наш словарь иной).
|
||||||
|
- **Карточка таски:** title, проект, owner (если есть), age (since open), последний коммит-маркер.
|
||||||
|
- **Группировка по проекту** опционально (toggle «по статусам vs по проектам»).
|
||||||
|
- **Поиск/фильтр** по проекту, тегам, owner'у — клиент-сайд JS (нет API за пределами initial-load).
|
||||||
|
- **Per-card drawer** показывает full markdown из `<slug>.md` (lazy-fetch из Gitea raw).
|
||||||
|
- **Refresh-таймер** видно на странице.
|
||||||
|
|
||||||
|
Чего точно нет в MVP:
|
||||||
|
|
||||||
|
- write-side ничего (drag-drop, edit, create);
|
||||||
|
- realtime обновления (WS, SSE);
|
||||||
|
- multi-tenant (пока один юзер);
|
||||||
|
- auth (это traefik basic-auth, не in-app);
|
||||||
|
- run history (это уровень оркестратора, не viewer'а).
|
||||||
|
|
||||||
|
## Зависимости
|
||||||
|
|
||||||
|
- Прямой read Gitea API к `OpeItcLoc03/agenda` + per-project репо — **уже работает**.
|
||||||
|
- traefik route + DNS на `board.kzntsv.site` — стандартная инфра VDS.
|
||||||
|
- cron tick — systemd timer или `vds-job-scheduler` (если поднимем) — на выбор при имплементации.
|
||||||
|
|
||||||
|
Ничего блокирующего.
|
||||||
|
|
||||||
|
## Связь с `agent-orchestration-without-user.md`
|
||||||
|
|
||||||
|
Viewer — независимый артефакт. Он читает текущий `.tasks/*.md` SoT, и продолжит работать как-есть после промоушена оркестратора (тот добавляет поля типа `owner`, `claim_token` — viewer просто отрендерит их в карточке). **Не блокируется ничем из orchestration-брейнсторма**, не блокирует его.
|
||||||
@@ -12,7 +12,8 @@ Catalog of all wiki pages. One line per page, organized by type. Updated on ever
|
|||||||
|
|
||||||
## Concepts
|
## Concepts
|
||||||
|
|
||||||
<!-- (none yet) -->
|
- [board-viewer.md](concepts/board-viewer.md) — design: read-only HTML kanban-viewer over Gitea API
|
||||||
|
- [bootstrap-manifest.md](concepts/bootstrap-manifest.md) — skill versions used to bootstrap layout
|
||||||
|
|
||||||
## Packages
|
## Packages
|
||||||
|
|
||||||
|
|||||||
@@ -13,3 +13,4 @@ Parseable: `grep "^## \[" .wiki/log.md | tail -20`.
|
|||||||
---
|
---
|
||||||
|
|
||||||
## [2026-05-22] init | wiki bootstrapped via setup-wiki@1.0.0
|
## [2026-05-22] init | wiki bootstrapped via setup-wiki@1.0.0
|
||||||
|
## [2026-05-22] ingest | promoted .workshop/.brainstorm/board-viewer.md → concepts/board-viewer.md
|
||||||
|
|||||||
Reference in New Issue
Block a user