# board-viewer-drawer-bundle-md ## Goal Drawer падает с `TypeError: Failed to fetch` при клике на любую карточку. Root-cause: `rawUrl` указывает на `git.kzntsv.site///raw/branch//` — приватные репо требуют 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` или встраивать в `` в `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-215` — `openDrawer` читает из 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`).