Чат в приложении: доставка сообщений, история и работа поддержки

Как спроектировать чат внутри приложения: подтверждение сообщения, повторы, работа без сети, непрочитанное, доступ, вложения и приёмка.

Автор: , CEO и основатель, 404gen.

Чат в приложении — это не только экран с пузырями сообщений. Пользователю нужна уверенность, что обращение принято, история сохранена и ответ относится к его вопросу. Для команды продукта это означает отдельные правила доставки, повторов, доступа, уведомлений и обработки обращений. Соединение в реальном времени решает часть задачи, но не заменяет хранилище и понятную модель состояний.

Материал предназначен заказчику мобильного приложения, руководителю поддержки и владельцу сервиса. Рассматриваем встроенный диалог клиента с сотрудником, а не публичную социальную сеть или чат-бота. Групповые сообщества, звонки и автоматические ответы могут потребовать самостоятельных решений. Цель первой версии — довести вопрос до ответственного и показать достоверный результат каждого действия.

Ниже разобраны сценарии, которые редко видны на первом макете: телефон потерял сеть после отправки, клиент сменил устройство, оператор завершил смену, вложение ещё проверяется, а push уже пришёл. В демонстрационном разборе продукта «Нить» показано, как отделять локальный черновик, подтверждённое сообщение и состояние обращения. Это концепт с учебными данными, без подключения реального канала поддержки.

Когда нужен чат внутри приложения

Встроенный диалог полезен, когда вопрос связан с конкретным заказом, заявкой или действием в продукте. Пользователю не приходится заново объяснять контекст в другом канале, а сотрудник получает разрешённые сведения рядом с обращением. При этом приложение должно передавать только необходимую информацию. Полный доступ ко всему кабинету клиента не является обязательным условием качественной поддержки.

Иногда достаточно формы обращения и истории ответов без непрерывного соединения. Если сотрудники отвечают только в рабочее время, искусственная надпись «оператор онлайн» создаёт лишнее ожидание. Перед разработкой изучают типичные вопросы, действующий канал поддержки и требуемую скорость реакции. Технологию выбирают после определения процесса, а не наоборот.

Нужен ли собственный чат или подключение готового решения, решают по доступу к истории, интеграциям, способам авторизации и условиям эксплуатации. Внешний продукт тоже требует обследования: где хранятся сведения, какие события доступны, как удаляются данные и что происходит при завершении договора. Наличие удобного виджета не отвечает на эти вопросы.

Разделите диалог, обращение и сообщение

Диалог хранит участников и контекст переписки. Обращение определяет рабочий процесс: тему, ответственного, состояние и связь с заказом. Сообщение представляет отдельную запись содержания. В простом продукте эти объекты могут совпадать по маршруту, но у них всё равно разные обязанности. Изменение исполнителя обращения не должно создавать новую историю или менять автора старых сообщений.

Модель «одна бесконечная переписка со службой поддержки» удобна на старте, пока у человека один вопрос. При нескольких параллельных заказах она смешивает обсуждения. Альтернатива — отдельные темы с общей точкой входа. Тогда заранее объясняют, как создать новое обращение и когда продолжать старое, чтобы пользователь не искал нужную реплику по всей истории.

Связь с предметом вопроса должна быть устойчивой. Если заказ переименован или карточка услуги изменена, старое сообщение не теряет смысл. В истории сохраняют понятный контекст на момент обращения в допустимом объёме. Политика хранения и допустимость копирования сведений требуют решения владельца продукта, а не случайного поведения компонента интерфейса.

Что означает «отправлено»

На устройстве текст сначала существует как черновик. После действия пользователя он может перейти в локальную очередь отправки. Затем сервер принимает и сохраняет сообщение. Отдельно могут появиться подтверждения доставки на устройство адресата и прочтения. Если эти этапы различаются в системе, интерфейс не должен объединять их одной галочкой с неоднозначным значением.

Подпись «принято сервером» означает более узкое обещание, чем «сотрудник прочитал». Выбирайте человеческие формулировки, но закрепляйте за каждой точное событие. Когда сведения о прочтении недоступны, такой статус не имитируют по времени присутствия оператора. Активное соединение не доказывает, что человек видел конкретный текст.

Для первой версии часто достаточно различать ожидание отправки, подтверждённое принятие и ошибку, требующую действия. Это возможное ограничение объёма, а не универсальный стандарт. Если бизнесу действительно нужны статусы доставки и прочтения, команда описывает источники этих подтверждений, способы синхронизации и правила для нескольких устройств.

СостояниеОснованиеЧто нельзя обещать
В очереди устройстваКоманда сохранена локальноЧто её уже получил сервер
ПринятоСервер подтвердил сохранённую записьЧто оператор уже прочитал текст
ДоставленоПолучено предусмотренное подтверждение адресатаЧто на вопрос подготовлен ответ
ПрочитаноЗафиксирован согласованный сигнал просмотраЧто обращение решено

Один клик не должен превращаться в два сообщения

У исходящей команды нужен устойчивый идентификатор, созданный до первой попытки отправки. При повторе после разрыва связи сервер находит уже обработанное действие или завершает ещё не выполненное. Если создавать новый идентификатор при каждом повторе, одна реплика появится несколько раз. Скрытие повторов только в интерфейсе не исправляет состояние хранилища.

Важно различать повтор технической попытки и намеренно отправленный новый текст. Пользователь вправе дважды написать одинаковое сообщение, и система не должна удалять второе только по совпадению содержания. Основание для объединения — идентификатор команды в пределах её автора и диалога. Текст и время являются вспомогательными признаками, а не надёжным ключом.

После принятия сервер возвращает окончательный идентификатор, время и порядок. Локальная запись связывается с подтверждённой. Тест воспроизводит ситуацию, в которой сервер сохранил сообщение, но ответ не дошёл до телефона. Следующий запуск приложения должен найти ту же запись и обновить статус, сохранив введённый текст и понятную историю действий.

Работа без сети и выход из приложения

Если отправка без соединения поддерживается, пользователь должен понимать, что текст пока остаётся на устройстве. Локальная очередь требует собственного жизненного цикла: ожидание, попытка, подтверждение и отмена до отправки. Возможность убрать ещё не переданное сообщение важна, когда связь возвращается через значительное время и исходный вопрос уже потерял актуальность.

Не обещайте автономную работу, если очередь хранится только в памяти открытого экрана. Закрытие приложения или перезапуск телефона тогда уничтожит ожидание. В требованиях определяют, какие данные сохраняются между запусками, как долго и на каких устройствах. Для чувствительного содержания учитывают модель защиты устройства и правила выхода из аккаунта.

При смене пользователя локальные данные не должны оказаться в новом аккаунте. Ожидающее сообщение принадлежит конкретному автору и диалогу; отправлять его после входа другого человека нельзя. Этот сценарий проверяют отдельно от обычного восстановления сети. Он касается границы доступа, а не только надёжности очереди.

WebSocket, запросы и восстановление соединения

Для двусторонних событий может использоваться WebSocket. В документации MDN он описан как API подключения к серверу и обмена данными. Это транспорт, а не готовая гарантия хранения, проверки полномочий или восстановления истории. Приложение отдельно определяет, какие сообщения были приняты и что нужно запросить после переподключения.

Постоянное соединение может закрыться при смене сети, переходе в фон или перезапуске сервера. После возвращения клиент получает подтверждённое состояние по устойчивому указателю истории. Просто открыть новое соединение недостаточно: события, возникшие в промежутке, могли не попасть на устройство. План восстановления должен работать и после длительного отсутствия.

Запрос истории и события реального времени могут пересекаться. Если одно сообщение пришло по обоим путям, оно отображается один раз по серверному идентификатору. Если клиент временно получает события не в том порядке, интерфейс восстанавливает последовательность согласно принятому правилу. Такой алгоритм проверяют на искусственно задержанных ответах, а не только на быстрой локальной сети.

Порядок, время и пагинация истории

Время телефона не должно быть единственным основанием сортировки. Пользователь может изменить часы, а два устройства — отправить сообщения почти одновременно. Сервер задаёт устойчивый порядок, пригодный для повторной загрузки. Отдельно отображаемое человеку время переводится в нужный часовой пояс и не используется как единственный идентификатор позиции.

Большую историю загружают частями. При добавлении старых сообщений положение чтения сохраняют, иначе человек потеряет нужный фрагмент. Новая реплика не должна автоматически прокручивать к концу того, кто читает предыдущую переписку. Лучше показать понятный переход к новым сообщениям, сохранив текущий контекст.

Если сообщение удалено или ограничено политикой хранения, определяют, как выглядит разрыв. Молчаливое переупорядочивание может изменить смысл ответа. Для редактируемого содержания обсуждают отметку изменения и доступ к истории согласно ролям. Не каждый чат обязан поддерживать редактирование, но выбранное поведение должно быть одинаковым на всех клиентах.

Непрочитанное на нескольких устройствах

Счётчик непрочитанного должен иметь понятное основание: какие сообщения считаются входящими, что считается просмотром и как синхронизируется позиция чтения. Открытый список обращений не всегда означает чтение содержимого диалога. Отображение части реплики в уведомлении также не обязательно является подтверждением прочтения.

Если человек прочитал историю на одном устройстве, второе получает обновлённую позицию. Запоздавшее событие не должно откатывать её назад и снова делать старые сообщения непрочитанными. При этом новая реплика, пришедшая после сохранённого указателя, остаётся новой. Проверка одного локального счётчика на одном телефоне этого не подтверждает.

Внутри команды поддержки личный просмотр и состояние обработки обращения могут различаться. Один оператор открыл диалог, но ответ ещё не назначен. Нельзя убрать задачу из общей очереди только потому, что кто-то увидел текст. Это разные рабочие события, которые необходимо разделять в продукте и аналитике.

Уведомление ведёт к актуальному состоянию

Push помогает вернуть человека в приложение, но не хранит историю и не гарантирует получение содержания. Пользователь может запретить уведомления, устройство — задержать их, а приложение — не иметь доступного канала в конкретный момент. При открытии переписки нужно загрузить сохранённые сообщения независимо от того, какие уведомления видел телефон.

Текст уведомления проектируют с учётом экранов блокировки и особенностей предметной области. Иногда достаточно «Есть ответ по обращению» без подробностей заказа и персональной информации. Полный текст реплики не следует включать автоматически. Условия согласия, допустимое содержание и политика хранения определяются для конкретного продукта.

Переход проверяет вход и доступ к диалогу, затем открывает актуальную позицию. Старое уведомление не должно показывать чужую переписку после смены аккаунта. Для деталей полезны разбор переходов по deep link и материал о push-уведомлениях; здесь эти механизмы рассматриваются как часть маршрута к сообщению.

Права проверяются для каждого действия

Наличие открытого соединения не даёт право читать любой диалог. Сервер проверяет участника и область доступа при подписке, чтении истории, отправке и загрузке вложений. Если сотрудник перешёл в другую команду или клиент потерял доступ к заказу, необходимо определить, что происходит с активным соединением и ранее разрешёнными операциями.

В рекомендациях OWASP по защите WebSocket рассматриваются аутентификация, авторизация, проверка сообщений и ограничение нагрузки. Для проекта это означает набор конкретных отрицательных тестов: попытку доступа к чужому диалогу, действие после завершения сессии и отправку неподдерживаемого сообщения.

Идентификатор диалога в адресе или запросе не является секретом, на котором строится защита. Даже зная его, посторонний не должен получить историю. Права проверяют по доверенной модели участников на сервере. Аналогичные ограничения требуются для служебных заметок: они не становятся клиентскими сообщениями из-за ошибочного переключения интерфейса.

Вложения проходят свой маршрут

Отправка файла состоит из загрузки, проверки и разрешения на использование. До завершения этих этапов вложение не должно выглядеть как готовое доступное сообщение. Указывают ограничения размера, поддерживаемые форматы и действия при отказе. Если текст уже принят, а вложение не загрузилось, пользователь видит эту разницу и может повторить только нужный шаг.

Доступ к файлу связан с правами на диалог. Долгоживущая публичная ссылка способна обойти ограничения самой переписки. Система определяет срок и область доступа, способ выдачи и поведение после закрытия обращения. Решение о хранении и удалении учитывает назначение данных; его нельзя заменить случайным сроком очистки временной папки.

Изображения и документы не должны автоматически исполняться как активное содержимое внутри интерфейса. Проверяют тип и структуру полученного объекта, допустимый предпросмотр и ограничения выдачи. Отдельно обрабатывают отмену пользователем и обрыв соединения. Повтор загрузки должен связываться с исходной командой, а не засорять диалог несколькими недоступными копиями.

Доступность и поведение интерфейса

У поля сообщения есть постоянная подпись, а у кнопок вложения и отправки — понятные имена для вспомогательных технологий. Ввод не должен исчезать после неуспешной попытки. При длинном тексте экран остаётся управляемым, клавиатура не закрывает нужное действие, а ошибка находится рядом с тем содержанием, к которому относится.

Новое сообщение и изменение статуса отправки представляют по-разному. Не следует заставлять программу чтения экрана заново проговаривать всю историю на каждое событие. В пояснении W3C о сообщениях состояния рассмотрено уведомление о существенных изменениях без непредсказуемого переноса фокуса.

Проверяют навигацию клавиатурой, крупный шрифт и длинные имена вложений. Цвет сам по себе не отличает ошибку от ожидания. При ответе оператора человек должен иметь возможность продолжить писать, не потеряв курсор. Автоматическое появление новых элементов не должно менять смысл текущего действия или случайно отправлять незавершённый черновик.

Рабочий процесс поддержки

На стороне оператора важны назначение, передача и завершение обращения. Автоматическая раздача может учитывать очередь, специализацию и текущую доступность, но её правило должно быть определено. Одновременное открытие диалога двумя сотрудниками не означает, что оба назначены. Клиенту требуется единый понятный ответ, а не две противоречащие рекомендации.

При передаче обращения сохраняют историю и ответственную роль. Внутренний комментарий помечают как служебный и защищают от публикации клиенту. Пользовательский ответ и заметка сотрудникам должны иметь хорошо различимые элементы управления. Ошибка режима особенно опасна, если интерфейс запоминает последний выбор без заметного напоминания.

Завершение обращения не должно стирать диалог. Нужно определить, можно ли открыть его новым сообщением или создаётся отдельная тема. При нерабочем времени показывают реальный порядок ответа без искусственного обещания постоянного присутствия. Сроки реакции берутся из согласованного процесса, а не из шаблонного текста виджета.

Связь с CRM и источником обращения

В CRM передают согласованный набор сведений: идентификатор обращения, клиента, связанный заказ, статус и назначение. Полная копия каждого сообщения может быть не нужна. Чем больше дублируется чувствительное содержание, тем больше мест требует контроля доступа, удаления и восстановления. Объём обмена выбирают по реальной задаче сотрудников.

Если подтверждение передачи в CRM задержалось, сам чат может продолжать работать. Состояние интеграции показывают отдельно от статуса отправки клиентского сообщения. Иначе пользователь увидит ошибку чата из-за недоступной административной системы или, наоборот, ложное подтверждение доставки обращения ответственному. Для восстановления нужна очередь необработанных операций обмена.

События из CRM тоже могут приходить повторно или в другом порядке. Они должны относиться к известному обращению и не перетирать более актуальное назначение без предусмотренного правила. Дополнительный контекст, например ссылка на страницу товара, передают как данные с ограниченной областью использования. Внешняя строка не должна управлять правами или выполнять действия приложения.

Какие показатели фиксировать на пилоте

Для надёжности полезно наблюдать подтверждённые сообщения, зависшие команды и повторные попытки. Для процесса поддержки — время до назначения, первого содержательного ответа и завершения. Эти интервалы считают по разным событиям. Автоматическое приветствие не должно подменять ответ сотрудника, если целью измерения является фактическое начало разбора вопроса.

Снижение числа звонков не всегда означает улучшение: пользователи могли просто не найти способ связи. Количество сообщений тоже неоднозначно: длинный диалог может отражать сложную задачу или непонятные ответы. Сопоставляйте измерения с категорией обращения, рабочим временем и результатом. Отдельно смотрите на незавершённые переписки и причины повторного открытия.

До пилота фиксируют исходное определение событий и ограничения наблюдения. Если подтверждения прочтения нет, метрика чтения остаётся неизвестной. Если история ещё не связана с решением вопроса, нельзя заявлять рост качества поддержки. Демонстрационный макет показывает гипотезу взаимодействия, но не доказывает снижение затрат или увеличение удержания.

Матрица приёмки встроенного чата

На стенде нужны управляемый разрыв сети, задержка ответа, несколько устройств и разные роли. Обычная отправка между двумя открытыми окнами проверяет только короткий маршрут. Исполнитель должен показать, что происходит после перезапуска приложения, истечения сессии и изменения состава участников. У каждого теста сохраняется ожидаемый результат в интерфейсе и на сервере.

ПроверкаОжидаемое поведение
Ответ потерян после сохраненияПовтор находит одно исходное сообщение
Две одинаковые реплики отправлены намеренноОбе сохраняются как отдельные команды
Телефон перезапущен без сетиОчередь ведёт себя согласно заявленной автономности
Пользователь сменил аккаунтЧужие черновики и история недоступны
Событие пришло и в истории, и по соединениюОтображается одна запись
Сообщение прочитано на другом устройствеУказатель чтения синхронизируется без отката
Файл не прошёл проверкуНет ложного статуса готового вложения
Оператор потерял доступСервер отклоняет дальнейшее чтение и отправку
Получено старое уведомлениеОткрывается актуальное разрешённое состояние

Состав первой версии и передача в эксплуатацию

Первую версию можно ограничить текстовыми обращениями, одной очередью поддержки и базовыми статусами принятия. Если вложения критичны для процесса, их нельзя исключать ради красивого короткого срока. Вместо перечня эффектов и анимаций фиксируют завершённые маршруты: создать обращение, получить подтверждение, прочитать ответ, передать ответственному и разобрать ошибку.

В состав проекта входят интерфейс клиента, рабочее место сотрудника, хранение, доступ, интеграции и восстановление. Если обсуждается готовый сервис, команда проверяет его соответствие этим маршрутам. Разработка с нуля не является обязательным ответом на любую задачу. Стоимость определяют после обследования; выдуманный срок по количеству пузырей сообщений не даёт надёжной оценки.

В 404gen такую задачу рассматривают в рамках разработки нативных приложений или кроссплатформенного продукта. Для оценки подготовьте основные темы обращений, текущий канал поддержки, правила доступа и используемую CRM. Отдельно обозначьте, какие сведения нельзя передавать стороннему поставщику и кто будет отвечать за эксплуатацию.

Частые вопросы

WebSocket гарантирует доставку сообщения?

Сам по себе он не гарантирует сохранение делового события и обработку его адресатом. Приложение отдельно задаёт подтверждение сервера, историю и повтор команды. После разрыва соединения клиент сверяет сохранённое состояние. Транспорт помогает обмениваться событиями в реальном времени, но не заменяет модель надёжной доставки на уровне продукта.

Почему сообщение видно, но рядом остаётся ожидание?

Интерфейс может сразу показать локальную запись, пока сервер её ещё не подтвердил. Такое поведение допустимо, если состояние понятно пользователю и текст не теряется при отказе. Подтверждение меняет статус той же записи. Нельзя считать появление пузыря доказательством того, что обращение уже доступно сотруднику.

Можно ли обойтись готовым чатом?

Да, если он соответствует нужным маршрутам, доступу, хранению и требованиям интеграции. Проверяют поведение при выходе из аккаунта, получение истории, перенос между операторами и условия передачи данных. Встраивание готового компонента сокращает часть работ, но не отменяет обследование процесса и проверку границ ответственности поставщика.

Нужны ли статусы прочтения в первой версии?

Только если у них есть понятная продуктовая задача и достоверный источник подтверждения. Для поддержки иногда достаточно принятия сервером и отдельного статуса обращения. Имитировать прочтение по присутствию оператора не следует. Правило должно одинаково работать на нескольких устройствах и не смешиваться с завершением самого вопроса.

Как проверить чат до публикации приложения?

Пройти сценарии с потерей сети, повтором отправки, несколькими устройствами, изменением доступа и отказом вложений. Затем проверить рабочее место поддержки и обмен с CRM. Результаты фиксируют отдельно для интерфейса, серверных операций и интеграций. Успешная переписка в двух окнах подтверждает лишь базовый маршрут.

404gen — креативное digital-агентство полного цикла, работаем удалённо по всей России.

Телефон: +7 993 729-59-59 (пн–пт, 10:00–19:00 МСК). WhatsApp: +7 913 141-20-96. Telegram: @aporkulevich. Почта: ap@404gen.ru.