opencode-config/docs/decisions/061-pr-144-optional-badge-subtitle-entrypoint.md
Sergey 0d16b028fa
fix(draw-image): optional badge/subtitle + self-healing docker entrypoint (#144)
* fix(draw-image): conditional slot bg + optional subtitle in buildSvg

* test(draw-image): optional badge/subtitle unit+integration+e2e

* feat(docker): self-healing entrypoint shim + .dockerignore

* test(draw-image): pytest assert --subtitle omitted when absent

* docs(handoff): optional badge/subtitle + docker entrypoint handoff+ADR

* docs(handoff): set PR number 144

* docs(project-map): fix PR refs 143 to 144

---------

Co-authored-by: opencode-agent <agent@opencode.local>
2026-07-30 01:23:25 +03:00

22 lines
No EOL
3.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ADR-061: Optional badge/subtitle + self-healing docker entrypoint (PR#144)
## Статус
Accepted (2026-07-29)
## Контекст
PR#134 (ADR-060) ввёл SVG template renderer для on-brand covers. При тестовом рендере выявлены три проблемы:
1. **Пустой badge рисует квадрат**`renderSlotBackground()` вызывался для каждого слота с bg-спекой ДО проверки контента. Cover без `--slots badge=...` получал пустой `<rect fill="#121212" stroke="#ccff00">` в районе (780, 780).
2. **Subtitle оставляет пустой `<text>`**`{{subtitle}}` заменялся на пустую строку безусловно, но `<text>` элемент оставался в DOM. Большинство cover'ов — title-only.
3. **Fresh clone = broken**`node_modules/` (sharp, lucide-static) gitignored, Dockerfile не устанавливал deps для draw-image. После `docker compose up``Cannot find module 'sharp'`.
## Решение
1. **Slot bg conditional**`renderSlotBackground()` перенесён внутрь `if (value)` блока в `buildSvg()`. bg/border рендерится ТОЛЬКО если слот заполнен контентом.
2. **Subtitle conditional** — если `args.subtitle` falsy, regex `/[^\n]*\{\{subtitle\}\}[^\n]*\n?/g` удаляет всю `<text>` строку с `{{subtitle}}` из шаблона ДО подстановки. При наличии subtitle — обычная подстановка `escapeXml(args.subtitle)`.
3. **Self-healing entrypoint**`docker-entrypoint.sh` (POSIX `#!/bin/sh`) проверяет `node_modules/sharp`, при отсутствии запускает `npm ci --prefix` (continue-on-error: WARN в логах, контейнер стартует), затем `exec opencode "$@"`. Dockerfile `ENTRYPOINT` → entrypoint shim. `.dockerignore` исключает `app_data/`, `.git`, `**/node_modules` из build context.
## Альтернативы
- **Install draw-image deps в Dockerfile (RUN npm ci)** — отвергнуто: node_modules gitignored, COPY не сработает; `npm ci` в build-time требует COPY package.json + package-lock.json из `.opencode/draw-image/`, усложняет Dockerfile. Self-healing entrypoint — одноразовая задержка при первом старте, потом skip.
- **Pre-build hook (postinstall sync-lucide в Dockerfile)** — уже работает через entrypoint: `npm ci` запускает postinstall (`sync-lucide.mjs`), восстанавливает 2007 иконок.
- **Удалить `<text>` subtitle через DOM-парсер (xmldom)** — overkill для одной строки. Regex по строке — достаточно, шаблон контролируемый.
- **`set -euo pipefail` в entrypoint** — отвергнуто: `npm ci` failure (нет сети) должен быть continue-on-error, иначе контейнер не стартует. POSIX `#!/bin/sh` для портативности в slim-образах.