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).
4.2 KiB
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 в htmlstatic/board.js:200-215—openDrawerчитает из localStorage / global var вместо fetchtests/— 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.jsonreasonable (предположительно <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).