Демо-проект
Заявка с сайта уходит в Telegram
Стенд доставки заявок: форма лендинга и форма WordPress-сайта приходят в Telegram, все попытки доставки видны в журнале.
разработка интеграции · Node.js · JavaScript · Telegram Bot API
в работеЛендинг падает на битом запросе, порты зашиты, README нет

Задача
Заявка с сайта живёт минуты. Пока она лежит в почте или в админке сайта, клиент успевает написать конкурентам. Владельцу нужно одно: чтобы имя и телефон падали туда, куда он и так смотрит весь день - в Telegram, и чтобы было видно, дошло сообщение или нет.
Это стенд, а не клиентский проект: компании вымышленные - «ЧистоДом», выездная химчистка мебели и ковров, и «Волокно», столярная мастерская. Задача при этом настоящая и типовая. Стенд нужен, чтобы показывать работающую доставку заявок вживую, а не описывать её словами.
Решение
Два входа и один общий модуль доставки.
Первый вход отдаёт готовый демо-лендинг и принимает его форму. Файлы лендинга читаются с диска как есть, а скрипт отправки подставляется в HTML на лету, перед закрывающим тегом. Исходник демо не меняется ни на строку. Важная оговорка: в самом демо написано, что формы никуда не отправляют, и в опубликованном демо это так и есть. На стенде отправка включена намеренно - иначе показывать было бы нечего.
Второй вход - приёмник заявок с внешних сайтов. Он ничего не показывает, а слушает один адрес: заявка приходит структурой данных, проверяется, уходит в Telegram и попадает в журнал. С ним работает форма WordPress-сайта «Волокно».
Доставка общая для обоих входов: до трёх попыток с нарастающей паузой между ними. Заявка ложится в журнал одной строкой, а попытки лежат внутри неё списком: номер попытки, код ответа Telegram, успех или нет. В журнале лендинга сохранился настоящий сбой: три попытки подряд с отказом Telegram, заявка не доставлена. Журнал не стали чистить - именно так и выглядит недоставленная заявка.
Детали, которые легко не заметить
- Ответ приёмника - это контракт для сайта, а не вежливое «спасибо». Дошло - сайт закрывает заявку; не дошло - ставит её в очередь и пробует снова по расписанию. Заявка остаётся на стороне сайта и уходит повторно, а не пропадает вместе с неудачным запросом.
- У приёмника согласие на обработку персональных данных - обязательное поле, а не галочка для вида: без него заявка получает отказ. На лендинге такой проверки на сервере пока нет, только в браузере.
- Отказ по полям приёмник тоже пишет в журнал, с причиной. Иначе «заявок сегодня не было» и «заявки были, но их отбросили» выглядят одинаково.
- Идентификатор чата в журналы не пишется - его нельзя показывать на скриншотах. Само содержимое заявки в журнале сохраняется: это журнал доставок, а не анонимная телеметрия.
- У приёмника каждое поле обрезается по длине, а размер запроса ограничен: открытый адрес не должен превращаться в способ забить диск. Отдача файлов лендинга отдельно проверяет, что путь не выводит за каталог проекта.
- Скрипт формы перехватывает отправку, но проверяет поля до перехвата: не прошло - событие уходит штатной логике формы, а не проглатывается.
Что осталось доделать
Стенд работает и снимается, но он не закончен. Честный список.
Форма на лендинге не показывает посетителю неудачу: скрипт рисует карточку «заявка отправлена» только при успешном ответе, а при отказе доставки или недоступном сервере не делает ничего - как раз в том сценарии с тремя отказами, о котором рассказано выше. Нужна ветка ошибки.
Первый вход читает тело запроса без ограничения размера и без обработки ошибки разбора: битый JSON роняет процесс целиком. У приёмника то же место сделано правильно, у лендинга - нет.
Скрипт формы ищет поле комментария под именами task и comment, а в форме лендинга оно называется what: текст «что почистить» с лендинга не доезжает до Telegram.
Порты зашиты в код - 4319 у лендинга и 4320 у приёмника, причём 4320 совпадает с портом соседнего стенда, и вдвоём они не поднимаются. Настроек из окружения стенд не читает вообще. Своего README у него нет, описание живёт в общем файле каталога стендов, и самопроверки, как у соседних стендов, здесь тоже нет - только живые прогоны. Ключи бота стенд пока берёт у соседнего проекта: под него нужен отдельный Telegram-бот с нейтральным именем, а создать его может только владелец учётной записи.
Скриншоты



