Неделя 159. Сколько стоит скорость

Разбор этой статьи
Эту тему разобрали в подкасте. Слушай параллельно с чтением.
Это сто пятьдесят девятая неделя с момента, как мы запустили Botseller в августе 2023 года. Период: с 10 августа 00:00 до 17 августа 00:00 по Москве.
В прошлом выпуске я рассказал, как наш отчёт о собственных продажах пять дней подряд сходился и врал, и закончил тем, что тарифные планы выходят в кабинет, а рассылка отправляла по семнадцать сообщений в секунду.
Платёжная часть на этой неделе была, только не международного контура, а всей платформы: тарифы, модули, себестоимость сообщений. Международная там же, где была, и причина прежняя.
А началось всё с семи строк. Во вторник в ядре платформы поменяли единицу измерения одной настройки, и в среду у клиента рассылка ушла залпом по его же базе.
В четверг в основную линию вошли тарифы. В пятницу вечером за ними вошли платные модули: их писали отдельно и параллельно, и в момент соединения они затёрли часть свежего кода старой копией. Суббота ушла на возврат.
Так выглядела самая объёмная неделя августа: больше половины всей работы приехало с вечера пятницы до ночи воскресенья. Поэтому выпуск не о том, сколько мы сделали, а о том, сколько это стоило и кому.
Сырой счётчик недели: 295 записей разработки в 9 рабочих контурах, из них 110 объединённых задач и 185 прямых правок. По объёму 33,4 тысячи добавленных строк.
Меня зовут Дмитрий Дьяконов, я основатель и CEO Botseller AI. Мы делаем платформу с AI-продавцом, CRM, мессенджерами, автоматизациями, рассылками, календарём и звонками. Каждую неделю я разбираю, что реально сдвинулось в продукте и зачем это нужно бизнесу. Поехали по 159-й.
Пульс недели

| Направление | Записей разработки | Что это значит простыми словами |
|---|---|---|
| Тарифы и платные модули | 118 | вместо «плати за каждый диалог» появились пакеты и модули |
| Отчёт о рассылке и доставка | 90 | видно, сколько дошло, кто прочитал и кто ответил |
| Показатели сотрудников и расписание | 37 | удержание считается по людям, а не по абонементам |
| Себестоимость и списание за WhatsApp | 18 | цена сообщения зависит от страны, стоимость рассылки видна до запуска |
| Российская языковая модель | 18 | российский контур получает свою модель: пока скелет |
| Служебные двери канала WhatsApp | 8 | чужой не заглянет в ваши шаблоны и отчёты |
| Сайт и поиск | 4 | битые ссылки в Яндексе наконец получили правильный ответ |
Главная мысль недели: в системе, где ходят деньги, скорость съедает то, что сделано. Одна и та же «1» в двух частях платформы значила минуту и секунду, и этого хватило на залп.
Антиспам WhatsApp сработал на наш собственный залп
Начну с самого неприятного, потому что это мы сделали сами.

В 156-м выпуске я рассказывал про паузу между сообщениями бота, чтобы ответ, разбитый на части, не вылетал очередью. У рассылок есть своя пауза, между сообщениями разным получателям. Вот с ней и случилось.
Ползунок в мастере рассылок размечен в секундах, а ядро хранило паузу в минутах, поэтому кабинет делил секунды на 60 и округлял, минимум единица. Во вторник 11 августа ядро перевело эту настройку с минут на секунды. Семь строк.
Кабинет об этом не узнал и продолжал делить: любое положение ползунка от 5 до 180 секунд превращалось в «1». До вторника эта единица означала минуту. После вторника секунду.
В среду один из клиентов с 24 правилами рассылки получил темп 16,7 сообщения в секунду на одной рассылке и 7,4 на другой. Один номер получил пять маркетинговых сообщений за 1,2 секунды. Площадка WhatsApp ответила 76 отказами с причиной «слишком часто».
Сломали во вторник, залп прошёл в среду, причину нашли при подготовке исправления в пятницу.
Представьте кухонный таймер, у которого деление «1» было минутой, а после обновления стало секундой. Яйцо, которое вы ставили на пять минут, снимут через пять секунд. Цифра на таймере та же.
Качество номера в WhatsApp это капитал: его понижают за частую отправку, а поднимают медленно. Залп своими руками роняет качество, а до 76 адресатов сообщение вообще не дошло: площадка придержала его на выходе. И счёт за наши семь строк пришёл не нам. Репутацию номера зарабатывает клиент, а потратили её мы.
Никто не солгал: ядро было право по-своему, кабинет по-своему. Единица измерения такая же часть договора между частями системы, как сама цифра. Простой откат, вернуть деление на 60, не подходил: сохранённые значения не перевести ни в какую сторону. Починили кабинет.
Это, кстати, не только наша болезнь. Откройте табличку, по которой считаете скидки или сроки, и найдите в ней колонку с числом «10». Если рядом не написано, проценты это или дни, у вас лежит та же мина. Просто ещё не взорвалась.
Из разбора вылезло ещё два расхождения. Суточный лимит номера был вписан в код одним числом на всех, хотя площадка выдаёт его каждому номеру отдельно и со временем поднимает. Теперь лимит спрашиваем у WhatsApp, а перед кнопкой «Отправить» видно, сколько уйдёт сегодня и какое у номера качество.
Второе про отказы. Раньше нажатие «STOP» только уходило в служебный журнал, и следующая рассылка приходила человеку снова. Теперь отказ попадает в стоп-лист сам, а кнопка «STOP» стала его вторым источником: кнопки в рассылках появились ещё во вторник, до залпа, и к выходным в отчёте стало видно, что именно получил человек.
Отчёт о рассылке показывал десять случайных сообщений
Вторая история про рассылки объясняет, почему залп заметили не сразу.

Отчёт по рассылке показывал ровно десять сообщений независимо от размера, причём случайных: номер страницы не доходил до базы. Хуже другое. Все цифры отчёта, отправлено, доставлено, ошибки, выгрузка, считались по этим десяти строкам. На рассылке в 696 адресатов тоже.
Отчёт делал то, что делала бы курьерская служба, если бы для сводки доставала из мешка десять конвертов и по ним объявляла процент доставки на всю тысячу. Курьеров за такое увольняют.
Экран сам вычислял состояние кампании из полученных строк, поэтому неправильная страница выглядела правдоподобно. Проверить это можно было в любой день, и никто ни разу не проверил, включая меня. Урок: сводка обязана считаться в источнике, а не по загруженной странице.
И если вы до середины августа решали по нашему отчёту, продолжать ли рассылки, откройте его заново: теперь там настоящие числа.
Починили в пятницу вечером и тогда же добавили воронку «отправлено, доставлено, прочитано, ответили». На рассылке 12 августа из 463 адресатов отправлено 86, доставлено 43, прочитано 43, ответили 10, отказов 377. Отклик десять из восьмидесяти шести: цифра, которой в отчёте не было никогда.
А 377 отказов из 463 это не норма официального канала. В одну рассылку 12 августа сошлись сразу три причины, и вот они.
Первая, залп, разобрана выше. Вторая: один из клиентов видел в своём отчёте 722 раза за день английскую техническую ошибку, и за ней стояла не его проблема, а наш сбой. Я его до сих пор разбираю, и это плохо само по себе: клиент читал английскую строку, пока я искал причину.
Третья интереснее. У клиента два подключения WhatsApp: обычное с телефона, по QR, и официальное. При рассылке по существующим лидам бралось подключение из карточки лида, без проверки канала, а отправка шла через официальный. 169 сообщений упали.
Виноват переключатель «продолжить в существующих чатах»: он включён по умолчанию и отправляет с того номера, через который клиент писал раньше, а не с выбранного. Пока он хотя бы предупреждает об этом.
Это та же диагностика вслепую, что с шаблонами в 157-м, только свет включал клиент, читая английские строки. Показывать человеку внутреннюю кухню хуже, чем честное «отправка временно не работала». Теперь причины отказов по-русски, с подсказкой к каждой.
Одно не доделали: в чате статус иногда прыгает с «прочитано» обратно на «доставлено», если подтверждение отправки пришло позже подтверждения прочтения. В отчёте это учтено, в чате нет.
Тарифы и модули: сто восемнадцать записей за неделю
Теперь про то, ради чего вся неделя и затевалась.

До этой недели платформа брала деньги одним способом: поштучно, за каждый диалог и слот. Это честно, и это мешает продавать. Владелец салона спрашивает «сколько это будет стоить в месяц», а мы отвечаем «зависит от того, сколько напишут». Для него это не ответ, а повод сказать «подумаю».
Почему не год назад: год назад я не смог бы доказать самому себе, что пакет окупается. Отчёт о собственных продажах, который я чинил в прошлом выпуске, до августа врал. Сначала пришлось научиться считать.
Можно было пересадить всех на пакеты. Проще для отчётности, но в 157-м выпуске я в FAQ пообещал, что условия для клиентов не меняются, и ломать это обещание через две недели не собирался.
Поэтому пакеты Старт, Рост и Бизнес появились рядом с поштучной оплатой, и действующие клиенты ничего не заметили, пока сами не зашли во вкладку «Тариф». Это как у мобильного оператора: можно платить за минуты, а можно взять пакет и знать сумму заранее. «Знать заранее» стоит дороже, чем кажется.
Кому какой: чем больше точек, каналов и людей, которые пишут, тем выше пакет. Салон с одним администратором и парой сотен диалогов в месяц живёт на младшем, сеть с тремя точками, звонками и официальным WhatsApp на старшем.
Деньги нельзя запускать с первого захода. За три дня перед запуском закрыли больше семидесяти дефектов в четырёх частях системы, и один запомните: через служебные адреса тарифов можно было дотянуться до чужого клиента. Дверь закрыли заранее. Ниже будет место, где такую же нашли уже открытой.
В четверг 13 августа тарифы вошли в основную линию сразу в трёх частях системы.
Отдельно про копейки, потому что это не про копейки.
Баланс хранился приближённым числом. Клиент пополнял ровно ту сумму, которую система у него сама и запросила, а на счету получался «минус ноль» с хвостом в тысячных. Проверка видела минус и выключала бота у того, кто только что заплатил.

Примерно каждое девятое пополнение «ровно на недостающую сумму» кончалось таким отказом. Сколько это людей и сколько часов они просидели с выключенным ботом, я не считал. Это мой долг, и я его признаю. Теперь баланс хранится точным числом.
С вечера пятницы до ночи воскресенья поверх тарифов легли платные модули: ещё один AI-сотрудник, ещё один канал, голосовые звонки, официальный WhatsApp, Рой и запуск под ключ. Один чек, продление «всё или ничего», чтобы не было состояния «тариф продлён, модули нет». В пробном периоде ежемесячные модули включены бесплатно, разовый «запуск под ключ» покупается отдельно.
И самое чувствительное для владельца: когда его AI-продавец перестаёт отвечать. Бот теперь выключается за неоплату сам, с льготным окном, а у нас есть рубильник, который останавливает выключатель, если тот ошибётся. В субботу выяснилось, что ошибиться может не выключатель, а то, что стоит перед ним.
Суббота, когда старая копия легла поверх новой
Вот счёт за скорость.

Тарифы вошли в основную линию в четверг. Ветка модулей вошла на следующий вечер и принесла с собой старую копию трёх файлов от 10 августа. Никакой сигнализации не сработало: для системы это было обычное изменение.
Два ремонтника делали одну квартиру по разным чертежам. Второй пришёл на сутки позже и переклеил стену, которую первый уже перенёс.
Ночью сломалось обновление базы: она перестраивается по списку инструкций, и в затёртой копии не хватило восьми описаний данных. Сервис данных не поднялся, и система запуска сама вернула прошлую версию. Была ночь, жалоб за эти часы не приходило.
К трём часам добрались до третьей поломки за ночь: без одного поля в ответе кабинет прятал все три карточки тарифов, и зашедший купить пакет увидел бы пустую страницу.
Хуже стало днём. В обед запустили версию, в которой из логики тарифов пропала часть кода, в том числе та, что назначает пробный период при регистрации.
Представьте: салон регистрируется в субботу днём, подключает WhatsApp, заходит в кабинет, и первое, что видит, красная плашка «Бот остановлен». Не «пробный период три дня», а вид должника. Так увидели четверо.
Выключатель за неоплату честно сделал свою работу, только неоплаты не было. Проверить регистрацию перед запуском не догадался никто, я в том числе. Исправление вошло вечером, до этого четверо сидели с остановленным ботом. Вернулись ли они после такого знакомства, я не знаю.
К полуночи вернули расчёт диалогов: в затёртой версии тариф не находился никогда, пробные диалоги считались платными, а два наложившихся запуска могли посчитать одни диалоги повторно. Кабинету тоже досталось: днём новую версию не удавалось собрать, а к ночи вернулась пропавшая вкладка «История операций».
Итого: три восстановления на сервере данных, два на кабинете, четыре клиента без пробного периода.
Вывод простой и дорогой: в системе, где ходят деньги, скорость съедает то, что сделано. Две параллельные работы соединяют по очереди и с проверкой, а не в пятницу вечером.
Я это знал.
Знать и делать оказались разными вещами.
Себестоимость сообщения была одной цифрой на весь мир
Ещё одна субботняя история, про то, что мы не ломали, а нашли.

Себестоимость сообщения через официальный канал WhatsApp была одной цифрой, вписанной прямо в код. На весь мир. Формально страна определялась по первой цифре номера, но два кода страны в таблице совпали, и страна в расчёте не участвовала вовсе. Никто не проверял это на данных, потому что цифра «работала».
Разброс между странами почти втрое. При единой цене одна страна уже была для нас убыточна, а другая переплачивала заметно. Это кафе с одной ценой доставки на весь город: ближние переплачивают, дальние приносят убыток, и никто не замечает, пока не посмотрит на карту.
В субботу вечером ставки переехали в справочник по странам и категориям с датами действия. Списание стало одной операцией вместо трёх: раньше, если последний шаг не проходил, деньги были сняты, событие не помечено, и повторный проход списывал ещё раз. Сколько раз это успело случиться, я не знаю.
В ночь на воскресенье появился прогноз стоимости рассылки до запуска, а кнопка «Отправить» блокируется при нехватке средств. Прошлые записи сохранили: колонку переименовали, а не пересоздали, чтобы отчёты за прошлые недели не поехали.
Цифра, вписанная в код, это цена без даты пересмотра: через год никто уже не помнит, откуда она взялась. Наша дожила до августа и всё это время была права ровно для одной страны из списка.
Честная часть: себестоимость всего, что списали до субботы, уже не пересчитать, там записана старая единая ставка. Для вас это значит одно: если получатели в одной стране, цена стала честной для неё; если в нескольких, она теперь разная, и в обе стороны.
Служебные двери канала WhatsApp стояли открытыми
Дальше то, чего я боялся больше залпа.

В четверг один из клиентов написал, что его сотрудник не может выгрузить шаблоны. У владельца всё работает, у сотрудника нет. Восемь отказов за сорок секунд: человек жал кнопку снова и снова, как жмут кнопку лифта.
Права сотрудника проверяются в двух местах, и эти два места до сих пор никто не сверял. Шаблоны открыли на чтение, шесть разделов той же роли ещё отвечают отказом.
С этого мы полезли смотреть остальные двери и нашли обратное.
У службы официального канала WhatsApp есть адреса, до которых можно дотянуться из интернета. К пятнице при проверке на действующей платформе выяснилось: один из них отдавал список шаблонов без проверки, кто спрашивает, а соседний проверку требовал. Служебный вход с табличкой «только для персонала», но без замка.
Объяснение банальное: их делали для вызовов между своими службами и считали внутренними, «снаружи их никто не найдёт». В интернете это не аргумент.
Пять адресов оказались мёртвым кодом без единого вызова за неделю, их удалили. Остальные закрыли проверкой: часть ключом, часть служебной подписью. Заодно нашли, что при каждом старте в журнал попадало больше настроек бота, чем нужно. Убрали.
В субботу утром вторая дверь, и хуже первой. Отчёт по рассылке отдавал данные чужого заказчика: под ключом одного клиента запрос по рассылке другого возвращал её цифры. Закрыли в то же утро ответом «не найдено», а не «запрещено», чтобы не подтверждать даже существование чужой рассылки.
Помните место в тарифах, где можно было дотянуться до чужого клиента? Там дверь закрыли заранее: тарифы делали с нуля и прогоняли через проверки. Эту нашли уже открытой, и нашли случайно, зайдя сюда по другому делу.
Урок для любого, у кого есть своя интеграция: у службы, которая торчит в интернет, «внутреннего» адреса не существует. Про ключи чата на сайте и служебную страницу с метриками я рассказывал в 157-м выпуске: та же история.
За неделю ответ «успех» вместо ошибки нашёлся в пяти местах, в трёх разных службах. Как это выглядит для человека: он нажимает «отписаться», система отвечает «готово», отписка никуда не записывается, и через неделю ему приходит следующая рассылка.
Он уверен, что мы его обманули. Мы уверены, что всё сработало. В прошлом выпуске такой ответ я нашёл в одном месте и счёл его отдельным дефектом. Пять мест в трёх службах за одну неделю это уже не дефект, а манера: ответить «готово» дешевле, чем разобраться, что именно не вышло.
Удержание считали по абонементам, а надо по людям
Последний сюжет для тех, у кого секции, студии и салоны.

В прошлом выпуске я рассказывал, что закрыть занятие в расписании не мог никто. Показатели сотрудников считаются только по закрытым занятиям, так что считать их по-настоящему мы начали только сейчас. И сразу стало видно, что формула кривая.
В среду 12 августа расчёт удержания правили пять раз, последний раз ближе к полуночи: первая правка была разбивкой по абонементам, три следующие меняли формулу, пятая подтягивала детали.
Что было не так. Абонементы с датой истечения в будущем считались «не продлёнными». Купленный заранее не считался продлением, и удержание занижалось ровно у самых ответственных клиентов.
И главное: удержание считалось по абонементам, а не по людям. Клиент с пятью разовыми посещениями весил в пять раз больше клиента с месячным абонементом.
Это как считать посетителей магазина по чекам: постоянный покупатель с картой даёт один чек в месяц, случайный прохожий за пять кофе даёт пять, и в отчёте прохожий «важнее».
От удержания зависит бонус тренера. То есть каждая правка за среду меняла чью-то зарплату задним числом. Показатель занижался у тренера, чьи клиенты покупают абонемент заранее: самые лояльные портили ему статистику.
Теперь один клиент равен одному голосу, а продление засчитывается на всём сроке действия абонемента и семь дней после.
Правило, которое забираю: прежде чем чинить формулу, посмотри, кому по ней платят. Если никому, экспериментируй. Если платят, каждая правка это перерасчёт. С каких пор формула считала криво, я не скажу. Если бонус тренера у вас привязан к удержанию, август лучше пересчитать по новой.
И мелочь из того же ряда: история посещений обрезалась на ста записях, а «Всего: 100» показывало число загруженных строк, а не реальное. Владелец студии, у клиента которого визитов больше сотни, видел ровно сто.
Три коротких: контур, сайт и два хвоста
Российский контур начал получать собственный мозг: во вторник векторный поиск научился работать с российской моделью, в четверг появилась прослойка к ней, а в пятницу днём движок AI-продавца принял семь правок за два часа с пометками вроде «ещё подправил». Так и выглядит подключение новой модели: не по инструкции, а на ощупь. Для клиентов пока ничего, это скелет.

Сайт: больше семисот битых ссылок полгода жили в Яндексе, потому что перенаправления стояли внутри приложения, а блог шёл мимо него. Теперь ответ «удалено навсегда» отдаётся на входе в сервер. «Мы поставили редирект» не значит «редирект срабатывает»: проверять надо снаружи.
И два хвоста. Отмена рассылки не отменяла сообщения, которые планировщик уже взял в работу, и рассылка висела «Активна»: теперь отменяет. А рассылки в ядре два дня «залипали»: причина не найдена, задача открыта, и это единственное место в выпуске, где я не могу написать, чем всё кончилось.
Главный итог недели

Самая объёмная неделя августа. И самая дорогая из тех, что я помню. Не совпадение.
Тарифы и модули это попытка расти: дать бизнесу понятный чек вместо «сколько набежит». Залп, суббота и четыре клиента с остановленным ботом это счёт за попытку. Я не буду делать вид, что счёт выставил кто-то другой. Единицу поменяли мы, ветку модулей влили в пятницу вечером мы, запуск в субботу без проверки регистрации сделали мы.
Если бы я проживал неделю заново, я бы задержал модули до понедельника. Потерял бы три дня. Сэкономил бы субботу и четырёх клиентов, которые увидели «Бот остановлен» раньше, чем увидели бота.

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

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

Следующая неделя: две правки этой недели откачу сам и объясню, почему это правильно, а за выходные поднимется российский контур платформы, основная его часть, из того же кода.
Приходите в Telegram-канал
Если этот формат отчётов вам полезен, подпишитесь на наш Telegram-канал @botseller_ai. Там я каждую неделю выкладываю бортовые журналы и короткие заметки про продуктовые решения, эксперименты и инциденты. Без рекламы, без воды, только то, что мы сами считаем важным.
Если хотите попробовать Botseller в своём бизнесе, используйте кнопку регистрации в шапке сайта. Я не вставляю отдельную ссылку в текст: платформа сама выберет правильный путь входа в зависимости от контура и настроек.
FAQ
У меня действующий тариф. Что изменилось с появлением пакетов и модулей?
Ничего, пока вы сами не решите иначе. Поштучная оплата работает как раньше, а пакеты появились рядом, для тех, кому нужен предсказуемый чек. Модули докупаются отдельно: ещё один AI-сотрудник, ещё один канал, голосовые звонки, официальный WhatsApp, Рой и запуск под ключ. В пробном периоде ежемесячные модули бесплатны, разовый «запуск под ключ» покупается отдельно.
Я пополнил баланс ровно на нужную сумму, а бот всё равно остановился. Это тот случай?
Скорее всего да, если это было до 13 августа. Признак простой: вы заплатили ровно ту сумму, которую платформа сама вам и показала, а остановка пришла в ту же минуту, не через день. С 13-го такого не бывает. Напишите в поддержку: мы видим и момент пополнения, и момент остановки, и разберём вашу пару.
Почему моя рассылка ушла залпом, если я ставил паузу?
Со вторника по пятницу значение «1» в двух частях системы читалось по-разному: кабинет считал в минутах, ядро уже в секундах. С этой недели пауза уходит ровно в тех секундах, что подписаны под ползунком. Отказы «слишком часто» за те дни в отчёте именно оттуда.
В отчёте о рассылке стало четыре цифры вместо двух. Какая из них важная?
Последняя. «Ответили» это те, кто написал в ответ в течение 72 часов после доставки, и единственная цифра, которая напрямую переводится в деньги. Остальные три показывают, где теряются получатели: при большом числе отказов смотрите причину рядом с каждым, теперь она по-русски. Фильтр «Ответили» оставляет в списке только ответивших.
Правда ли, что цена сообщения теперь зависит от страны получателя?
Да, с середины августа себестоимость берётся из справочника по странам, а не из одной цифры на всех. Перед запуском рассылки видно её ориентировочную стоимость и хватит ли баланса.
Сотрудник не может открыть шаблоны WhatsApp, хотя у владельца всё работает. Что делать?
С этой недели шаблоны доступны роли сотрудника на чтение. Если отказ в другом разделе, это ещё не закрыто: шесть разделов ждут отдельного решения.
Как теперь считается удержание в показателях сотрудников?
Раньше клиент с пятью разовыми посещениями считался пять раз, а клиент с абонементом один, и у тренера с постоянными клиентами удержание выглядело хуже, чем у тренера со случайными. Теперь каждый человек считается один раз, а продлением считается любой абонемент, купленный пока действует текущий или в течение недели после. Проверьте августовские бонусы: у тренеров с лояльной базой показатель, скорее всего, вырастет.



