Демо-проект

Заявка с сайта уходит в Telegram

Стенд доставки заявок: форма лендинга и форма WordPress-сайта приходят в Telegram, все попытки доставки видны в журнале.

разработка интеграции · Node.js · JavaScript · Telegram Bot API

в работеЛендинг падает на битом запросе, порты зашиты, README нет

2 входаформа лендинга и приёмник с сайтов
3 попыткидоставки при сбое Telegram
3 проверкиу приёмника: имя, телефон, согласие
0 правокв исходном коде демо-лендинга
Первый экран демо: Заявка с сайта уходит в Telegram

Задача

Заявка с сайта живёт минуты. Пока она лежит в почте или в админке сайта, клиент успевает написать конкурентам. Владельцу нужно одно: чтобы имя и телефон падали туда, куда он и так смотрит весь день - в Telegram, и чтобы было видно, дошло сообщение или нет.

Это стенд, а не клиентский проект: компании вымышленные - «ЧистоДом», выездная химчистка мебели и ковров, и «Волокно», столярная мастерская. Задача при этом настоящая и типовая. Стенд нужен, чтобы показывать работающую доставку заявок вживую, а не описывать её словами.

Решение

Два входа и один общий модуль доставки.

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

Второй вход - приёмник заявок с внешних сайтов. Он ничего не показывает, а слушает один адрес: заявка приходит структурой данных, проверяется, уходит в Telegram и попадает в журнал. С ним работает форма WordPress-сайта «Волокно».

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

Детали, которые легко не заметить

  • Ответ приёмника - это контракт для сайта, а не вежливое «спасибо». Дошло - сайт закрывает заявку; не дошло - ставит её в очередь и пробует снова по расписанию. Заявка остаётся на стороне сайта и уходит повторно, а не пропадает вместе с неудачным запросом.
  • У приёмника согласие на обработку персональных данных - обязательное поле, а не галочка для вида: без него заявка получает отказ. На лендинге такой проверки на сервере пока нет, только в браузере.
  • Отказ по полям приёмник тоже пишет в журнал, с причиной. Иначе «заявок сегодня не было» и «заявки были, но их отбросили» выглядят одинаково.
  • Идентификатор чата в журналы не пишется - его нельзя показывать на скриншотах. Само содержимое заявки в журнале сохраняется: это журнал доставок, а не анонимная телеметрия.
  • У приёмника каждое поле обрезается по длине, а размер запроса ограничен: открытый адрес не должен превращаться в способ забить диск. Отдача файлов лендинга отдельно проверяет, что путь не выводит за каталог проекта.
  • Скрипт формы перехватывает отправку, но проверяет поля до перехвата: не прошло - событие уходит штатной логике формы, а не проглатывается.

Что осталось доделать

Стенд работает и снимается, но он не закончен. Честный список.

Форма на лендинге не показывает посетителю неудачу: скрипт рисует карточку «заявка отправлена» только при успешном ответе, а при отказе доставки или недоступном сервере не делает ничего - как раз в том сценарии с тремя отказами, о котором рассказано выше. Нужна ветка ошибки.

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

Скрипт формы ищет поле комментария под именами task и comment, а в форме лендинга оно называется what: текст «что почистить» с лендинга не доезжает до Telegram.

Порты зашиты в код - 4319 у лендинга и 4320 у приёмника, причём 4320 совпадает с портом соседнего стенда, и вдвоём они не поднимаются. Настроек из окружения стенд не читает вообще. Своего README у него нет, описание живёт в общем файле каталога стендов, и самопроверки, как у соседних стендов, здесь тоже нет - только живые прогоны. Ключи бота стенд пока берёт у соседнего проекта: под него нужен отдельный Telegram-бот с нейтральным именем, а создать его может только владелец учётной записи.