docs(реклама): ещё три находки приёмки глазами — мёртвый пункт «Моя база», минус на медиа, срок показа

Все три нашлись из вопросов владельца, глядя на живой экран. Ни одну не
увидели 1832 теста экранов и 292 теста телеграм-модуля.

1. «Моя база номеров» ведёт в никуда. Пункт читает client_tg_contacts, а в
эту таблицу не пишет ни одна строка кода: ни экрана загрузки, ни серверной
ручки, ни переноса из сделок. У ЛЮБОГО клиента пункт всегда покажет ноль.
Тесты зелёные потому, что каждый сам вписывает контакты перед проверкой, —
голый шов: состояние собирается руками, а дойти до него нечем.

2. С медиа наценка съедается, на видео уходит в минус. Клиент платит
тариф x1.40 (630/560/504 ₽ за тысячу по ступеням), МТС берёт 600 с
картинкой и 680 с видео. clientEstimateRub() принимает только число
показов — медиа на цену для клиента не влияет ни в оценке, ни в списании.
На кампании от 5000 показов с видео убыток 120 ₽ за тысячу. Песочница
выключена, деньги живые.

3. Срок показа нигде не объяснён. Портал сроком не управляет вовсе: в
задании роботу нет ни одной даты. Срок ставит кабинет МТС по умолчанию —
сегодня + 7 дней, каждому человеку один показ. «Лимит на объявление» —
потолок-предохранитель, а не длительность.

Ничего не чинил: все три — решения владельца, записаны с дорогами выбора.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Дмитрий
2026-08-02 19:33:34 +03:00
parent 9e23c59e60
commit 46e1adecba
@@ -454,6 +454,97 @@ webm/mkv/mpeg/wmv проверяются формат и вес, остальн
«Выберите, кому показывать, — посчитаем охват.» Но выбор-то уже сделан — не хватает самих
номеров. Поломкой не выглядит, но фраза не про ту ситуацию. Мелочь, **решение за владельцем.**
#### 🔴 Находка 4 — «Моя база номеров» ведёт в никуда: загрузить базу некуда
**Нашёл владелец за полминуты, глядя на экран** (02.08.2026): выбрал «Моя база номеров»,
увидел ноль и спросил — «а куда эту базу загружать?».
Ответ: **никуда.** Пункт читает `client_tg_contacts`. Замер по всему проекту: в эту таблицу
**не пишет ни одна строка кода**. Есть только миграция, модель и чтение в
`TelegramAudienceService::fromBase()`. Ни экрана загрузки, ни серверной ручки (в телеграм-модуле
их 10 — `routes/web.php:100116`, среди них нет ни одной про контакты), ни переноса из сделок,
ни задания-заливщика.
Значит, у **любого** клиента этот пункт всегда покажет ноль — это не пустота демо-организации.
**Почему не поймали 292 зелёных теста ClientTg:** каждый тест сам вписывает контакты
(`Contact::create(...)` в `AudienceServiceTest.php:67`, `:116`, `:132` и далее). Проверяется
«если контакты есть — охват считается верно», а до состояния «контакты появились» тест не
доходит, потому что дойти туда нечем. Ровно класс «голый шов»: тест СОБИРАЕТ состояние руками
вместо того, чтобы ДОЙТИ до него.
Рабочих путей из трёх — два: «Свежие сделки за период» (читает `deals`) и «Свой список номеров»
(номера печатаются в поле, уходят в `client_tg_campaign_phones`). Оба проверены живьём.
**Решение за владельцем — две дороги:**
1. **Убрать пункт** с экрана (и из авто-правила, если он там есть) — честно, быстро, ничего не
обещает впустую.
2. **Сделать загрузку базы** — экран заливки файла + ручка + разбор номеров + стоп-лист. Это
отдельная пачка, не мелкая правка.
🔴 **До решения этот пункт нельзя катить на боевой в нынешнем виде:** клиент выберет «свою
базу», увидит ноль и решит, что портал потерял его клиентов.
#### 🔴 Находка 5 — с медиа наша наценка съедается, а на видео уходит в минус
**Вскрылось из вопроса владельца 02.08** «цена на 40% больше, а в течение какого срока
показываться будет?».
**Что клиент платит нам.** Ступенчатый тариф `client_tg_tariffs` × наценка
`TG_MARKUP = 1.40` (+40%), считает `TelegramTariffService::clientEstimateRub($impressions)`.
Ступени (₽ за показ, до наценки): 0.45 / 0.42 (от 1000) / 0.40 (от 5000) / 0.38 (от 10000) /
0.36 (от 50000). С наценкой это **630 / 588 / 560 / 532 / 504 ₽ за тысячу**.
**Что берёт МТС.** Замер живьём в кабинете 02.08 (см. «💰 Медиа удорожает показы»):
**с изображением 600 ₽ за тысячу, с видео 680 ₽**. Базовая ставка без медиа — по комментарию
в `bots/mts-telegram-ads/src/cabinet.js:556` ≈400 ₽ за тысячу; **живьём не переподтверждено**.
**Беда:** `clientEstimateRub()` принимает ТОЛЬКО число показов. Медиа на цену для клиента
**не влияет вообще** — ни в оценке, ни в списании (`CampaignController.php:204`, `:307`).
| Объём | Клиент платит нам | МТС без медиа ≈400 | МТС с картинкой 600 | МТС с видео 680 |
|---|---|---|---|---|
| до 1000 | 630 | +230 | **+30** | **50** |
| от 5000 | 560 | +160 | **40** | **120** |
| от 50000 | 504 | +104 | **96** | **176** |
То есть на кампании с видео портал платит МТС больше, чем берёт с клиента. Чем крупнее
кампания, тем больше убыток.
При этом подсказка у поля медиа честно говорит клиенту «с картинкой показ стоит дороже —
600 ₽ за тысячу, с видео 680 ₽», а счёт ему выставляется тот же самый. Обещание и счёт
разошлись в разные стороны.
**Решение за владельцем — дороги:**
1. **Считать медиа в цене**: передавать в `clientEstimateRub()` признак медиа и брать за такие
показы отдельную ставку (тариф со ступенями «без медиа / картинка / видео»).
2. **Оставить как есть** — сознательно доплачивать за медийные кампании ради привлекательности.
3. **Не давать медиа**, пока цена не разведена.
🪤 Ловушка: пока `TG_SANDBOX=false`, это **живые деньги**. Первая же крупная кампания с видео
уйдёт в минус молча — портал нигде не сравнивает свою цену с ценой МТС.
#### ⏱ Срок показа: 7 дней, а не «пока лимит не кончится»
Ответ на второй вопрос владельца. Портал сроком **не управляет вообще** — в
`client_tg_campaigns` нет ни одного поля с датой, и в задании роботу
(`RunTelegramCampaignJob.php:109120`) передаются только текст, ссылка, заголовок, лимит,
категория ОРД и файлы. Даты там нет.
Срок задаёт кабинет МТС **своими значениями по умолчанию**, робот их не трогает
(`bots/mts-telegram-ads/src/cabinet.js:555563`): **показать каждому 1 раз, даты «сегодня →
+7 дней», автозапуск после модерации включён.**
Значит: **окно показа — 7 дней**, каждый человек видит объявление **один раз**, поэтому всего
показов примерно столько же, сколько людей в аудитории. «Лимит на объявление, ₽» — это
**потолок-предохранитель**, а не то, что растягивает или сокращает показ.
🔴 На экране этого не написано нигде. Клиент не знает ни про 7 дней, ни про «один раз
человеку». **Решение за владельцем:** дописать в подсказку к лимиту или отдельной строкой в
сводке шага «Проверка и отправка».
#### Что осталось за приёмкой глазами
**Боевой не смотрели.** Всё выше — локальная версия. На боевом экраны выглядят иначе как