Files
board-viewer/.tasks/board-viewer-drawer-bundle-md.md
vitya cfa4572731 tasks: round1 UX feedback — 6 dev-tasks + review umbrella [board-viewer-ux-round1-review]
User первые впечатления после go-live board.kzntsv.site:
- drawer падает TypeError (приватные репо + no browser token; bundle md
  в build-time — единственно верное решение)
- slug не виден на карточке (только в data-attr)
- дата без времени, неясный формат
- owner-pill дублируется (single-owner whitelist → visual noise)
- нет нумерации задач (BV-12 / T-001 shorthand нужен)
- done-tail слишком длинный (нужен render-side cutoff/collapse)

Все 6 — code-impl в board-viewer (не deploy → не в .admin, per workshop §5).
TDD posture везде (project follow tdd-criteria).

Drawer bug = critical (clear-impl: bundle md в build-time, root-cause grounded).
Show-slug + full-datetime = clear-impl, простой TDD-цикл.
Owner-conditional = clear-impl (single vs multi owner branches), 2 fixtures.
Task-numbers + done-cutoff = design-first (4 open questions каждый),
brainstorm если recommendations не пройдут single-session.

+ review umbrella 🔵 blocked-by 6 slug'ами (workshop §4 mandatory).

Ops-handoff (rebuild image + Portainer pull) — отдельная taska в
.admin/[board-viewer-redeploy-ux-round1] (workshop §5).
2026-05-22 18:39:01 +03:00

4.2 KiB
Raw Blame History

board-viewer-drawer-bundle-md

Goal

Drawer падает с TypeError: Failed to fetch при клике на любую карточку. Root-cause: rawUrl указывает на git.kzntsv.site/<owner>/<repo>/raw/branch/<branch>/<path> — приватные репо требуют auth, в браузере токена нет (он только в build-контейнере для статической генерации, auth.toml ro-mounted). Browser fetch без Authorization → Gitea отдаёт 401 / 302→login HTML → fetch воспринимает как failure → TypeError.

Решение: bundle per-task md-content в build-time. Build-контейнер уже знает где per-task .md файлы (он их fetch'ит для парсинга), у него есть Gitea token. Расширить read-фазу: вместе с STATUS.md тянуть и per-task .md (если существует), складывать в dist/tasks-md.json или встраивать в <script type="application/json" id="tasks-md">…</script> в index.html. Drawer читает из этого локального data вместо fetch.

TDD posture

Mode = TDD (project CLAUDE.md имеет follow tdd-criteria). Failing test первым:

  • Unit: reader получает per-task md content параллельно с STATUS.md, кладёт в TaskRecord.md_content?: string
  • Render: каждая карточка имеет data-md-encoded или используется shared JSON-bundle с data-md-key={slug}
  • Drawer test (board.js): открывает draweр по data-key, читает из bundled JSON, рендерит через marked.parse — без fetch
  • E2E smoke: открыть локально dist/index.html в browser-driver (или mocked DOM), кликнуть карту → drawer показывает md content, не «Failed to load»

Key files

  • src/gitea.ts — добавить метод getRawContent(owner, repo, path) через API (/api/v1/repos/.../contents/+base64-decode или /api/v1/repos/.../raw/... с токеном)
  • src/reader.ts — расширить чтобы для каждого TaskRecord пулить per-task .md (если file exists)
  • src/render.ts:136 — добавить data-md-key вместо data-raw-url, либо встроить JSON-bundle в html
  • static/board.js:200-215openDrawer читает из localStorage / global var вместо fetch
  • tests/ — fixture для per-task md, новые тесты

Acceptance criteria

  • Все 49 текущих тестов всё ещё pass + новые тесты для md-bundle pipeline
  • E2E smoke на real board.kzntsv.site (live): клик на любую карту → drawer заполняется per-task content без network-запросов на git.kzntsv.site
  • DevTools Network: открыть карту → 0 запросов исходящих к git.kzntsv.site/raw
  • Размер index.html или tasks-md.json reasonable (предположительно <500 KB на 80 records — markdown текстовый, gzip сильно сожмёт)
  • Карты без per-task .md файла (status=ready без deep-context) — drawer показывает только title + status block, без «Failed to load»

Decisions log

  • 2026-05-22: создана из user UX-feedback round1 — drawer ломается с TypeError. Root-cause grounded: приватные репо + no browser token. Импл-направление = bundle, не proxy (proxy потребовал бы nginx с auth_request к board-viewer-build или Gitea token в nginx — переусложнение). Bundle deterministic + no runtime network.

Notes

  • Bundle approach впишется в существующий cron-loop pattern (build every 300s регенирует index.html + tasks-md). Никаких runtime-зависимостей от Gitea API.
  • Файлы могут быть rotated/архивированы (см. сестринскую таску board-viewer-ux-done-cutoff).