Files
portal/bots/mts-telegram-ads
Дмитрий d50a93e55c feat(телеграм-робот): боевой режим пересдачи отклонённой кампании (mode:resubmit) — проверено живьём
Хвост №1 из STATE ревью-правок: оформили доказанный в A2 путь пересдачи в
постоянный режим робота mode:'resubmit'. Робот берёт ОТКЛОНЁННУЮ кампанию, входит
в её редактор через «Исправить», вносит исправления и повторно отправляет на
модерацию БЕЗ ОПЛАТЫ (0 ₽ — деньги не списываются).

Что нового:
- parseResubmitTask (task.js): своё задание пересдачи — campaignId + submitMode
  (draft|live, без дефолта, чтобы live не случился сам) + правки на выбор
  (moderatorFile и/или adText/buttonUrl/ordCategory). Нужна хоть одна правка —
  иначе тот же контент снова отклонят. Номера/бюджет не нужны (уже у кампании).
- openResubmitEditor (cabinet.js): нативный клик «Исправить» в строке кампании по
  id → ждём редактор /telegram-a2p/{id}/message (в чужую кампанию не лезем).
- submitWithoutPayment (cabinet.js): на /payment жмём ТОЛЬКО «Отправить на
  модерацию без оплаты»; денежные кнопки («Списать…»/«Оплатить») — двойная защита
  через isForbiddenButtonText, не жмём никогда.
- editResubmitFields + вынос fillAd в хелперы (fillAdText/fillAdLink/
  selectOrdCategory/fillAdMedia): пересдача правит только заданные поля тем же
  проверенным кодом (DRY, поведение fillAd не изменилось).
- runResubmit (runner.js) + ветка mode:'resubmit' в bin/run.js (до parseTask, как
  read-status). draft — предохранитель (до /confirmation, не шлём); live — отправка
  без оплаты.

Живая проверка на реальных отклонённых кампаниях (28.07.2026):
- DRAFT (2231132, правка текста + документ): вошёл «Исправить» → правка → загрузка
  документа → /confirmation → НЕ отправил (resubmitted:false, stoppedAt:confirmation).
- LIVE (2231134, правка текст+ссылка+ОРД, без документа): полный цикл → «без оплаты»
  (0 ₽) → resubmitted:true; read-status подтвердил moderating. Баланс не тронут.

Робот npm test 110/110 (было 94, +16). Приёмочный лист и живые результаты:
docs/superpowers/2026-07-28-robot-resubmit-mode-ACCEPT.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-28 16:43:58 +03:00
..

МТС-бот «Реклама в Telegram по своей базе»

1. Что это

Робот сам заходит в кабинет МТС Маркетолог (marketolog.mts.ru) и создаёт рекламную кампанию в Telegram по загруженной базе телефонов клиентов. Работает на Windows-сервере рядом с мостом LiderraMtsBridge (тот же сервер, что для СМС МТС). У робота два режима: «черновик» (доходит до кнопки запуска, ничего не тратит) и «боевой» (нажимает кнопку и списывает деньги с баланса кабинета).

2. ⚠️ Важные предупреждения (прочитать первым)

  • Кабинет МТС — это реальные деньги. На балансе кабинета лежат настоящие рубли. Робот в режиме «боевой» их тратит. Пока идёт наладка — запускать только «черновик».
  • Живой вход в кабинет = доступ к деньгам. Профиль браузера бота (папка, указанная в MTS_BROWSER_PROFILE_DIR) — это как ключ от кассы: хранить на сервере, не копировать, никуда не выкладывать, не отправлять по почте/в чат.
  • Телефоны клиентов — персональные данные (152-ФЗ). Робот держит их только во временном файле на время прогона и удаляет сразу после — файл не остаётся на диске и не попадает в git. В боевых кампаниях использовать только базу с согласием клиентов на рекламные звонки/сообщения, не старые лиды без согласия.

3. Разовая настройка (один раз)

Установка зависимостей и браузера:

cd bots/mts-telegram-ads
npm install
npx playwright install chromium

Скопировать .env.example в .env и заполнить:

Переменная Что это
MTS_BROWSER_PROFILE_DIR папка на диске, где браузер бота хранит вход в кабинет (профиль)
MTS_CABINET_URL адрес главной страницы кабинета МТС Маркетолог
MTS_TELEGRAM_URL адрес раздела «Реклама в Telegram» в кабинете
SMTP_HOST, SMTP_PORT адрес и порт почтового сервера для отправки писем (Unisender Go)
SMTP_USER, SMTP_PASS логин и пароль для отправки писем (те же креды, что у портала)
ALARM_FROM с какого адреса приходят письма-алярмы/отчёты
ALARM_TO на какой адрес слать письма-алярмы/отчёты
BUDGET_CAP_RUB потолок бюджета в рублях: боевой запуск дороже этой суммы робот запрещает сам
HUMAN_DELAY_MS пауза между действиями робота в кабинете (мс) — «по-человечески», не чтобы сайт заподозрил робота

Разовый вход в кабинет. Один раз нужно открыть браузер бота в видимом режиме и вручную залогиниться (телефон/пароль + код по СМС) — после этого вход запомнится в профиле браузера, и робот дальше сможет заходить сам. Команда:

node bin/login.js

(или npm run login). Откроется окно браузера на странице кабинета — войти руками, как обычно (телефон/пароль + код по СМС). После того как в окне появится кабинет, вход сохранён в профиле браузера — окно можно закрыть. Это действие делает владелец (у него доступ к телефону/паролю кабинета).

4. Файл с номерами

  • Формат: по одному номеру в строке, вид 79000000000 (11 цифр). Робот сам приводит к этому виду номера вида «+7…», «8…», убирает лишние символы и повторы.
  • Требование кабинета: минимум 367 номеров «не МТС». Реклама в Telegram по своей базе показывается только абонентам НЕ-МТС (по МТС-номерам из той же базы можно отправить СМС — в боте это выключено).
  • Куда класть файл: в папку screenshots/ (она в .gitignore — номера не попадут в git). В примере задания путь screenshots/test-phones.txt.
  • Где взять тестовую базу: XLSX-экспорт лидов из старого кабинета поставщика crm.bp-gr.ru — эту выгрузку делает владелец.

5. Формат задания (task.json)

Поле Обязательное Что это
mode да draft (черновик, безопасно) или live (боевой, тратит деньги)
phonesFile да путь к файлу с номерами
adText да текст объявления (до 160 символов)
adTitle да заголовок объявления (до 40 символов)
buttonUrl да ссылка — что рекламируем (канал/бот/сайт)
budgetRub да бюджет кампании в рублях
cpmRub да цена за 1000 показов, рубли
ordCompanyName да название компании/сервиса — для маркировки рекламы (ОРД)
ordCategory нет категория товара/услуги для ОРД, по умолчанию «Размещение рекламы»
mediaFile нет путь к картинке/видео объявления
clientTag нет своя метка для учёта (не используется кабинетом)

Пример (файл task.example.json):

{
  "mode": "draft",
  "phonesFile": "screenshots/test-phones.txt",
  "adText": "Подключите наш телеграм-бот и получайте заявки быстрее",
  "adTitle": "Лидерра — заявки на автопилоте",
  "buttonUrl": "https://liderra.ru",
  "budgetRub": 1000,
  "cpmRub": 400,
  "ordCategory": "Размещение рекламы",
  "ordCompanyName": "Лидерра"
}

6. Запуск

Черновик (безопасно, ничего не тратит):

node bin/run.js --task task.example.json

Робот дойдёт до кнопки запуска, снимет скриншот шага и не нажмёт её. На почту (ALARM_TO) придёт отчёт.

Боевой (тратит деньги): то же самое, но в задании "mode": "live". Запускать только с разрешения владельца и в пределах потолка BUDGET_CAP_RUB — робот сам сверяет бюджет задания с потолком и отказывается запускать, если бюджет больше.

Результат прогона печатается в консоль в виде JSON, например {"ok": true, "matched": 996, "launched": false}matched это сколько номеров «не МТС» нашлось, launched — нажал ли робот кнопку запуска.

6.1. Пересдача отклонённой кампании (mode: "resubmit")

Если модерация МТС отклонила кампанию, робот может её починить: войти в редактор через «Исправить», внести исправления и снова отправить на модерацию без оплаты (0 ₽ — деньги не списываются).

Что исправляем — на выбор (в ответ на причину отказа): приложить документ модератору (лицензию/справку) и/или поправить текст/ссылку/категорию ОРД. Нужна хотя бы одна правка — иначе тот же контент снова отклонят. Номера/бюджет не нужны — они у кампании уже есть.

Поле Обязательное Что это
mode да resubmit
campaignId да номер кампании, которую чиним (из кабинета)
submitMode да draft (дойти до конца, не отправлять) или live (отправить без оплаты)
moderatorFile нет* путь к документу для модератора (pdf/картинка)
adText нет* новый текст объявления
buttonUrl нет* новая ссылка (канал/бот/сайт)
ordCategory нет* новая категория ОРД

* хотя бы одно из полей-правок (moderatorFile/adText/buttonUrl/ordCategory) обязательно.

{
  "mode": "resubmit",
  "campaignId": "2231134",
  "submitMode": "live",
  "moderatorFile": "screenshots/licenziya.pdf",
  "adText": "Исправленный текст объявления"
}

submitMode: "live" реально отправляет кампанию на повторную модерацию (бесплатно) — запускать только с разрешения владельца. Результат: {"ok": true, "campaignId": "2231134", "resubmitted": true}.

7. Присмотр за входом (keep-alive)

Команда node bin/keepalive.js тихо проверяет, жив ли вход в кабинет. Если вход слетел — робот сам отправляет письмо-алярм на ALARM_TO.

Чтобы проверка шла сама каждые 15 минут, добавить задачу в Планировщик заданий Windows (пример команды, путь заменить на реальный на сервере):

schtasks /create /tn "LiderraMtsTgKeepAlive" /tr "node C:\путь\bots\mts-telegram-ads\bin\keepalive.js" /sc minute /mo 15 /ru СИСТЕМА

8. Что делать при алярме на почте

Письмо приходит с темой вида «[МТС-бот] АЛЯРМ на шаге «...»» и приложенным скриншотом. Частые причины:

  • «Вход слетел — нужен повторный логин» — повторить разовый вход из раздела 3.
  • «недостаточно номеров не-МТС» (меньше 367) — нужна база побольше.
  • «Шаг «Стоимость» ещё не размечен» — это ожидаемо на сегодня, см. раздел 9.

9. Текущее состояние / что ещё не готово (честно)

Реализованы и проверены (юнит-тесты ядра — все зелёные, см. npm test) шаги:

  • вход в визард кампании;
  • выбор «Своя база клиентов»;
  • загрузка базы и подсчёт «не МТС»;
  • проверка порога 367 «не МТС» (ниже — честный алярм «недостаточно номеров не-МТС», кампанию не создаём) и переход со шага «Аудитория» на «Объявление» (кнопка «Продолжить», с само-проверкой, что попали на нужный шаг, а не заполняем объявление вслепую на чужой странице);
  • заполнение объявления (текст, заголовок, ссылка, блок ОРД);
  • финал: черновик — стоп перед кнопкой, боевой — нажатие кнопки.

Не готово:

  • Шаг «Стоимость» (бюджет/CPM) в кабинете пока не размечен — точные места на экране, куда робот должен кликать, ещё не сняты вживую. До этого робот на этом шаге штатно останавливается и шлёт алярм — это ожидаемо, не поломка.
  • Часть полей объявления (точное место поля «Заголовок», «Название компании» для ОРД, поле для картинки/видео) помечены в коде как требующие подтверждения — они снимаются на первом реальном черновике.
  • Приёмка «боевого» режима (один контрольный запуск на минимальном бюджете) — только с явного разрешения владельца.

10. Устройство (кратко)

Файл Назначение
src/config.js читает .env, проверяет, что все нужные настройки заданы
src/task.js читает и проверяет задание (task.json)
src/phones.js приводит номера к формату 79..., убирает мусор и повторы
src/budget.js проверяет, что бюджет боевого запуска не выше потолка
src/mailer.js отправка писем-алярмов и отчётов на почту
src/browser.js открывает браузер с сохранённым профилем (живым входом)
src/session.js проверяет, жив ли вход в кабинет
src/cabinet.js шаги визарда кабинета: вход, загрузка базы, объявление, финал
src/runner.js весь прогон целиком: собирает шаги по порядку, ловит ошибки, шлёт алярм/отчёт, чистит временный файл с номерами
bin/run.js команда запуска одного задания
bin/keepalive.js команда проверки живого входа (для Планировщика Windows)
docs/cabinet-flow.md подробная карта кабинета МТС — какие кнопки/поля где находятся