From 4eac8d8ff14f8152ada518423aa29cd3e86519db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Sun, 2 Aug 2026 16:14:54 +0300 Subject: [PATCH] =?UTF-8?q?docs(=D1=80=D0=B5=D0=BA=D0=BB=D0=B0=D0=BC=D0=B0?= =?UTF-8?q?):=20=D0=BF=D1=80=D0=BE=D0=BC=D1=82=20=D1=81=D0=BB=D0=B5=D0=B4?= =?UTF-8?q?=D1=83=D1=8E=D1=89=D0=B5=D0=B9=20=D1=81=D0=BC=D0=B5=D0=BD=D0=B5?= =?UTF-8?q?=20=E2=80=94=20=D0=BF=D0=B0=D1=87=D0=BA=D0=B0=204,=20=D0=B5?= =?UTF-8?q?=D0=B4=D0=B8=D0=BD=D1=8B=D0=B9=20=D0=BA=D0=B0=D1=80=D0=BA=D0=B0?= =?UTF-8?q?=D1=81=20=D1=82=D0=B5=D0=BB=D0=B5=D0=B3=D1=80=D0=B0=D0=BC-?= =?UTF-8?q?=D1=8D=D0=BA=D1=80=D0=B0=D0=BD=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Разведка сделана живьём, а не по памяти, и вскрыла две мины, из-за которых задание владельца «сделать как у Яндекса» нельзя выполнить в лоб: 1. Деньги у экранов РАЗНЫЕ. Яндекс берёт из рекламного кошелька (ad_wallets, баланс/заморожено/свободно), телеграм — общий баланс тенанта, причём frozen_rub отдаётся жёстко '0.00'. Вставить AdWalletHeader в телеграм — значит показать клиенту чужие деньги. Нужен тот же вид при своих данных. 2. Живого счётчика охвата без сервера не будет. У телеграма всего восемь ручек, оценки среди них нет; охват возвращает только POST /campaigns, а она создаёт черновик в базе. Дёргать её на каждое изменение поля — засорить базу. Нужна новая серверная ручка оценки. Отсюда совет владельцу: разбить пачку 4 надвое — 4а чистый фронт (вкладки, карточка денег, единый вид карточек кампаний), 4б мастер шагов и живой счётчик (требует бэкенда). Иначе смена кончится посередине. Названа и цена: на нынешнюю разметку телеграм-экрана завязано 45 тестов. Ориентиры даны с номерами строк, сверенными с живыми файлами; список меток разметки проверен поимённо — одну (tg-headline) я написал по памяти неверно, настоящая tg-ad-headline, поправлено до коммита. Прежний промт помечен отработанным, с указателем на этот. Co-Authored-By: Claude Opus 5 (1M context) --- .../2026-08-04-PROMT-podskazki-na-ekranah.md | 10 +- ...2026-08-05-PROMT-karkas-telegram-ekrana.md | 307 ++++++++++++++++++ 2 files changed, 313 insertions(+), 4 deletions(-) create mode 100644 docs/superpowers/2026-08-05-PROMT-karkas-telegram-ekrana.md diff --git a/docs/superpowers/2026-08-04-PROMT-podskazki-na-ekranah.md b/docs/superpowers/2026-08-04-PROMT-podskazki-na-ekranah.md index 93a467c5..c6d7ae99 100644 --- a/docs/superpowers/2026-08-04-PROMT-podskazki-na-ekranah.md +++ b/docs/superpowers/2026-08-04-PROMT-podskazki-na-ekranah.md @@ -1,9 +1,11 @@ # Промт следующей смене — Пачка 3: подсказки «?» на рекламных экранах -> ✅ **Работа этого промта ВЫПОЛНЕНА 02.08.2026** — подсказки стоят у 16 полей, тесты -> зелёные, на боевой не выкачено и глазами не принято. Итог — в разделе «Пачка 3» файла -> замечаний. Разделы «Что уже сделано», «Ловушки» и «Где всё стоит» ниже остаются -> действующими для пачки 4; задание в разделе «Работа смены» — уже история. +> ✅ **Работа этого промта ВЫПОЛНЕНА 02.08.2026** (коммит `6ae6457b3`) — подсказки стоят у +> 16 полей, тесты зелёные, на боевой не выкачено и глазами не принято. Итог — в разделе +> «Пачка 3» файла замечаний. +> +> 👉 **Действующий промт — [2026-08-05-PROMT-karkas-telegram-ekrana.md](2026-08-05-PROMT-karkas-telegram-ekrana.md)** (пачка 4). +> Этот файл держим только ради истории; замеры в нём устарели. Поставлено 02.08.2026 поздним вечером, после закрытия пачки 2. Всё ниже — живые замеры. diff --git a/docs/superpowers/2026-08-05-PROMT-karkas-telegram-ekrana.md b/docs/superpowers/2026-08-05-PROMT-karkas-telegram-ekrana.md new file mode 100644 index 00000000..4f8f25ca --- /dev/null +++ b/docs/superpowers/2026-08-05-PROMT-karkas-telegram-ekrana.md @@ -0,0 +1,307 @@ +# Промт следующей смене — Пачка 4: единый каркас телеграм-экрана + +Поставлено 02.08.2026 ночью, после закрытия пачки 3. Всё ниже — живые замеры этой смены. + +**Главный документ работы — [2026-08-02-ZAMECHANIYA-edinyy-vid-reklamnyh-ekranov.md](2026-08-02-ZAMECHANIYA-edinyy-vid-reklamnyh-ekranov.md).** +Там замечания владельца дословно, требования МТС к медиа и план всех пяти пачек. +Этот промт — вход, состояние и работа одной смены. + +--- + +## 🔴🔴🔴 Первое, что надо знать + +**Песочница ВЫКЛЮЧЕНА 02.08.2026 в 07:40 МСК — телеграм-реклама на ЖИВЫХ ДЕНЬГАХ.** +Клиент жмёт «Запустить» → списывается его баланс → робот реально платит в кабинете МТС. + +Откат: `TG_SANDBOX=true` в `.env` боевого → `sudo -u www-data php artisan config:cache` → +`sudo systemctl restart liderra-queue`. Копия настроек: +`/home/ubuntu/deploy-backups/.env.bak-pered-vyhodom-iz-pesochnicy-20260802`. + +Прочие красные линии: прод — только с явного «да» владельца, база по умолчанию **чтение**; +номера телефонов — ПДн, в задание роботу не класть; пуш **только в gitea** (GitHub мёртв); +владелец **не программист** — простым русским, короткими абзацами. + +--- + +## Работа смены — Пачка 4 + +Замечание владельца: два рекламных экрана выглядят как сделанные разными людьми. Яндекс — +опрятный кабинет, Телеграм — простыня на одной странице. + +### Как устроены оба экрана сейчас — замер + +**Яндекс** `AdvertisingYandexView.vue` — **97 строк**, чистая обёртка: + +```text +

Яндекс Аудитория> → «Мои кампании» | «Новая реклама» + → CampaignList | CampaignWizard +``` + +**Телеграм** `AdvertisingTelegramView.vue` — **608 строк** простыни. Ориентиры на 02.08 ночь: + +| Строка | Что там | +|---|---| +| 264 | `

Реклама в Телеграме по своей базе

` | +| 284 | `` — панель авто-рекламы вклинена ПЕРЕД формой | +| 288–289 | карточка «Новая кампания», деньги строкой подзаголовка: «Общий баланс: X ₽» | +| 430–441 | кнопки `tg-calc` «Рассчитать» и `tg-launch` | +| 452–465 | «Мои кампании»: `tg-campaigns`, строки `tg-campaign-row` | + +Вкладок нет, карточки денег нет, мастера шагов нет, кампании нарисованы простым списком +(`v-list-item`: заголовок — текст объявления, подзаголовок — статус и число кандидатов), +а у Яндекса — карточки с ярлыком, припиской и кнопками. + +### 🔴 Мина первая: деньги у экранов РАЗНЫЕ + +Проверено по коду, не по памяти: + +- **Яндекс** берёт из рекламного кошелька — таблица `ad_wallets`, поля `balance_rub` / + `frozen_rub`, свободно = баланс − заморожено (`AdvertisingWalletController.php:34`). +- **Телеграм** берёт **общий баланс тенанта** — `tenants.balance_rub`, а `frozen_rub` + отдаётся жёстко `'0.00'` (`Api/ClientTg/CampaignController.php:59-60`). + +**Просто вставить `` в телеграм-экран НЕЛЬЗЯ** — он покажет клиенту деньги +рекламного кошелька Яндекса, а спишутся другие. Это враньё дороже, чем некрасивый экран. + +Это не поломка: телеграм платит с общего баланса **по решению владельца** (коммит `6f469fb1` +«деньги на общем балансе»). Значит задача — **тот же вид при своих данных**: либо у +`AdWalletHeader` появляется вход «какой кошелёк показывать», либо рядом живёт свой такой же +на вид компонент. Обе дороги честные; первая меньше кода, вторая меньше риска задеть Яндекс. + +Слова «Заморожено» на телеграм-карточке при жёстком нуле лучше не показывать вовсе, чем +показывать всегда ноль — иначе клиент решит, что деньги не резервируются, и это тоже враньё. + +### 🔴 Мина вторая: живого счётчика охвата без сервера не будет + +Владелец просил «живой счётчик охвата вместо кнопки Рассчитать». У Яндекса он работает +отдельной ручкой `GET /campaigns/{id}/audience-size` (`web.php:453`) — мастер дёргает её с +задержкой на каждое изменение поля. + +**У телеграма такой ручки нет.** Все ручки модуля — восемь, вот они целиком +(`routes/web.php:101-112`): список кампаний, создать, показать, запустить, отменить, +пересдать, приложить медиа, плюс три на авто-правило. Охват возвращает **только** +`POST /campaigns` — а она **создаёт черновик в базе**. + +Значит дёргать её на каждый чих нельзя — базу засорит черновиками. Нужна **новая серверная +ручка оценки** (посчитать охват и смету, ничего не записывая). Это работа с бэкендом: +контроллер, маршрут, тесты Pest, права роли. + +### Совет по объёму: разбить пачку 4 надвое + +Работа заявлена как одна, но половины разные по цене и риску. Рекомендация — сделать так и +показать владельцу после первой половины: + +- **4а — чистый фронт, без сервера:** вкладки «Мои кампании» / «Новая реклама», карточка + денег сверху в яндексовом виде (со своими данными, см. мину 1), панель авто-рекламы — + внутрь вкладки, а не поперёк экрана, карточки кампаний в одном виде с яндексовыми. +- **4б — мастер шагов + живой счётчик:** требует новой ручки оценки на сервере и переделки + двухшагового потока «Рассчитать → Запустить» (спека §5, комментарии в коде на строках + 47, 140, 181). + +Если браться за всё сразу — смена кончится посередине, а экран останется разобранным. + +### Чем платим: тесты придётся править + +На нынешнюю разметку телеграм-экрана завязаны **45 тестов**: `advertising-telegram-view` +(25), `telegram-auto-rule-panel` (12), `podskazki-na-ekranah` (8, из них 4 про телеграм). +Переделка каркаса их сломает — это нормально и ожидаемо, но заложи время. + +🪤 **Правь тест только когда поменялся смысл, а не чтобы он позеленел.** Если тест ждёт +«кнопка Рассчитать есть», а мы её убрали — тест переписывается честно. Если тест ждёт +«запуск списывает деньги», а он покраснел — сломали дело, а не тест. + +### Опорные точки, которые нельзя потерять + +Метки, по которым тесты находят живое (ломать их = ломать проверки без пользы): +`tg-ad-text`, `tg-ad-link`, `tg-ad-headline`, `tg-audience-days`, `tg-phones`, `tg-budget-cap`, +`tg-ord`, `tg-media`, `tg-calc`, `tg-launch`, `tg-campaigns`, `tg-campaign-row`, +`tg-resubmit-*`, `tg-auto-*`, и `help-hint` — подсказки из пачки 3. + +### Чем кончается смена + +Либо «экраны похожи как два кабинета одной системы — вот что сделано, вот что осталось», +либо честное «не успел, вот где остановился». Приёмка глазами — всё равно пачка 5. + +--- + +## Что уже сделано + +### ✅ Пачка 1 — коммит `7922bffb` (на боевой НЕ выкачена) + +Заголовок объявления и картинка в **авто-правиле** (раньше их не было вовсе — авто со +ссылкой на сайт сгорело бы в кабинете уже после списания денег); проверка медиа по настоящим +требованиям МТС (`app/app/Rules/ClientTg/MtsMedia.php`, длительность и кадр видео читает +`app/app/Support/Mp4Probe.php` без внешних программ); цена показа с медиа показана ДО +загрузки файла; предохранитель — накопитель не запускает пачку без заголовка при рекламе +сайта; отказ сервера доходит до клиента его словами. + +Граница честности: длительность и кадр читаются только у mp4/mov/m4v; у webm/mkv/mpeg/wmv +проверяются формат и вес. + +### ✅ Пачка 2 — коммит `a2496dfe6` (на боевой НЕ выкачена) + +Замечание З-6: «почему статус крутится, когда она отклонена?» Экран физически не мог +показать правду — сервер не отдавал ни числа реальных показов, ни счётчиков принятых и +отклонённых объявлений. + +- сервер отдаёт `delivered_impressions` + счётчики объявлений **одним** запросом на весь + список (на N+1 стоит датчик); те же счётчики — в отчёте по кампании; +- ярлык по фактам: `running` при нуле показов → «Принято, показов пока нет»; пошли показы → + зелёное «Крутится»; часть отклонена → «часть объявлений отклонена — 2 из 15»; все → + красное «Отклонено» с причиной; +- 🔴 **правило перехода статусов НЕ тронуто** — на `rejected` висит возврат заморозки + (`AdWalletService::release`, «ВЫХОД 2»). Трогать его нельзя и в пачке 4; +- подписи собраны в один файл `composables/campaignStatusMeta.ts` (было ДВЕ копии, и они + уже разъехались); телеграмные — в `views/advertising/telegramStatusLabels.ts`. + +### ✅ Пачка 3 — коммит `6ae6457b3` (на боевой НЕ выкачена) + +Подсказки «?» у **16 полей**: телеграм-форма (дни сделок, лимит на объявление, ОРД, +картинка/видео), форма пересдачи (ОРД), панель авто-рекламы (порог 367, бюджет, дневной +лимит), мастер Яндекса (оба конца периода, срок показа, частота — на шаге и в сводке, цена +за тысячу), кошелёк (заморожено, свободно). + +- тексты — **один файл** `composables/podskazkiReklamy.ts`, 13 штук; поля ОРД и «Частота + показов» стоят в разметке дважды, и копий текста больше нет по построению; +- про ОРД написано словами владельца из ответа З-4, дословно; +- на очевидные поля («Текст объявления», «Ссылка», «Кошелёк») подсказки **нет намеренно**, + и на это стоит отдельный тест — чтобы следующая смена не навешала шума; +- язык стерегут датчики: ни одной латинской буквы, запрет жаргона, длина 40–200 знаков, + два-три предложения. + +🪤 **Подсказку в поле ввода вешать слотом `#append-inner`, а не `#label`** — метка у Vuetify +плавающая, при щелчке уезжает вверх и знак вопроса уехал бы с ней. Готовых образцов +«подсказка внутри поля» в проекте не было: все прежние стояли у чекбоксов и заголовков. + +--- + +## Что дальше (пачка 5) + +**Приёмка глазами обоих экранов подряд + выкат на боевой.** Смотреть в первую очередь: + +- как «?» смотрится внутри поля рядом с крестиком очистки у «Картинка или видео» + (тест доказал, что подсказка там есть, но как она выглядит — глазами не видел никто); +- одинаково ли называются статусы на двух экранах; +- не появилось ли двух карточек денег на телеграм-экране после пачки 4. + +--- + +## ⏸ Отложено владельцем — НЕ поднимать + +**Портал не хранит числа показов телеграм-кампании** (колонка `actual_cost_rub` есть, но её +не пишет ни одна строка кода; доставленных показов в таблице нет вовсе). Владелец 02.08: +«показывает, надо только запустить и начнёт показывать — не обращай внимание пока». +В пачки 4–5 не входит, по своей инициативе не трогать. + +--- + +## Где всё стоит — замер 02.08 ночью + +**`main` = ветка `fix/tg-zagolovok-obyavleniya` = `6ae6457b3`**, неотправленного 0, +рабочая папка чистая. + +### Боевой + +- Заголовок объявления на разовой форме доехал (выкат 02.08 днём), приёмка глазами пройдена. +- 🟡 **Откат того выката ещё лежит:** каталог `public/build-old-zagolovok` и архив + `/tmp/front-backup-2026-08-02-zagolovok.tgz`. Сутки прошли — можно убирать. +- 🔴 **Пачки 1, 2 и 3 на боевой не поехали.** В пачке 1 миграция (`client_tg_auto_rule`: + `ad_headline`, `media_path`) — выкат только с отдельного «да» владельца. +- Фронтенд собирается прямо на боевом (node 20.20.2, ~2,4 с). Безопасный порядок: собрать + в `public/build-new`, проверить, подменить `mv`, потом `chown -R www-data:www-data`. +- Телеграм: 7 таблиц `client_tg_*`, `TG_ROBOT_TRANSPORT=poll`, **`TG_SANDBOX=false`**. + +### Робот + +Живёт на машине владельца: `C:\liderra\mts-telegram-robot`, свой Node 20 +(`C:\liderra\node20\node.exe`), профиль браузера `C:\liderra\mts-bot-profile`. Стучится в +портал раз в минуту. Баланс МТС **5 010 ₽** — фактический потолок трат. + +⛔ Не ставить робота на сервер и не покупать прокси — обе дороги закрыты навсегда. + +### Тесты и сторожа + +- Экраны (их и трогает пачка 4): `cd app && npx vitest run` — **1787 тестов, 0 падений**, + 237 файлов, 3 пропущено, ~2,5 минуты. Замер этой смены. +- Реклама Яндекса: `cd app && DB_DATABASE=liderra_testing_zag php artisan test --filter=Advertising` + — **435, 0 падений**. Телеграм-модуль: то же с `--filter=ClientTg` — **281, 0 падений**. + Замер вечера 02.08; PHP в пачке 3 не трогали. +- Статанализ: `cd app && composer stan` — **0**. Формат: `composer pint -- --dirty`. +- Проверка типов: `npm run type-check` — **7 ошибок в чужих файлах** (автоподбор, проекты, + старые спеки рекламы), они были до нас. Смотреть, не добавилось ли **своего** файла. +- Робот: `cd bots/mts-telegram-ads && npm test` + +🪤 Гонять из папки `app`, иначе «Could not open input file». + +--- + +## Что остаётся за владельцем + +1. 🔴 **Стена площадки: минимум 367 номеров**, у самого крупного клиента 112. Из сделок + порог не набрать — но клиент может загрузить **свой список**, и тогда пойдут живые деньги. +2. **Чтение вердикта модерации (`read-status`) не проверено ни разу.** Вскроется на первом + живом запуске: не прочитает робот ответ МТС — кампания провисит 48 часов и уйдёт в + «нужен разбор», деньги при этом не вернутся (реклама могла показываться). +3. **Токен робота засветился в выводе команды** 02.08 (в файлы и коммиты не попал). + Перевыпустить, когда будет удобно. +4. **Пачки 1, 2 и 3 надо принять глазами и решить про выкат.** + +--- + +## Ловушки + +### Правка кода + +- 🪤 **Причёсывалка (`prettier --write`) переписывает ВЕСЬ файл**, если он не был причёсан + до тебя. 02.08 телеграм-экран так дал 296 изменённых строк вместо 24 — 250 из них чужое + форматирование, за которым пропадает своя правка. Датчик: сравнить `git diff --stat` и + `git diff --stat -w`; разошлись — почти всё пробелы. Лечение: `git checkout HEAD -- <файл>` + и применить только свою правку руками. +- 🪤 Проверять, был ли файл причёсан ДО тебя, надо **внутри `app/`**: + `cd app && git show HEAD:app/<путь> > proverka.vue && npx prettier --check proverka.vue && rm proverka.vue`. + Во временной папке нет `app/.prettierrc.json` — причёсывалка меряет чужой меркой и врёт, + что не причёсано вообще всё. Замер 02.08: телеграм-экран, панель авто и мастер Яндекса + **не причёсаны**, кошелёк — причёсан. +- 🪤 **Итоги группировки — не модели.** Запрос с `groupBy` + `count(...) as total` через + модель Eloquent даёт строки, притворяющиеся моделью, и статанализ ругается на + несуществующие свойства. Лечение — `->toBase()` перед `->get()`. +- 🪤 **Тесты экранов лежат в `app/tests/Frontend/`**, а не рядом с кодом. Их 237 файлов. +- 🪤 **Имён колонок и таблиц наизусть не помнить.** Кампании Яндекса — `ad_campaigns`, + объявления — `ad_campaign_banners`, правило авто-телеграма — `client_tg_auto_rule` + (единственное число!), рекламный кошелёк — `ad_wallets`. Сперва `information_schema`. +- 🪤 **Переменные оболочки в путях временных файлов** дали мусор `app/$out` и `app/$TEMP/` + прямо в рабочей папке. Писать временное в каталог-черновик сессии, а не в `app/`. + +### Гит и сторожа + +- 🪤 **После НОВОГО тестового файла на PHP статанализ краснеет** — это шум `$this` в Pest, + гасится `app/phpstan-baseline.neon`. Пересобрать: + `php vendor/bin/phpstan analyse --memory-limit=512M --generate-baseline`, потом **глазами** + сверить diff: должны добавиться только твои файлы, удалений быть не должно. +- 🪤 **Номер записи в `db/CHANGELOG_schema.md` брать как максимум по ВСЕМ веткам плюс один.** + Последняя занятая — **v9.64** (пачка 1). Пачка 4а схему трогать не должна; 4б — только + если ручке оценки понадобится что-то в базе (скорее всего нет). +- 🪤 **Коммитить явными путями.** Машинный `docs/observer/STATUS.md` переписывается хуком + после каждого коммита и молча уезжает в следующий. Снимать `git restore --staged`. +- 🪤 **Штатно падают два сторожа, оба не на нашей работе:** `gitleaks-full-history` и + `lychee-links`. Отключать на **один** пуш: + `LEFTHOOK_EXCLUDE=gitleaks-full-history,lychee-links git push …`. +- 🪤 Один «Errors: 1» в прогоне экранов приходит из `AutopodborManualCompetitorError.spec.ts` + — оборванный сетевой запрос в чужом наборе, был до нас. +- 🪤 Многострочное сообщение коммита — heredoc `-F -`. Коммит с хуками идёт ~12 секунд. + +### Боевой + +- 🔴 **Заливку скрипта и его запуск не соединять** одной командой — виснет на две минуты. + Два отдельных вызова: залить → выполнить → прочитать файл результата. +- 🔴 **Вывод писать в файл** (`file_put_contents`); `echo` из tinker не доезжает. + **Нет файла ⇒ скрипт УПАЛ**, а не «данных нет». +- 🔴 **`config:cache` / `optimize` — от `www-data`, НЕ от root.** От root портал ложился на 18 минут. +- 🔴 **Полный overlay на боевой ЗАПРЕЩЁН** — катить поимённым списком файлов. +- 🪤 `sudo -u postgres psql` на боевой машине — **СТАРАЯ копия**. Живая база — Managed PG. +- 🪤 Демо-вход `admin@demo.local` **не работает с 01.07** — тестовых учёток на бою нет, все + 10 тенантов живые. Для приёмки глазами просить доступ у владельца. + +--- + +Работа идёт **пачками**: после каждой владелец делает компакт. Не хвататься за всё сразу.