The "New ticket" modal only took a plain-text message. It now matches the
existing reply box on an open ticket: a "Прикрепить файл" button, and Ctrl+V
paste of a clipboard screenshot attaches it directly. POST /api/tickets
switched from JSON to multipart/form-data to carry the optional file,
reusing the same saveAttachment/attachment-delivery path replies already use.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GteWhnWKTmnXcsd5jx6H7u
Four requested improvements:
1. Logo + wordmark now link to /dashboard.
2. Header reordered: nav links (Заявки/Статистика) centered, right side
now reads notifications -> theme -> settings -> account name -> logout,
matching the requested order.
3. New TicketToasts component: in-page toast + a short Web Audio chime for
new tickets and customer messages, shown regardless of tab focus.
Complements the existing DesktopNotifications, which only fires the
native OS notification while the tab is backgrounded. Also added a 30s
polling refresh on the dashboard as a plain safety net under the
existing SSE push, in case an event is dropped by whatever's in front
of this app on the network.
4. Agents now see only tickets assigned to them plus unassigned ones (not
the whole board) — listTickets() takes an optional visibility filter,
applied in both the dashboard page and the /api/tickets search route,
and mirrored client-side so a live SSE update can't leak a
just-reassigned-away ticket onto their board. Settings gear and the
Статистика nav link are now hidden entirely for agents rather than
just showing fewer items inside. Also closed a real gap this surfaced:
/stats had no server-side role check at all (only the nav link was
hidden), so any agent could load it directly — added the same
session.user.role !== "admin" guard the other admin-only settings
pages already have.
Verified end-to-end with a temporary Playwright pass (installed and fully
removed afterward): logo click navigation, header icon order, agent view
missing the gear/Статистика, direct-URL access to /stats and
/settings/accounts still redirecting non-admins, and ticket visibility
correctly disappearing from an agent's board the moment it's reassigned
to someone else.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012o9j9RezxbZVKQMrB7oRLY
Attachments: file storage on the same data volume, serving route with
dual auth (session or portal/widget token, internal-note attachments
never token-servable), inbound ingestion from email (mailparser) and
Telegram (photo/document handlers), outbound delivery via SMTP
attachments and Telegram sendDocument/sendPhoto, upload UI (paperclip +
pending-file chip) on all three reply surfaces. Extracted
lib/tickets/delivery.ts so the text-only and attachment-upload admin
routes share one channel-delivery code path instead of duplicating it.
Canned responses: CRUD + a popover picker in the reply box that inserts
a saved template into the draft.
Tags: fixed 6-color palette reusing existing soft-badge tokens, a picker
on the ticket page, colored chips + a filter row on the dashboard.
Search: LIKE-based (not FTS5 — simpler and sufficient at this volume)
across ticket subject, customer name, and message bodies; a debounced
search box on the dashboard.
Desktop notifications: permission toggle + a background subscriber that
fires for new tickets and customer messages while the tab is hidden,
clicking one navigates to the ticket.
Password change: new account settings page, verifies the current
password before updating.
Nav: gear-menu settings list now includes Шаблоны ответов/Теги/Аккаунт.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QcXH24ky6zjk2UyK5oZUPH