Inbound HTML emails were being flattened through html-to-text for display, which lost all formatting and — for images embedded as data: URIs — leaked the raw base64 as visible "[data:image/png;base64,...]" link text (an Outlook/webmail screenshot-paste artifact). Customer messages now also store a sanitized HTML rendering (messages.body_html) that preserves the sender's fonts/colors/layout and shows inline images (data: URIs render natively; cid: references are rewritten to the matching attachment's serving URL via a new attachments.content_id column). Sanitization is a tag/style allowlist (lib/mail/sanitize-html.ts, covered by sanitize-html.test.ts) — no script/event handlers/javascript: hrefs, no layout-breaking CSS. The plain-text fallback (used for channels other than email) also drops image/data-URI link text via html-to-text selectors, for the same underlying bug on that path. Also: pasting a screenshot (Ctrl+V) into the agent reply box now attaches it directly, reusing the existing attachment-upload/email-delivery path — no more "save to disk, then click attach" round trip. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GteWhnWKTmnXcsd5jx6H7u
top-tickets
Хелпдеск-система: тикеты, дашборд по статусам, канал Telegram, realtime-обновления без перезагрузки страницы, отдельный клиентский портал. MVP-1 — см. /root/.claude/plans/refactored-discovering-corbato.md за архитектурой и тем, что отложено на MVP-2 (email, встраиваемый виджет).
Запуск в Docker
cp .env.example .env
npm run generate-key # вставить результат в CREDENTIALS_ENCRYPTION_KEY
# заполнить ADMIN_BOOTSTRAP_EMAIL / ADMIN_BOOTSTRAP_PASSWORD / TELEGRAM_BOT_TOKEN в .env
docker compose up --build -d
Приложение слушает :8081 (уже проброшено внешним nginx на help.top-sysops.ru). При первом старте контейнер сам применяет миграции и создаёт админ-аккаунт из .env.
Локальная разработка
npm install
cp .env.example .env # + generate-key, как выше
npm run db:migrate
npm run bootstrap-admin
npm run dev
Telegram
Подключается через Настройки → Telegram в интерфейсе (или через TELEGRAM_BOT_TOKEN в .env — сработает только при первом старте, если бот ещё не настроен). Чтобы бот видел все сообщения в группе, а не только с упоминанием — @BotFather → /setprivacy → Disable.
Токен, который прислали в чат Claude Code, стоит перевыпустить (@BotFather → /revoke) — он засветился в истории сессии.