* 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>
3.1 KiB
3.1 KiB
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. При тестовом рендере выявлены три проблемы:
- Пустой badge рисует квадрат —
renderSlotBackground()вызывался для каждого слота с bg-спекой ДО проверки контента. Cover без--slots badge=...получал пустой<rect fill="#121212" stroke="#ccff00">в районе (780, 780). - Subtitle оставляет пустой
<text>—{{subtitle}}заменялся на пустую строку безусловно, но<text>элемент оставался в DOM. Большинство cover'ов — title-only. - Fresh clone = broken —
node_modules/(sharp, lucide-static) gitignored, Dockerfile не устанавливал deps для draw-image. Послеdocker compose up→Cannot find module 'sharp'.
Решение
- Slot bg conditional —
renderSlotBackground()перенесён внутрьif (value)блока вbuildSvg(). bg/border рендерится ТОЛЬКО если слот заполнен контентом. - Subtitle conditional — если
args.subtitlefalsy, regex/[^\n]*\{\{subtitle\}\}[^\n]*\n?/gудаляет всю<text>строку с{{subtitle}}из шаблона ДО подстановки. При наличии subtitle — обычная подстановкаescapeXml(args.subtitle). - Self-healing entrypoint —
docker-entrypoint.sh(POSIX#!/bin/sh) проверяетnode_modules/sharp, при отсутствии запускаетnpm ci --prefix(continue-on-error: WARN в логах, контейнер стартует), затемexec opencode "$@". DockerfileENTRYPOINT→ 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 cifailure (нет сети) должен быть continue-on-error, иначе контейнер не стартует. POSIX#!/bin/shдля портативности в slim-образах.