The click-to-zoom feature from the previous commit worked for cid:-referenced images but silently failed for images embedded directly as a data: URI — confirmed with a real Playwright click: Chrome refuses to navigate a tab (even a new one, even from a direct user click) to a data: URL, so <a href="data:...' target="_blank"> just does nothing. The cursor still showed zoom-in on hover since that's plain CSS, which is exactly the "лупа появляется, но не нажимается" symptom reported. Fix: imap.ts now extracts every data:image src out of an inbound email's HTML into a real attachment file (deduping identical images embedded more than once), the same way cid: images already were, and rewrites the HTML to point at that attachment's normal /api/attachments/... URL instead. That also shrinks messages.body_html (data URIs can be hundreds of KB sitting in a DB column) and gets data-URI images the same "no duplicate chip below" treatment cid: images already had. attachments.isInline is now its own real column (backfilled from the existing content_id-based cases) instead of being derived from content_id, since a data-URI-derived attachment is inline but was never cid-referenced. sanitizeEmailHtml's link-wrapping step now skips any residual data: src defensively (unwrapped-but-visible beats a link that looks clickable but isn't). Verified against the real deployment with actual browser clicks (Playwright): both a data-URI image and a cid: image now open their full-resolution attachment in a new tab; before this fix the data-URI one silently did nothing. Added a vitest.config.ts (needed for the new test file's @/ import aliases) and unit tests for the extraction/dedup logic. 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) — он засветился в истории сессии.