← все проекты

LeadForge AI

Платформа лидгена: Авито-машина, Директ-машина, email-аутрич, мультитенант. Ядро лидгена MyVision.

repo: aitodo:/mnt/docker-data/leadforge-ai (git на сервере)server: aitodo, pm2 leadforge-*, lf-postgres:5437docs: docs/YD-PIPELINE.md, docs/etalons/память: leadforge-avito-mechanics, leadforge-yd-pipeline, leadforge-offer-system
готовS1 · Tenant Identity (1A.0.5)1/5

Цель: Идентичность тенантов

Tenant identity
закрыт ранее
feature
Вход одной кнопкой вместо Client ID и Secret
Предпринимателю нечего делать со словами Client Secret. У всех трёх площадок вход кнопкой возможен: Авито — OAuth2 authorization_code; Яндекс Директ — страница Яндекс ID с кнопкой «Разрешить»; ВК — либо agency_client_credentials (клиент не вводит ничего, просто передаёт кабинет агентству), либо authorization_code по заявке в ads_api@vk.team. Нужно: зарегистрировать наши приложения на трёх площадках (одноразово, действие владельца), потом написать /oauth/<платформа>/start и callback по образцу существующего amocrm.
feature
Причесать интерфейс кабинета: адаптив
Кабинет плохо адаптируется под узкие экраны. Проверить настройки, рекламные кабинеты, дашборд на 390, 768, 1024.
feature
Авито ISKRA: кабинет подключён, изоляция проверена
Кабинет клиента подключён и читается его же доступом. Пересечений с нашим ноль: у Искры 34 объявления, у нас 15, фиды пишутся в разные папки по компаниям. Что у них: все по 990 руб, заголовки-ключи через слэши, размножены по 14 городам, покрыты футбол/хоккей/баскетбол/волейбол/регби/лёгкая атлетика. ПРОБЛЕМА: рубрики смешаны — часть в «Спорт и отдых», часть в «Предложение услуг», при том что категория важнее ключевых слов.
feature
ВК ISKRA: рекламного кабинета нет, прислали токен сообщества
Сотрудник клиента прислал ключ vk1.a... — это токен сообщества «ISKRA | Производитель спортивной формы» (iskra_sport, id 240149869), для рекламы не годится: ads.getAccounts отвечает «method is unavailable with group auth». Callback API, который ему показали, — про уведомления сообщества, не про рекламу. НУЖНО: клиент создаёт рекламный кабинет на ads.vk.com, затем Общие настройки → Доступ к API → Запросить доступ, и присылает Client ID и Secret. Токен сообщества сохранён — пригодится для лид-форм и сообщений, но это отдельная задача.
feature
готовS2 · Multi-tenancy + RLS (1A.1)2/2

Цель: Полная изоляция тенантов

RLS-политики
pen-test 72/0
feature
jose JWT + SET LOCAL
feature
готовS3 · Авито-машина v28/8

Цель: Автономный конвейер Авито

Фикс kill-правила (слепота к чат-лидам)
strategist.ts: leads7d обязателен
feature
Статус-синк с Авито
каждые 6ч; авто-restore выключен после дублей
feature
Бюджет-гейт (аванс<500р)
avito-spend-gate.ts
feature
Дедуп-гард + библиотека картинок
новые без фото не публикуются
feature
Лайфсайкл: тексты→обложка→цена→вывод с уроком
уроки в TG
feature
Пул 31 оффер-направление из штаба
sync_agency_offers.py
feature
Санитайзер суррогатов LLM (0xd0)
feature
Чистка дублей Консультаций
фид пересобран
feature
В РАБОТЕS4 · Директ-машина17/18

Цель: Директ как у сильного директолога

Директолог-аналитик (разбор в TG)
yd-analyst.worker
feature
Аналитик YD Фаза 1: анализатор по всем данным + автономия + бэкофис
yd-dimensions (ключ/слот-позиция/пол×возраст/устройства/гео + пороговые находки), политика автономии yd-autonomy (safe→auto, spending→approval, переключатель assisted→full), таблица yd_insights, подключён в еженедельный воркер, вкладка «Директолог» в бэкофисе. Проверено на живых кампаниях.
feature
Уроки аудита B2B-Директа вшиты в пайплайн
Компилированный интент-фильтр семантики (yd-keyword-intent, интегрирован в expandKeywordsViaWordstat), комбинаторные 7+3 объявления в yd-executor (search+РСЯ), 272 минус-фразы, эталон Э9. Задеплоено (pm2 restart).
feature
КЗ: стратегия «максимум конверсий» + цели registration/purchase; разметка сайтов
КЗ 712193779 → WB_MAXIMUM_CONVERSION_RATE по цели формы (лимит 1500/нед). Созданы цели registration+purchase в Метрике КЗ. Разметка MyVision+LeadForge сайтов (form_open+lead_form reachGoal) на проде.
feature
Миграция кабинета под 24leadforge.ru/app
nginx path /app + прокси /api на aitodo через https, куки host-only. Вход проверен живым логином. Сброшен пароль владельца.
feature
Редизайн посадки 24leadforge.ru: сервис + реальные скрины + форма регистрации
Позиционирование сервис-платформа (не внедрение). Реальные скрины кабинета (Реклама/Директолог, Лиды, Агенты) через headless. Форма «заявка на регистрацию» без гейта 200к, цель registration. Тестовые лиды для скрина заведены и удалены.
feature
Корректировки аудитории через API (bidmodifiers)
Разгадан bidmodifiers API: get требует Levels ВНУТРИ SelectionCriteria (без него молча падает 8000), add отдаёт Ids массивом. Вшито в yandex-direct.ts: +IncomeGradeAdjustments (платёжеспособность), Ids-парсинг, ошибки из AddResults[].Details, новый getBidModifiers(+Levels). Применены B2B-корректировки на КЗ/MyVision/LeadForge: income VERY_HIGH=+30%/HIGH=+15% (Топ платёжеспособных), КЗ демо искл<18 + -50% на 25-34. Confirmed end-to-end через сам клиент.
feature
Запуск кампаний разблокирован: замкнут цикл предполётной проверки
Гейт требовал запись в campaign_preflight_runs и был fail-closed, а runPreflight() не вызывался ниоткуда — таблица пустовала, любой запуск блокировался навсегда. Теперь гейт сам проводит проверку по фактическому состоянию кампании; врезка внутри call(), поэтому закрыты все пути запуска.
preflight/yd-collect.ts + врезка в yd-guard; проверено на живом кабинете (91 кампания)
feature
Предполётная проверка перестала давать ложные нарушения
ads.get не запрашивал SitelinkSetId, поля CalloutIds не существует (уточнения в AdExtensions), хеш картинки выдавался за креатив из банка.
на кампании 58516629: было 143 нарушения, стало 73 — все настоящие
feature
Семантика Вордстата сохраняется и привязывается к кампании
Семантику собирали для контекста модели и теряли: отчёт читался и удалялся, номер наружу не отдавался, поэтому проверка считала фразы выдуманными.
yd-semantics.ts + wordstatWithReportId; сквозной прогон: отчёт 1446706021, 22704 показов → проверка видит
feature
Карта механики Директа + самопроверка
docs/YD-MACHINE.md (ловушки полей, устройство гейта, пороги, грабли) и scripts/yd-selftest.mjs, крон понедельник 08:00, расхождения в телеграм.
9 проверок, прогон зелёный; правило входа вшито в CLAUDE.md проекта и глобальный
feature
Синк кабинета (+77) + защита клиентских
managed_by_ai гейт
feature
Метрика: счётчики/цели/reachGoal
мёртвый 56222857 заменён
feature
Пайплайн + 5 скиллов + 8 эталонов
docs/YD-PIPELINE.md
feature
КЗ-кампании v2: 243 фразы, 9 групп
500р/день каждая
feature
Модерация 14 объявлений + показы
Проверено 09.08 через API: 13 активных объявлений, все в статусе active — отклонённых и заблокированных нет. За 14 дней 336 показов и 9 уникальных обращений. Модерация пройдена, показы идут.
feature
Перепривязка счётчиков старых кампаний
Скрипт yd-fix-counters разбирает 91 кампанию: счётчик по посадочной странице, без --apply только показ. Мёртвый 56222857 в настройках уже не встречается. Четырём черновикам привязан 109681054 (цель 585238631), архивные пропускаются. Одиннадцать кампаний с чужими счётчиками (200476 Пульс цен и др.) не тронуты: кабинет общий, это решение владельца.
feature
РСЯ на оплату за конверсии (10+/нед)
feature
блокS5 · Email-реанимация (2428 лидов)0/3

Цель: Деньги из спящей базы

SMTP-релей (VK порезал SMTP)
feature
DNS: DKIM/SPF в Тильде
feature
Кампания seg:trade 634 (автокарточки)
dry-run → превью → 3/час
feature
ревьюS6 · Оффер-система (107 офферов)10/12

Цель: Сильные офферы по фреймворкам + критик-цикл, персона, 4 длины под площадки; вшито в креативы+лендинг (gated)

Фреймворки+критик+getBestOffer
Фреймворки 4U/ODC/PmPHS/Хормози/BAB/AIDA/FAB + критик-рубрика 0-100 + getBestOffer (генерация→критик→≤3 круга→лучший). Compiled-AI: overall/планка считает код. Ветка sprint-6, 116 тестов зелёные.
feature
Ресерч + база 107 case-backed офферов
18 verified_case с реальными URL-кейсами, 10 strong_example, 79 framework_template; 7 фреймворков, 15 ниш; seed-offer-bank-v2 на проде (Demo org).
feature
gpt-5-mini + фикс reasoning-ловушки
reasoning_effort проброшен в общий chat() (guard gpt-5/o*), лимиты токенов подняты; nano отвергнут — выдумывал цифры и не ловил их критиком.
feature
Калибровка: outcome-first + персона + критик buyer_outcome_clarity
Критик +7-е измерение (вес 0.22): механика в заголовке («пилот/агент») проваливается. Персона покупателя зашита ДАННЫМИ. Правила: фича→выгода, бей по статус-кво (ChatGPT).
feature
4 длины оффера под площадки
headline≤24 (креатив), adTitle≤40 (Директ), heroOffer≤60 (лендинг-hero), fullOffer≤160 (тело); clampLen по границе слова, без висящих союзов.
feature
differentiation: план Б (узкий угол) + путь для кейсов (план А)
Узкий угол always-on без кейсов (квалификация/ночь-выходные/первая линия). Поле cases течёт в оффер (план А). Потолок ~70% честный для generic-позиционирования.
feature
Движок вшит в креативы+лендинг (gated OFF) + фикс nginx /landings/
ad-creative-generate + generateLanding под флагом useOfferEngine (default off). Демо-лендинг: hero=оффер. Починен nginx location /landings/ (был SPA-заглушка → чёрный экран).
feature
merge sprint-6 → main + рестарт pm2 (deploy)
Флаги useOfferEngine остаются OFF — включение движка на реальной кампании отдельным шагом.
ff-merge sprint-6 → main (686d1da); pm2 restart leadforge-workers+api — online, здоровы. Флаги useOfferEngine OFF, поведение кампаний не изменилось.
feature
Онбординг: захват кейсов клиента → cases (план А)
Вопрос про кейсы в опрос о компании/услугах; кейсы поднимают differentiation. Путь данных готов (loadBusiness читает cases).
orgs PATCH /me + алиас /current (починен 404 сохранения шага «О компании»), принимает cases[] → merge в business_profile.cases (jsonb). Онбординг: поле «Кейсы и результаты» → отправка массивом. Дашборд пересобран, live отдаёт новый билд. loadBusiness читает cases → офферы усиливаются (план А замкнут).
feature
Включить движок на реальной кампании (трата LLM)
Прогнан на живой услуге (gpt-5-mini, 3 варианта, 2 круга, несколько рублей). Работает: критик оценивает по 7 измерениям, слабые уходят на переделку. Нашлось важное — планку 90 не взял ни один вариант, а движок всё равно отдавал «лучший», и креативы с лендингом его брали. Добавлены passed и bar, слабый оффер больше не идёт в рекламу. Включать на кампании имеет смысл после того, как хоть один вариант возьмёт планку.
feature
Офферы не берут планку 90: поднять конкретность и отличие
На прогоне все шесть вариантов провалились по concreteness (20-50) и differentiation (30-60). Причина скорее в исходных данных, чем в модели: без цифр результата и без кейсов оффер нечем сделать конкретным. Проверить на профиле с заполненными cases.
Нашлась причина в коде: критик считал weakest (какие мерки провалены), а код это выбрасывал — на переделку уходил общий список замечаний, и круг за кругом чинилось не то. Теперь переделка получает провалившиеся мерки как требования. Добавлен досмотр кодом до дорогой оценки: общее место в заголовке + ни одной цифры = предсказуемый провал, платить критику незачем. Замер: отличие 47→53, конкретность 56→62, результат покупателя 62→74, лучший 78→79, круги растут 72→75→79. Планку 90 не берёт, и причина честная: при пустых кейсах и выгодах отличаться нечем, а выдумывать запрещено. Движок теперь так и отвечает (blockedBy) вместо молчаливой выдачи слабого оффера — это вопрос к онбордингу. 15 тестов.
feature
Wire + deploy в live
ждёт «да»
feature
планS7 · Roadmap: 1A.2–1A.40/3

Цель: Trigger.dev / KG / Critic

1A.2 Trigger.dev
feature
1A.3 Knowledge Graph
feature
1A.4 Critic
feature
В РАБОТЕS8 · Avito: машина роста Ф1 + песочница + vision-судья17/18

Цель: Автономный A/B-рост объявлений + офлайн-тренажёр агентов + критик картинок

2 объявления в эфир: «Дашборд с ИИ» 150к + «ИИ-директолог» 75к
Карусели 6 карточек через Kie gpt-image-2-text-to-image; INSERT avito_ad_map + rebuildFeed; на живом аккаунте 408820630
Карусели 6 карточек через Kie gpt-image-2-text-to-image; INSERT avito_ad_map + rebuildFeed; на живом аккаунте 408820630
feature
Ф1-execute: автономная генерация A/B
growth-loop генерит предложения (текст OpenRouter / картинки Kie) → ready_to_apply → apply-proposals (критик+спенд-гейт) → measure (вердикт+урок). Флаг AVITO_GROWTH_AUTOAPPLY (ВЫКЛ), капы 2/запуск+40р/сут, дедуп, контакт-гард. apply/measure расширены на cover/carousel
growth-loop генерит предложения (текст OpenRouter / картинки Kie) → ready_to_apply → apply-proposals (критик+спенд-гейт)
feature
Дизайнер: текст в safe-area
Заголовок смещён в центр (верх/низ 15% режутся в превью-рубрике). Фикс coverPrompt/carouselPrompt
Заголовок смещён в центр (верх/низ 15% режутся в превью-рубрике). Фикс coverPrompt/carouselPrompt
feature
Песочница v1: офлайн-турнир агентов
ген→3 судьи→адверс.критик→self-play→дистилл в avito_playbook. 1-й прогон 2 сферы: 12 уроков + правила формата, ~$0.15. Сжали недели тестов в минуты
ген→3 судьи→адверс.критик→self-play→дистилл в avito_playbook. 1-й прогон 2 сферы: 12 уроков + правила формата, ~$0.15. С
feature
Vision-судья на картинки (OpenRouter multimodal)
Построен, ловит off-topic/кринж/чужой стиль (6/10 брак на живом create-mquiy4b7, выцепил кросс-объявленческое замешивание). Осталось вшить в growth-loop+apply+разовый проход
Судья gpt-4o+detail:high встроен ПЕРЕД avito_add_image (junk → отказ + удаление файла), в критерии добавлены не-русский текст и выдуманные домены. Коммит 2771e23.
feature
Почистить мусорные карусели старых объявлений
Старые объявления с шаблонными зелёными картинками (опечатки, чужие лица) — пересобрать начисто в неон-стиле по теме ПЕРЕД A/B
Карусели живых объявлений вычищены: убраны англ. инфографика и фейк-домен, дубли, восстановлена обложка Дашборда, обложка Консультации взята из банка (0 руб). В фиде 4 объявления, офферы первыми, дублей нет.
feature
Связать песочницу с продакшеном
Паттерны success/failure из playbook + бан-жаргон → в промпт генератора заголовков (сейчас приор только считает уроки, не подаёт текст)
Приоры складывали уроки песочницы и замеры в эфире поровну: шесть выводов симуляции весили как шесть замеров. Теперь прод полновесно, песочница со своей уверенностью 0.35, при расхождении побеждает эфир; где замеров нет, подсказка прямо говорит «это догадка». На живых данных по заголовкам было 7✓/6✗ (замер один из тринадцати), стало 3✓/2✗.
feature
Включить AVITO_GROWTH_AUTOAPPLY
После тренировки в песочнице + чистки каруселей — включить автономку
feature
Карта механики Авито + самопроверка
Механику разбирали трижды с нуля. docs/AVITO-MACHINE.md + scripts/avito-selftest.mjs, крон, алерты.
самопроверка ловит расхождения; правило входа в CLAUDE.md + скилл avito-work
feature
Продвижение: найдено, что оно не включалось ни разу
Все 102 объявления стояли AdStatus=Free. Услуг x2/x5/x10 в категории услуг больше нет — там аукцион цены просмотра; минимальная ставка 42 ₽ даёт нулевой прогноз показов.
лестница ставок на cpxpromo setAuto/setManual, пороги в коде; тест 2100 ₽/нед на «Дашборде»
feature
Связка объявления с номером Авито (объявления были невидимы для машины)
После публикации через фид avito_item_id оставался пустым — механизма связки не существовало, поэтому не работали статистика, ставки, лестница, сверка и снятие.
lib/avito-link-ids.ts в status-sync; связано 8 из 8, самопроверка показывает 11/11
feature
8 продуктовых объявлений опубликованы
Позиционирование владельца: разрабатываем ИТ-продукты с ИИ, разовые агентские услуги не берём. Разнесены по четырём подкатегориям вместо одной.
все 8 активны и управляемы из кода; 30 черновиков-клонов снесены
feature
Ф0. Триаж + нормы (keystone)
yd_norms (базлайны/пороги по нише, обучение baseline), дневной код-гейт в yd-analyst.worker: норма→ИИ не зовём (0 токенов), аномалия→триггер сбора. Гейт холодного старта. Немедленный алерт на выброс расхода.
Ф0 LIVE. yd_norms (нормы/пороги, RLS, сид отказа: КЗ<78 freemium, MV/LF<55 b2b) + learned baseline (mean±2σ из снапшотов, cpl/cpc/ctr/spend). yd-triage.ts: воронка из ad_analytics_snapshots + отказ из Метрики (per-counter токен из metrica_counters), cold-start гейт (моложе 7д ИЛИ <100 кликов/14д), детект аномалий, spend-алерт (sendAlert critical), запись в yd_insights period.kind=triage. Вшит в дневной крон 09:00 MSK (до apply 11:00). Попутно фикс латентного бага: getCampaigns не просил CounterIds → отказ был слеп и в weekly insights. Тест: КЗ отказ 76.3%<78=норма (ИИ не зван), MyVision АНОМАЛИЯ отказ 77.1%>55 (записана), LeadForge cold-skip. aiCalls=0. Числа только кодом.
feature
Ф1. Замкнуть петлю
Контракт HYPOTHESIS аналитик→директолог, запись правки как yd_experiment + before_state, двугоризонтный вердикт (T+1 отказы/трафик, T+3..7 CPL/конверсии) + guardrail-метрики, откат при регрессии.
Ф1 LIVE (queue-only, деньги-гейт). Замкнута петля: аномалия(триаж)→разрезы(analyzeDimensions)→ГИПОТЕЗА(ИИ chatJSON, только на аномалии, кормится числами кода)→автономия→safe+reversible применить+эксперимент ИЛИ очередь yd_actions на аппрув. Вердикт (расширен yd-experiment-evaluate): 2 горизонта (fast отказы/трафик T+1, slow CPL/конв T+3..7), guardrail (трафик не умер), ОТКАТ при регрессии (revertAction по before_state). Файлы: yd-hypothesis.ts, yd-loop.ts, +evaluateLoopExperiment/bounceWindow в evaluate-воркере. Крон yd-loop-daily 09:30 MSK. Money-gate: YD_LOOP_AUTOAPPLY по умолчанию OFF → всё в очередь на аппрув, живые кампании авто НЕ меняются; включение флага = safe+reversible авто. Попутно: фикс getCampaigns (NegativeKeywords — read-modify-write минусов не перезатирается), приоритет loop-эксперимента в выборке вердикта (бэклог 461 не голодит). Проверено: гипотеза на MyVision (отказ 77%→add_negatives с реальным мусором), вердикт улучшение→winner / регресс→откат(reverted=true, no-op), queue-only прогон положил гипотезу в yd_actions.
feature
Ф2. База уроков yd_playbook
niche·symptom·diagnosis·action·outcome·confidence. Каждый закрытый эксперимент пишет строку. Приор перед LLM (компиляция) — режет токены.
yd_playbook под RLS + запись урока при закрытии эксперимента (обе ветки вердикта) + чтение ДО модели. Накопился уверенный ответ — гипотеза берётся из базы без вызова ИИ (компиляция). Нет ответа — модель зовём, но передаём грабли: что уже проваливалось. Уверенность считается кодом по доле побед и объёму (порог 0.7 при 3+ наблюдениях), а не называется моделью. Проверено пятью случаями.
feature
Ф3. collectFullReport() — кнопка полной таблицы
Переиспользуемая КОД-функция (не ИИ), вызывается при любом разборе: разрезы аудитории/ключи/запросы/площадки/офферы/объявления/креативы/время/гео/устройство со всеми метриками. Разметка строк работает/мало данных/плохо. + недельный режим.
Девять разрезов одним вызовом, каждая строка размечена работает/мало данных/плохо кодом, а не моделью. Недельный режим — то же окно в 7 дней. Нашлось: отчёты запрашивались разом, Директ ставил часть в очередь, и «готовится» принималось за «пусто» — объявления молча терялись. И пустой разрез теперь объясняется, а не читается как «проблем нет». 7 тестов.
feature
Ф4. Создающая сторона A/B
Заведение контролируемых тестов: новое объявление/группа/ключи из Вордстата. Bandit (комбинаторные) vs Директ.Эксперименты/holdout для измерения лифта.
Способ выбирается предметом: креативы — комбинаторные (площадка перебирает быстрее нас), ставки/стратегия/посадочная/аудитория — только с контрольной группой. Без контроля тест не заводится: это была бы правка под видом эксперимента. Вердикт осторожный — меньше 100 кликов или 5 обращений молчим, разница меньше 10% это шум. Итоги подводятся вместе с экспериментами, урок уходит в базу знаний. 8 проверок.
feature
Ф5. Эскалация/алерты
Немедленный алерт (TG) на расход/обнуление конверсий/0 показов. Эскалация человеку после N кругов без нормы.
yd-escalation: три тихие беды, которых не видно по расходу — показы обнулились (кампания активна, денег не тратит, никто не замечает), конверсии обнулились при живом трафике (платим за клики без заявок), петля крутится вхолостую. Плюс остановка авто-правок после N кругов без результата: isLoopStuck спрашивается ПЕРЕД разбором. Всё считается кодом, крон 09:40 МСК, молчит когда всё в порядке. Проверено на подставных данных: 3 из 3 находок, здоровая кампания не задета.
feature
готовS9 · S1. Лиды клиента — клиенту4/4

Цель: Заявка с формы клиента попадает в ЕГО компанию и падает ему в телеграм. Фундамент SaaS-разделения.

Ключ формы у каждой компании (capture_key) + роутинг в capture.ts
organizations.capture_key + роутинг в capture.ts. Проверено боем: с ключом → компания клиента, без ключа → мы, левый ключ → мы (не падает).
feature
Привязка телеграма клиента по коду (/start <код>) → chat_id компании
Код в кабинете (POST /orgs/me/notify/telegram-code) + /start lfXXXXXX в боте пишет chat_id компании.
feature
Карточка лида уходит владельцу компании, а не нам
capture шлёт карточку в чат компании; чат не привязан — падает нам, чтобы заявка не потерялась.
feature
Проверка: лид клиента виден только ему (пен-тест изоляции)
Проверено входом в кабинет живой тестовой компанией: клиентское меню без внутренней кухни, панель уведомлений отдаёт свой ключ и код, привязка чата + заявка по ключу легли в компанию клиента.
feature
готовS10 · S2. Свои ИИ-агенты у каждого клиента4/4

Цель: При заведении компании создаётся её собственный набор агентов — копии наших эталонов, с настройками под её бизнес.

Эталонный набор агентов (шаблон из нашей орги, 9 шт)
Девять ролей перенесены из нашей орги как эталон, а не копия: копия притащила бы клиенту наши тексты, цены и запреты.
feature
Клонирование агентов при создании компании
Заводятся при регистрации черновиками. Повтор не плодит дублей, а обновляет настройки. Ошибка заведения не роняет регистрацию. Проверено живой регистрацией: 9 из 9.
feature
Настройки под клиента из онбординга: тон, офферы, о чём нельзя говорить
configFor подставляет тон, офферы, услуги, гео и запреты из бизнес-профиля и брифа. Чего нет — помечается «не хватает», а не выдумывается.
feature
Изоляция знаний: агент клиента не видит наши базы
Агенты живут под RLS компании; проверено на временной компании — агенты других компаний не видны.
feature
готовS11 · S3. Реклама клиента в его кабинетах4/4

Цель: Клиент подключает свои кабинеты, кампании реально запускаются.

Кабинеты per-org (ad_accounts + провайдер + экран)
feature
Починить preflight: кампанию сейчас НЕЛЬЗЯ запустить
Гейт сам запускает предполётную проверку в assertYdCallAllowed — закрыты все 4 пути запуска. Ложные нарушения убраны (SitelinkSetId, CalloutIds, хеш картинки): было 143, осталось 73 реальных.
feature
Гео и бюджет из брифа клиента вместо хардкода
Посадочная, счётчик Метрики и гео берутся из данных компании и брифа. Раньше всё трое были зашиты на наши сайты и на Москву с Петербургом. Нет сайта или счётчика — бриф уходит в blocked с причиной, а не собирает кампанию не туда.
feature
Проверка баланса кабинета перед запуском
Три исхода вместо двух: хватает — запускаем, пусто — блокируем, неизвестно — предупреждаем но пропускаем. Блокировать запуск потому, что площадка не отдала цифру, значит наказывать клиента за устройство чужого API. Выяснено по факту: у Директа accounts.get в v5 не существует, AccountManagement в v4 требует подключённого общего счёта, Funds при SHARED_ACCOUNT_FUNDS остатка не содержит. Авито отдаёт аванс.
feature
готовS12 · S4. Контент и SEO под клиента (слит в S17)0/1

Цель: Контент-машина и лендинги работают на сайт клиента, а не только на наш.

Контент-машина per-org (сейчас только наш контур на cfru)
дубль: то же самое в S17 «Перенести механику из bo-seo-team.mjs в мультиарендный вид»
feature
готовS13 · S5. Приёмка SaaS3/3

Цель: Проверка изоляции на живых клиентах + тариф и лимиты.

Пен-тест изоляции на 2 живых компаниях
Автопроверка scripts/lint-tenant-isolation.sh гоняется и после правок чистая (кроме наших разовых скриптов и сборки). Осталось живьём: пен-тест на двух реальных компаниях, когда заведём клиента.
scripts/pentest-isolation.sh: две компании через настоящий API, вторая пытается достать данные первой. 8 из 8 — лиды, счётчик Метрики, кабинеты, очередь решений, рекламный расход, фид, подмена компании заголовком, запрос без токена. Гонять перед заведением каждого клиента, денег не тратит.
feature
Лимиты и тариф: что входит, где стоп
Таблица ai_usage: расход пишется внутри chat() и на каждой готовой картинке, компания берётся из контекста выполнения. Цены статикой в коде, подписочный Клод по нулю, незнакомая модель помечается. Точность 4 знака (при двух тысячи дешёвых вызовов давали ноль). Потолок себестоимости в тарифах: trial 500, start 1500, business 4500, pro 12000, enterprise 40000 руб/мес; компания сверх потолка пропускается обходом целиком. Клиенту цифры не видны: /admin/usage под операторским ключом. 10 тестов прайса + 9 сквозных проверок.
feature
Снять заглушку crm-sync или реализовать amoCRM/Битрикс
Настоящая выгрузка заявок: Битрикс24 через входящий вебхук, amoCRM через долгоживущий токен (сделка+контакт одним запросом). Защита от дублей с двух сторон: поиск карточки по телефону и почте, номер заведённой запоминается в enrichment_data. Сломанный доступ (401) отключает интеграцию, а не повторяется вечно. Приём ИЗ CRM отвечает честным отказом. Два пути: кнопка в кабинете и обход каждые 30 минут. Доступ проверяется при подключении. 12 сквозных проверок.
feature
В РАБОТЕS14 · План развития платформы (волны 1-7)12/16

Цель: docs/PLATFORM-PLAN.md: стабильность рекламы, очередь решений, качество, MCP, ВК, лендинги, тарифы

Волна 1. Стабильность рекламы: запуск Директа разблокирован
Гейт сам гоняет предполётную проверку, ложные нарушения убраны, карта YD-MACHINE.md + самопроверка по крону
feature
Волна 2. Единая очередь решений (таблица decisions)
Авито (лестница+стратег) и Директ (запуск через предполётную) пишут в одну таблицу; замер раз в 6 ч; GET /api/v1/decisions/*; карта docs/DECISIONS-QUEUE.md
feature
Волна 2 хвост: перенести ВК в очередь решений
У канала пока нет своих решений о тратах — переносить будет что после запуска ВК
vk-decisions.ts: запуск ВК попадает в единую очередь, отказ гейта ложится в gates того же формата, что у Авито и Директа. Проверено — заблокированный запуск виден в сводке как rejected с недельной суммой.
feature
Волна 2 хвост: честный замер для Директа
Сейчас каналы кроме Авито закрываются пометкой «замер вручную». Нужен разбор статистики кампании против baseline
Решения Директа замеряются по снимкам за неделю против baseline: обращение подешевело, подорожало или не сдвинулось. Отдельно оговорён случай «нечего мерить» — не выдумываем вердикт при нулевом расходе.
feature
Волна 3. Качество как отдельный слой
Текстовые правила вынесены в quality/ad-text-rules и подключены к Директу и Авито. Осталось: судья картинок и банк креативов.
Слой качества собран: судья креативов в общем пакете (Авито, Директ, ВК) с правилами по каналам, текстовые правила ad-text-rules, критик ВК с дешёвой проверкой текста до дорогого разбора картинки, досмотр офферов кодом. Проверено на живом объявлении и 12+15 тестами.
feature
Волна 4. Клиентские инструменты через MCP
MCP-сервер на /api/v1/mcp (JSON-RPC: initialize, tools/list, tools/call). Пять инструментов: заявки по источникам, расход на рекламу, кампании, очередь решений, предложение изменения. Предложение НЕ выполняется — ложится в очередь со статусом proposed. Инструментов, тратящих деньги или меняющих живые кампании, нет намеренно. Себестоимость для нас не отдаётся. Ключ выдаётся в кабинете, показывается один раз, в базе только sha256; новый ключ отзывает старый. 7 проверок на живом сервере, включая изоляцию между компаниями.
feature
Волна 5. ВКонтакте как полноценный канал
ВК доведён до канала: клиент нового кабинета ads.vk.com, гейт трат обоих кабинетов, лид-формы и автосбор заявок, аудитории и счётчики ретаргетинга, плюс стратег кампаний (план из брифа, число групп от бюджета, порог обучения 300 руб/группа, доли считает код) и критик креативов. Пустой бриф не превращается в выдуманный план. 12 проверок. Остаётся прогнать самопроверку на реальных доступах клиента.
feature
Волна 6. Лендинги под кампанию
Страница собирается из обещания кампании: заголовки объявлений и запросы идут в задание, hero повторяет обещание теми же словами. Связка кампания-страница в campaign_landings, заявки считаются по метке кампании. Попутно вычищено: в подвале было наше имя и «auto-generated by LeadForge AI»; счётчик Метрики брался мимо настройки клиента; generate_landing и generate_proposal звались без orgId (страница и КП собирались по данным чужой компании); маршрут был прибит к SYSTEM_ORG_ID; убран мёртвый /public/lead-capture, который при переформатировании файла включил бы приём заявок без ключа в первую попавшуюся компанию. 7 проверок.
feature
Волна 7. Тарифы и квоты
Перенесено в конец по решению владельца
Таблица ai_usage: расход пишется внутри chat() и на каждой готовой картинке, компания берётся из контекста выполнения. Потолки себестоимости в тарифах (trial 500, start 1500, business 4500, pro 12000, enterprise 40000 руб/мес), компания сверх потолка пропускается обходом целиком. Клиенту цифры не видны: /admin/usage под операторским ключом. 10 тестов прайса + 9 сквозных проверок.
feature
ТЕСТ dueDate
Тестовая задача, заводилась для проверки механики сроков. Закрыта как мусорная.
check
Свой кабинет Директа вместо общего с Пульс Ценами
Лимиты Директа считаются на логин: 1000 отчётов Вордстата в сутки делятся с чужими инструментами в том же кабинете e-16707300. Плюс правило «MV/LF не палить» в общем кабинете. Отдельный кабинет снимает и то, и другое; per-org кабинеты в ad_accounts уже поддержаны.
decision
Заявка на отдельный Wordstat API (api.wordstat.yandex.net)
Отдельный бесплатный API со своей квотой на OAuth-токен, не ест тысячу Директа. Нужна заявка в поддержку Директа с логином и ClientId приложения. Снимает потолок на сбор семантики для клиентских кампаний.
decision
Ключевые цели Метрики на кампаниях: выбрать стратегию
Счётчики на кампаниях есть, PriorityGoals пусты. Постановка целей осмысленна вместе со сменой стратегии: сейчас WB_MAXIMUM_CLICKS (максимум кликов). Решение владельца: остаться на кликах или переводить на конверсии по цели формы.
feature
Волна 3. Качество текста в общий пакет
quality/ad-text-rules: обещания и внешние контакты запрещены везде, англицизмы — замечание, длины только там, где подтверждены. Директ получил проверку ad_text_quality, критик Авито перешёл с копии на общие правила. 15 тестов.
feature
Волна 3 хвост: судья картинок и банк креативов в общий пакет
Текстовые правила вынесены. Осталось vision-судья (сейчас в avito-ad-critic) и банк креативов — их ждут ВК и Директ.
Судья креативов переехал в packages/ai/src/quality/creative-judge — теперь общий для Авито, Директа и ВК. Правила по каналам разведены явно: у Авито важен порядок слайдов, у Директа связь картинки с заголовком, у ВК считываемость за секунду. Без картинок возвращает null и не тратит вызов модели. Проверено на живом объявлении: вердикт publish, 6 картинок, стиль единый.
feature
Статистика объявлений Авито пишется только для нашего кабинета
Найдено 19.08. Поля last_stats_views, last_stats_contacts и версии _7d в avito_ad_map заполняются единственным местом — apps/api/src/index.ts, где организация зашита константой ORG = 92f39df0 (наш кабинет). Для ISKRA и любого следующего клиента они пустые. ПОСЛЕДСТВИЯ: авто-улучшение объявлений сортирует кандидатов по COALESCE(last_stats_views_7d, 0), и при сплошных NULL это выбор наугад, а не «худшее объявление». Истории по объявлениям клиента нет вовсе: дневной таблицы статистики Авито в базе не существует, кабинет показывает цифры только на лету из API. ЧТО НУЖНО: сбор по всем организациям через forEachOrg на расписании плюс дневная таблица, иначе динамику объявления показать нечем, а тесты рубрик меряются вручную.
feature
В РАБОТЕS15 · Проверки по сроку15/24

Цель: Задачи вида «через неделю посмотреть, сработало ли». Срок на задаче (dueDate), напоминание в ТГ раз в сутки.

Авито: цена обращения по двум циклам продвижения (2800 ₽)
Цель владельца — 500-700 ₽ за лид. Если выйдет дороже 1500 ₽, лестница сама снимет продвижение. ssh aitodo "docker exec lf-postgres psql -U leadforge -d leadforge -c \"SELECT object_ref, cost_rub, outcome FROM decisions WHERE channel='avito' AND status='measured';\""
За 14 дней 9 уникальных обращений. При заявленных 2800 руб за два цикла это 311 руб за обращение — вдвое дешевле цели 500-700 руб. ВАЖНО: история операций Авито за те же 14 дней показывает лишь 550 руб с пометкой «Продвижение» плюс 3000 руб подписки; цифра 4900 руб/нед по API не подтверждается. Если реальная трата 550 руб, обращение стоит 61 руб. Точную сумму продвижения видно только в кабинете.
check
Очередь решений: замер отработал, ничего не застряло
Если решения висят в applied после срока — крон замера сломался и молчит. ssh aitodo "docker exec lf-postgres psql -U leadforge -d leadforge -c \"SELECT status, count(*) FROM decisions GROUP BY status;\"" Карта: docs/DECISIONS-QUEUE.md
Проверено 09.08: applied 3, proposed 2, rejected 1. Старше 10 дней в applied/gated нет ничего — замер не сломан. Самое старое applied от 08.08, окно замера ещё не наступило.
check
Директ: разобрать 73 нарушения предполётной по «Ретаргетинг»
Пока не закрыты — кампанию не запустить, гейт держит. ssh aitodo "cd /mnt/docker-data/leadforge-ai && set -a && . ./.env && set +a && node scripts/yd-selftest.mjs" Карта: docs/YD-MACHINE.md
Разобрано: 4 из 5 видов нарушений оказались ложными (номера объявлений теряли точность, не запрашивались BiddingStrategy и PriorityGoals, минус-слова сверялись построчно против нормализованной формы Директа). Кампания «Ретаргетинг» — чужая архивная из общего кабинета Пульс Цен, чинить её незачем. Настоящая мишень — 8 наших (LF): у кандидата 712889425 осталось 2 нарушения, оба требуют решения владельца.
check
Авито: значения Specialty для 5 объявлений в запасных категориях
Проверено 09.08: справочника Specialty нет ни в одном машинном виде. API: /autoload/v1/user-docs/node/, /core/v1/items/categories, /autoload/v2/categories — все 404. Файлы автозагрузки all.xml, tree.xml, Goods.xml — 404. Страница шаблонов отдаёт только ссылку в поддержку. Значение достаётся ГЛАЗАМИ из формы подачи объявления в кабинете — действие владельца, кодом не обходится. Записано в docs/AVITO-MACHINE.md, не исследовать заново.
Решено 13.08 другим путём. Справочника Specialty в API действительно нет, но значение берётся с ЖИВОГО объявления клиента: страница отдаёт ботам 439, поэтому открывать браузером (Playwright) и читать блок параметров. Так получены все поля для пошива формы: Specialty Пошив одежды, Sewing Крупный, Materials, ProvidesMaterials, Prepayment, WorkExperience, WorkWithLegalEntities. Записано в docs/AVITO-MACHINE.md и в память iskra-avito-autoload-blocked.
check
Авито: аванс не кончился (продвижение ест 4900 ₽/нед)
ПРОВЕРЕНО 10.08. Аванс 1610.94 руб (было 2032 на 09.08, 3274 на 08.08). Фактический расход за 14 дней: 4414 руб — подписка 3000, продвижение 1090 (550+540), целевые действия 324. В среднем 315 руб/день, аванса хватит примерно на 5 дней. Цифра «4900 руб/нед» НЕ подтвердилась: продвижение стоит около 550 руб/нед. ОТДАЧА за 14 дней: 291 показ, 7 обращений, из них 6 — на объявление «Поиск партнера в ит стартап» (создано руками, машиной не управляется, не про услуги). Наши управляемые объявления дали 1 обращение. Последние 6 дней (04–09.08) — ноль обращений. 9 из 11 объявлений без обращений вообще. ЖДЁТ РЕШЕНИЯ ВЛАДЕЛЬЦА: (1) снять продвижение и не жечь аванс, (2) менять рубрики и офферы — показов 18/день на 11 объявлений, нас просто не находят, (3) оставить и смотреть ещё неделю. Проверка: ssh aitodo "cd /mnt/docker-data/leadforge-ai && set -a && . ./.env && set +a && node scripts/avito-selftest.mjs"
Проверено 14.08: аванс 2698.82 руб, кабинет пополнили (было 1610 на 10.08). Кошелёк 1767 руб так и не переведён в аванс - сам он не тратится. Объявлений 18 активных, 5 из них вне управления автозагрузкой.
check
Директ: дозамерить семантику 5 кампаний (упёрлись в суточный лимит Вордстата)
10.08 · просрочено 21 дн.
Прогон 09.08: замерено ранее 3 кампании, к замеру 5. На второй кампании (712700771, 236 фраз, 24 отчёта) снова упёрлись в суточный лимит Вордстата — он уже был израсходован сегодня. Замер возобновляемый, продолжит с этой кампании. ssh aitodo "cd /mnt/docker-data/leadforge-ai/apps/workers && node --env-file=/mnt/docker-data/leadforge-ai/.env --import tsx src/yd-collect-semantics.ts all"
check
Директ: быстрые ссылки и минус-площадки для 7 остальных кампаний
У кампании 712889425 сделано (5 ссылок с описаниями). Остальные ведут на другие сайты, набор ссылок и якоря нужно проверять по каждому сайту отдельно, вслепую копировать нельзя. РСЯ дополнительно требует минус-площадки: сейчас их нет ни у одной.
Минус-площадки (1030 записей) поставлены 5 нашим сетевым кампаниям; 3 чужие в общем кабинете не тронуты, одна из них работает. Быстрые ссылки поставлены 3 кампаниям без них (Контент-завод, My Vision, LeadForge) — наборы собраны по якорям, снятым с живых сайтов; 2 кампании Пульс Цен пропущены, сайт не наш. Попутно найдена слепота: getCampaigns не запрашивал ExcludedSites, поэтому проверка «стоят ли запреты» всегда видела ноль.
check
ISKRA: блог зашёл в индекс Яндекса и Google
Блог и 2 статьи опубликованы 10.08 на 1skra.ru, в sitemap.xml есть. Проверка: site:1skra.ru/blog в Яндексе и Google; в Вебмастере - Индексирование -> Страницы в поиске. Если через 2 недели ноль страниц - проверить robots.txt (Disallow только /api/), доступность sitemap и отправить страницы на переобход. Заодно посмотреть в Метрике 109572218, есть ли заходы на /blog/.
Проверено 24.08 по свежей выгрузке Вебмастера (9-22 августа, залита в seo_search_positions, теперь 202 запроса против 138). Блог В ИНДЕКСЕ: раздел /blog/ дал 48 показов за неделю по двум запросам, средняя позиция 8.4. Показы сайта выросли с 5 в день (9.08) до 34 (22.08), запросов в выдаче с 5 до 13-26 в день, средняя позиция держится 7-9. Появились небрендовые коммерческие запросы, которых раньше не было: командная форма на заказ (позиция 5), заявка на спортивную форму (6), спортивная форма с логотипом на заказ (12), экипировка на заказ спортивная (8), форма для тренеров Владивосток на заказ (12). Клики пока редкие, 0-5 в день: позиции во второй половине первой страницы, CTR низкий. Вывод: индексация и видимость работают, следующий рычаг - подъём позиций и заголовки под клик.
check
ISKRA: показать статьи владельцу и после ок опубликовать
Завод делает 2 статьи в день автоматом (10:10 и 16:10 МСК), они копятся в статусе ready и на сайт не уходят - цель публикации намеренно не заведена. К среде накопится 4-6 штук. Проверка: обновить https://myvisionagency.ru/lab/iskra-articles свежими статьями, показать владельцу, получить ок и только тогда публиковать. Команда: psql -c "SET app.current_org_id='a59c3c22-107c-432f-953a-70e679420fbe'; SELECT title, created_at FROM seo_articles ORDER BY created_at;" ВАЖНО: публикатор кладёт плоские .html, а блог собран папками /blog/<адрес>/ - перед публикацией это надо привести к одному виду.
Опубликованы 2 статьи, блог 1skra.ru теперь из 4 штук. По дороге вскрылось три вещи: завод не видел двух ручных статей и написал дубли про ткани (обе отбракованы, ручные занесены в базу); воркер работал на коде 44-часовой давности, поэтому правки каркаса и жанра не применялись; на всём блоге не было счётчика Метрики - трафик не считался с запуска. Всё исправлено, статьи перевыпущены на Sonnet 4.6 (5578 и 5315 знаков против 2400 у gpt-4o-mini).
check
SEO-завод: первые статьи крона на Sonnet 4.6
12.08 модель статей переключена на anthropic/claude-sonnet-4.6 (SEO_ARTICLE_MODEL в .env), воркер перезапущен. До этого gpt-4o-mini упирался в 3200 знаков и не проходил проверку объёма. Кроны: 10:10 и 16:10 МСК. Надо увидеть, что крон реально выпускает статьи, а не падает на проверках, и что уровень держится. Команда: ssh aitodo "docker exec lf-postgres psql -U leadforge -d leadforge -t -A -c \"SET app.current_org_id='a59c3c22-107c-432f-953a-70e679420fbe'; SELECT created_at, status, length(html), title FROM seo_articles ORDER BY created_at DESC LIMIT 4;\"" — свежие должны быть в ready, длиной от 15000 знаков страницы. Смотреть также логи: pm2 logs leadforge-workers --lines 200 | grep seo-article. Публиковать сборщиком iskra_blog.py, память iskra-blog-publishing.
Проверено 13.08: крон на Sonnet отработал вхолостую и вскрыл две поломки, обе мои. Первая - критик Авито блокировал статью за упоминание домена (правило про увод с площадки), хотя статья живёт на сайте самой компании; теперь замечание про домен для статей пропускается, телефоны и почта по-прежнему запрещены. Вторая - отбраковав дубли, я вернул их фразы в очередь, и завод каждый день брал закрытую тему, писал статью и тут же отклонял: 11 и 13 августа так сгорели впустую. Фразы с занятым ядром сняты с очереди (3 штуки), плюс ядро уход теперь ловит слово ухаживать - раньше не ловило, и вторая статья про стирку могла пройти. После правок две статьи написаны с ПЕРВОЙ попытки: 7811 и 7224 знака, по 4 раздела, обложки сгенерировались автоматически.
check
ISKRA Авито: отдача двух новых объявлений
Опубликованы 12.08: 8353601405 хоккей, 8353626334 школа. На старте 6 и 2 просмотра, ноль обращений - первый день, судить рано. Через неделю сравнить с направлениями клиента: в среднем по кабинету 13.5 процента из просмотра в контакт, у флагов 28, у дорогих объявлений по 990 руб всего 2-3. Команда: ssh aitodo 'cd /mnt/docker-data/leadforge-ai/apps/workers && set -a && . /mnt/docker-data/leadforge-ai/.env && set +a && node --import tsx src/scripts/iskra-stats.mjs 7'. Если обращений ноль при живых просмотрах - проверять цену в карточке: гипотеза, что 990 руб отсекает обращения, а 100-150 руб их даёт.
Поглощена более полной проверкой на 21.08: там все пять наших объявлений плюс отдача продвижения. Отдельно два первых смотреть смысла нет.
check
ISKRA Авито: отдача пяти объявлений и продвижения
14.08 залиты три новых объявления (волейбол 8353562259, баскетбол 8353113372, регби 8353655753) плюс два прежних. Все пять по 990 руб - владелец решил цену не снижать. На хоккейное 8353601405 включено продвижение 350 руб/день авто-бюджетом. Аванс клиента был 10059 руб. Смотреть: сколько съело продвижение и дало ли оно обращения против четырёх объявлений без него. Команда: ssh aitodo 'cd /mnt/docker-data/leadforge-ai/apps/workers && set -a && . /mnt/docker-data/leadforge-ai/.env && set +a && node --import tsx src/scripts/ours-avito.mjs'. Продвижение проверять по auto.budgetPenny в getBids - поля isActive там нет.
Проверено 19.08. Продвижение в услуговой рубрике не работает: на хоккейном 8353601405 авто-бюджет 350 руб/день стоял с 14.08 — за неделю НОЛЬ списаний и 20 показов, 1 обращение. Пакетов больше просмотров в услугах нет вовсе, vas/prices отдаёт пять услуг по 1-2 руб. В товарной рубрике пакеты есть: x2_1 150 руб, x5_1 290, x10_1 500. Куплено продвижение x2_1 на футбол 8353542067 и волейбол 8353383502, списано 300 руб с кошелька. Механика записана в docs/AVITO-MACHINE.md: PUT /core/v2/accounts/{uid}/items/{id}/vas_packages телом package_id, старый /vas для пакетов даёт 400.
check
Директ ISKRA: пополнили ли счёт для теста на 15 000
16.08 проверено: на счёте 713437598 (логин directiskra) ноль рублей, деньги не поступали. Кампании настроены под тест и ждут только пополнения: Поиск 5000 руб/нед, РСЯ 2500 руб/нед, итого 7500 в неделю или 15000 за две. Цели проставлены: Оставил заявку (564605606) и Клик на телефон (564605730). Обе кампании в состоянии OFF. Проверка баланса: ssh aitodo 'cd /mnt/docker-data/leadforge-ai/apps/workers && set -a && . /mnt/docker-data/leadforge-ai/.env && set +a && node --import tsx src/scripts/yd-balance-probe.mjs'. Как появятся деньги - включать campaigns.resume и через две недели считать расход делить на конверсии.
Закрыта досрочно: 16.08 деньги на счету обнаружены (24590 руб), кампании Поиск и РСЯ запущены. Дальнейшее отслеживание перешло в проверку про модерацию на 17.08 и итог теста на 30.08.
check
Директ ISKRA: прошла ли модерация и пошли ли показы
16.08 запущены Поиск (713475036) и РСЯ (713475097): State ON, Status MODERATION, 169 объявлений отправлено на модерацию. Проверить что Status стал ACCEPTED и пошли показы. Команда: ssh aitodo 'cd /mnt/docker-data/leadforge-ai/apps/workers && set -a && . /mnt/docker-data/leadforge-ai/.env && set +a && node --import tsx src/scripts/yd-state.mjs'. Если модерация отклонила - смотреть причины по объявлениям через ads.get с полем StatusClarification.
Проверено 16.08 досрочно: обе кампании ACCEPTED, State ON. Показы пошли: Поиск 287 показов / 17 кликов / 451 руб, РСЯ 835 показов / 24 клика / 95 руб, 28 достижений целей. Все цифры уже подтягиваются в кабинет клиента.
check
Директ ISKRA: итог теста на 15 000 — цена заявки
30.08 · просрочено 1 дн.
Тест на две недели: Поиск 5000 руб/нед, РСЯ 2500 руб/нед, итого 15000 за 14 дней. Цели для подсчёта: 564605606 Оставил заявку и 564605730 Клик на телефон. Посчитать расход делить на конверсии по каждой кампании отдельно - поиск и РСЯ дают разную цену, усреднять их бессмысленно. Данные: отчёт CAMPAIGN_PERFORMANCE_REPORT с полями Cost и Conversions, либо ad_analytics_snapshots после сбора. Сравнить с целевой планкой владельца 500-700 руб за обращение.
check
Авито: что покажет исправленный замер экспериментов
23.08 · просрочено 8 дн.
16.08 исправлено измерение: результат мерился окном в 3 дня против базового в 7, из-за чего 365 правок из 389 признаны провальными арифметически. Теперь окно 7 дней, вердикт по доле обращений на просмотр, на малых числах не судим. Проверить: появились ли настоящие победители и сработал ли авто-откат хоть раз (за всю историю ноль откатов при 365 ухудшениях). Команда: docker exec lf-postgres psql -U leadforge -d leadforge -c "SELECT winner, count(*) FROM avito_experiments WHERE applied_at > '2026-08-16' GROUP BY 1;" Разбор: myvisionagency.ru/lab/avito-mehanika
check
SEO ISKRA: новая выгрузка Вебмастера, сравнить позиции
30.08 · просрочено 1 дн.
16.08 загружена первая выгрузка Вебмастера по 1skra.ru за 01-14.08: 138 запросов, 261 показ, 42 перехода, у блога 15 показов и позиция 5.7. Через две недели взять новую выгрузку в Вебмастере (Поисковые запросы -> Управление группами -> выгрузка XLSX) и залить, чтобы увидеть динамику позиций после статей. КОМАНДА ЗАГРУЗКИ: 1) Скачать XLSX из Вебмастера 2) Локально: python webmaster-to-json.py && python load-webmaster.py (скрипты в scratchpad сессии 16.08) 3) scp webmaster-load.sql aitodo:/tmp/ && ssh aitodo "docker exec -i lf-postgres psql -U leadforge -d leadforge < /tmp/webmaster-load.sql" 4) Проверить в кабинете: https://24leadforge.ru/app/dashboard/analytics, блок «Поиск и статьи» СМОТРЕТЬ: выросли ли показы у /blog/, появились ли новые запросы, куда сдвинулась средняя позиция.
check
Авито ISKRA: товарная рубрика против услуг — где обращения дешевле
09.09 · через 9 дн.
19.08 опубликованы три объявления в товарной рубрике «Спорт и отдых»: футбол 8353542067, волейбол 8353383502, баскетбол 8353161233. Размещение бесплатное, продвижение НЕ включали. Волейбол и баскетбол намеренно повторяют наши же темы из услуг, поэтому сравнение честное: одна тема в двух рубриках. КОМАНДА ПРОВЕРКИ: ssh aitodo, папка /mnt/docker-data/leadforge-ai/apps/workers, скрипт src/scripts/iskra-goods-test.ts (создан 19.08): выводит показы и обращения по трём товарным и двум услуговым объявлениям за период. Запуск: set -a && . ../../.env && set +a && node --import tsx src/scripts/iskra-goods-test.ts ЧТО СЧИТАТЬ: обращений на объявление в товарах против наших волейбола 8353562259 и баскетбола 8353113372 в услугах за тот же период. БАЗОВАЯ ЛИНИЯ (замер 19.08 за 01.08–18.08): наши пять объявлений в услугах получили суммарно 22 показа и 1 обращение за 18 дней — то есть они почти не показываются. Волейбол 3 показа и 1 обращение, баскетбол 1 показ, хоккей 13, спортшкола 3, регби 2. Если товарные объявления дадут заметно больше показов, дело было в рубрике; если столько же — упираемся не в рубрику, а в видимость без продвижения, и тогда следующий шаг другой.
check
Директ ISKRA: помогли ли минус-слова и отключение сетей
21.08 сделано: цена конверсии поднята с 1000 до 1300 руб в обеих кампаниях, добавлено 39 минус-слов (стало 225, было 186). РСЯ была остановлена и по решению владельца возвращена: при оплате за конверсию она не тратит бюджет без обращений, держать включённой ничего не стоит. Работают обе кампании, ретаргет остаётся черновиком, группы не трогали. ДО ПРАВОК: отказы с рекламы 57 процентов при 681 визите, 37 процентов кликов на нецелевых запросах (логотипы 106 кликов и 66 процентов отказов, клубная атрибутика 24 и 67, вышивка 18 и 61, инвентарь 12 и 58). Сети дали 281 визит и ноль обращений. КОМАНДА ПРОВЕРКИ: ssh aitodo, папка /mnt/docker-data/leadforge-ai/apps/workers, set -a && . ../../.env && set +a, затем node --import tsx src/scripts/iskra-bounce.ts 2026-08-21 2026-08-28 и node --import tsx src/scripts/iskra-queries.ts 2026-08-21 2026-08-28 ЧТО СЧИТАТЬ: доля отказов с рекламы должна упасть с 57 процентов, доля нецелевых кликов с 37. Отдельно посмотреть, дали ли сети хоть одно обращение за неделю с чистой семантикой. Если отказы остались высокими, причина в страницах входа: футбольная давала 68 процентов при 241 визите против 46 у производства.
Проверено 28.08. Минус-слова сработали: нецелевые клики упали с 37 до 18 процентов (по делу 389 кликов из 473, отказы там 27 процентов). Отказы НЕ изменились — было 57, осталось 57: причина не в семантике, а в страницах входа (главная 60 процентов при 187 визитах, производство 51 при 102). РСЯ за 16-28.08 дала 414 кликов, 4819 руб и одно обращение — ту самую мусорную заявку 24.08 с кодом +7 124 с площадки Яндекс.Картинки. Площадка запрещена 27.08. Предложено выключить РСЯ целиком. Поиск: 901 клик, 9781 руб, 6 заявок и 1 звонок, обращение по 1397 руб. Разбор: myvisionagency.ru/lab/iskra-analiz
check
Авито ISKRA: что дало продвижение трёх товарных объявлений
24.08 списалось 372 руб (по 124 на объявления 8353161233, 8353383502, 8353542067 в рубрике Спорт и отдых). За сутки 4 просмотра на троих — судить рано, отчётность Авито отстаёт на сутки. Разбор на 25.08: myvisionagency.ru/lab/iskra-avito-razbor — наши услуги дают 1.97 просмотра в день, столько же сколько клиентские, весь отрыв клиента куплен пакетами (9914 руб за 13 дней, 583 руб за контакт). Пакеты клиента истекали 25.08 — проверить, продлил ли. КОМАНДА ПРОВЕРКИ: docker exec lf-postgres psql -U leadforge -d leadforge -c "SELECT c.external_campaign_id, s.date::date, s.spent::int, s.impressions, s.conversions FROM ad_analytics_snapshots s JOIN ad_campaigns c ON c.id=s.ad_campaign_id WHERE c.external_campaign_id IN ('8353161233','8353383502','8353542067') AND s.date > '2026-08-23' ORDER BY 1,2;" Смотреть: выросли ли просмотры против 1.3 в день и появились ли контакты. Цена просмотра выше 20 руб (столько выходит у клиента на пакетах) — продвижение не оправдывается, переходить на пакет vas вместо ставки cpxpromo.
Проверено 28.08. Ставка cpxpromo в товарной рубрике не работала (403 на getBids), поэтому 26.08 куплен пакет x2_7 по 500 руб на три объявления, 1500 руб с кошелька, действует до 02.09. Отдача: просмотры выросли ровно вдвое, с 1.0 до 2.0 в день, и появилось первое обращение — волейбольное 8353383502, 4 просмотра и 1 контакт за три дня. Пока 1500 руб за одно обращение, окончательный счёт 02.09 (заведена отдельная проверка). Семь наших объявлений в услугах: 2.3 просмотра в день, 1 обращение, продвижение там купить нельзя. У клиента пакеты кончились 25.08 и просмотры упали с 42 до 20 в день. Разбор: myvisionagency.ru/lab/iskra-analiz
check
Авито ISKRA: что дал пакет x2 за 1500 руб и фильтр телефона на форме
02.09 · через 2 дн.
26.08 куплен пакет x2_7 (до 2 раз больше просмотров, 7 дней) на три товарных объявления 8353161233, 8353383502, 8353542067 — по 500 руб, 1500 руб с кошелька, действует до 02.09 10:36. База сравнения за 12-24.08: эти три давали 1.33 просмотра в день на объявление и ноль контактов. У клиента на пакетах выходило 20 руб за просмотр. КОМАНДА ПРОВЕРКИ (Авито): docker exec lf-postgres psql -U leadforge -d leadforge -c "SELECT c.external_campaign_id, sum(s.impressions) prosm, sum(s.conversions) kont, sum(s.spent)::int rub FROM ad_analytics_snapshots s JOIN ad_campaigns c ON c.id=s.ad_campaign_id WHERE c.external_campaign_id IN ('8353161233','8353383502','8353542067') AND s.date >= '2026-08-26' GROUP BY 1;" Считать цену просмотра: 1500 / просмотры. Дороже 20 руб — пакет не оправдался, брать x5_7 или уходить в услуги. КОМАНДА ПРОВЕРКИ (форма 1skra.ru): python E:/Temp/claude/C--Users-pc/5023dd01-b534-4708-9d97-1bcaead29ee8/scratchpad/get-leads-log.py затем analiz-leads.py Смотреть: появились ли новые причины отбоя phone_not_ru и не отбивается ли что-то живое. Если мусор пошёл с российскими номерами — ставить капчу Яндекса (обсуждали 26.08, отложили).
check
Директ ISKRA: что изменилось после отключения РСЯ
04.09 · через 4 дн.
28.08 остановлена кампания РСЯ 713475097 (ACCEPTED/SUSPENDED). База для сравнения за 16-28.08: поиск 901 клик, 9781 руб, 6 заявок и 1 звонок, обращение 1397 руб; РСЯ 414 кликов, 4819 руб, одно мусорное обращение. Поиск в недельный лимит не упирается: 5267 руб при разрешённых 10000. КОМАНДА ПРОВЕРКИ: ssh aitodo, /mnt/docker-data/leadforge-ai/apps/workers, set -a && . ../../.env && set +a node --import tsx src/scripts/iskra-yd-full.ts 2026-08-28 2026-09-04 ЧТО СЧИТАТЬ: выросло ли число обращений на поиске после отключения сети и не подорожало ли обращение. Если поиск так и не выбирает 10000 руб в неделю, обсудить с владельцем подъём цены конверсии с 1300 руб — это единственный рычаг объёма при оплате за конверсию.
check
research-daily: сработал ли прогон 1 сентября без дублей
02.09 · через 2 дн.
28.08 переделан research-daily. Было: сбор источников внутри forEachOrg, одни и те же 9 статей пересказывались на каждую из 108 организаций — 972 запроса к LLM в сутки, 1107 находок при 418 уникальных заголовках, около 45 руб/день (COST-MODEL.md закладывал 14). Стало: источники разбираются один раз за прогон, находки раскладываются по org отдельным шагом, дедуп по source_url, расписание 1 и 15 числа в 22:00 МСК, окно дайджеста расширено до 15 дней. Первый прогон по новой схеме — 1 сентября 19:00 UTC. КОМАНДА ПРОВЕРКИ: ssh aitodo "pm2 logs leadforge-workers --lines 400 --nostream | grep -i 'Sources parsed once'" ssh aitodo "docker exec lf-postgres psql -U leadforge -d leadforge -At -c \"SET row_security=off; SELECT created_at::date, count(*), count(DISTINCT title), count(DISTINCT org_id) FROM research_findings WHERE created_at > '2026-09-01' GROUP BY 1;\"" ЧТО СЧИТАТЬ: в логе должна быть строка Sources parsed once for all orgs со счётчиками articlesFetched и skippedAlreadySeen. Число запросов к LLM за прогон должно быть не больше числа новых статей (раньше 972). Если articlesFetched=0 и находок нет — это нормально, значит новых статей в источниках не появилось, дайджест берёт находки за 15 дней. Расход по ai_usage за 1 сентября по cron:research-daily должен упасть с 45 руб примерно до нуля-единиц. ЕСЛИ ПУСТО: проверить, что repeatable-job в Redis жив — docker exec lf-redis redis-cli ZRANGE 'bull:research-daily:repeat' 0 -1 WITHSCORES. Бэкапы прежнего кода лежат рядом: apps/workers/src/lib/research.ts.bak-2026-08-28 и research-extra.ts.bak-2026-08-28.
check
ISKRA: упали ли отказы после облегчения страниц и что дало гео
05.09 · через 5 дн.
28.08 сделаны две вещи. 1) Гео: добавлены 7 групп Россия (кроме 8 городов), 166 ключей, 15 объявлений на модерации. 2) Страницы: 188 картинок в webp с ресайзом до 1400px, отложенная загрузка на 10 страницах. Футбольная 20.6 МБ -> 0.23 МБ на старте, загрузка 4.8 -> 1.4 сек. БАЗА ДО ПРАВОК (16-28.08, только реклама): всего 996 визитов, отказы 56 процентов. По страницам: football 243 визита и 68 процентов отказов (со смартфона 171 визит, 70 процентов, 7 секунд), basketball 68, volleyball 62, главная 54, production 48. Смартфоны 61 процент против 47 на компьютерах. КОМАНДА ПРОВЕРКИ: ssh aitodo, /mnt/docker-data/leadforge-ai/apps/workers, set -a && . ../../.env && set +a node --import tsx src/scripts/iskra-deep.ts 2026-08-29 2026-09-05 ЧТО СЧИТАТЬ: отказы на /football/ должны уйти заметно ниже 68 процентов, время на странице вырасти с 7 секунд. Если не изменилось — причина не в скорости, а в содержании страницы, и надо смотреть первый экран и оффер. Отдельно: пошли ли визиты и обращения из новых регионов (разрез по городам).
check
В РАБОТЕS16 · Первый живой клиент (понедельник 11.08)22/27

Цель: Завести ЛК, подключить Директ/ВК/Авито и СЕО к сайту клиента так, чтобы цифры шли и лиды фиксировались

Кампания клиента больше не рекламирует наш сайт
Посадочная бралась хардкодом (myvisionagency/24contentzavod), счётчик Метрики — по списку наших доменов с запасным вариантом «наш счётчик». Теперь сайт и счётчик берутся у компании; нет их — бриф в blocked с причиной.
fix
14 мест работали нашими кабинетами за чужие компании
6 воркеров и 8 библиотек создавали клиента площадки без организации (токены из env). Переведены на кабинет компании. NoAdAccountError → forEachOrg считает компанию пропущенной, а не упавшей.
fix
Сбор цифр читал пустое поле вместо кабинета
ad-analytics-collect брал доступы из ad_campaigns.platform_credentials (пусто у всех 135 кампаний), а панель пишет в ad_accounts. Теперь берёт кабинет компании.
fix
Вход клиенту: задан инвайт-код
Регистрация закрыта, но REGISTRATION_INVITE_CODE не был задан — завести вход было нечем. Код в .env; сквозная проверка scripts/client-onboarding-smoke.sh, 10 шагов зелёные.
fix
🔴 ВК: подключить кабинет и проверить, что цифры идут
Доступы клиента проверены боем 10.08: это НОВЫЙ кабинет VK Реклама (ads.vk.com, OAuth2), владелец Юлия Стольная, внутри 1 кампания клиента от 10.08, показов и расхода 0. Самопроверка vk-selftest: 9 из 9, расхождений с картой 0. Клиент жаловался, что доступы не подходят - причина оказалась наша: кнопка Проверить в ЛК держала свою копию логики и всегда шла в старый api.vk.com (VK API 15: token required), из-за чего кабинет метился invalid. Копия удалена, /check теперь зовёт probeAdAccount. Статус кабинета в базе поправлен на active. ОСТАЛОСЬ: перезапустить leadforge-api, чтобы правка заработала в ЛК, и нажать Проверить глазами.
Кабинет клиента подключён и читается: самопроверка 9 из 9, расхождений с картой 0. Это новый кабинет VK Реклама (ads.vk.com), владелец Юлия Стольная, внутри 1 кампания клиента от 10.08 (показов и расхода нет), 1 аудитория, лид-форм нет. По дороге починены два бага: кнопка Проверить в ЛК шла в старый api.vk.com и метила рабочий кабинет invalid; токены выписывались на каждый вызов и не сохранялись, из-за чего упёрлись в token_limit_exceeded и кабинет перестал отвечать (лечится POST /v2/oauth2/token/delete.json). Теперь токен один на компанию, лежит в ad_accounts.credentials. Карта docs/VK-MACHINE.md переведена из документации в проверенные факты.
check
🔴 СЕО и Контент-завод к сайту клиента: путь не проверен
Контент-завод — отдельный сервис на cfru, в контур LeadForge не подключён. Как именно СЕО-часть привязывается к сайту клиента и per-org ли она — НЕ проверял. Разобрать до понедельника.
Способ доставки выяснен: FTP, доступ есть и проверен на деле (сайт по нему выкачивали). SSH выяснять не нужно, поддомен остаётся запасным вариантом.
check
Авито: подключить кабинет клиента и проверить сбор
Развилка кабинета проверена на Директе. Для Авито нужны clientId/clientSecret клиента; проверка доступа при подключении есть (читает аванс).
Кабинет 414744452 подключён и читается полностью, сбор проверен: 36 объявлений, статистика за 30 дней 2103 просмотра и 284 обращения. Автозагрузка открылась после вставки ссылки на фид в кабинете.
check
Экран счётчика Метрики в кабинете клиента
Ручки GET/PUT /orgs/me/metrika готовы, поля в интерфейсе нет. Пока задаётся через API.
Панель Яндекс Метрики в настройках кабинета: номер счётчика проверяется обращением к Метрике токеном самого клиента (тем же, что для Директа), показываются название счётчика, сайт и список целей, цель заявки выбирается из списка. Похожая на заявку подсказывается. Разбор ответа проверен на живом счётчике 56222857; выяснилось, что на несуществующий счётчик Метрика отвечает 403, а не 404 — подсказка покрывает обе причины. Живая сборка кабинета обновлена.
feature
ВК: поддержан новый кабинет (ads.vk.com)
80% кабинетов на нём. OAuth2 с тремя потоками, токен на сутки с самопродлением. Кабинет определяется по введённым доступам, клиента не спрашиваем.
feature
ВК: лид-формы и автосбор заявок в кабинет клиента
Заявка из ленты оставалась внутри рекламного кабинета и умирала непрочитанной. Теперь падает в leads компании каждые 15 минут, без дублей, окно 3 дня.
feature
ВК: критик креативов и стратег кампаний
Осталось до уровня Авито и Директа: критик объявления до публикации, судья картинок, стратег который сам ведёт кампании. Механика есть в Авито — переносить в общий пакет (Волна 3 плана).
Критик ВК: сначала дешёвые правила по тексту (обещания, контакты, жаргон), потом общий судья креативов с правилами ВК — считываемость за секунду, много текста на картинке режет охват. Стратег: план кампании из брифа с делением бюджета кодом. 12 проверок, оба исхода критика.
feature
Рекламный расход клиента в ЛК
Владелец: расход НА РЕКЛАМУ показывать надо (его деньги, его результат), нашу себестоимость по токенам и картинкам — нет. Собирать по каналам из ad_analytics_snapshots.
дубль: сделано в задаче ниже
feature
Расход показывался в 308 раз больше реального
Планировщик каждый час пересобирал окно в 30 дней, сборщик просто вставлял строки: до 66 снимков одного дня на кампанию. 20 533 891 ₽ вместо 66 668 ₽. Чтение берёт последний снимок на кампанию и день, запись очищает окно перед сбором.
fix
Рекламный расход клиента в ЛК
GET /analytics/ad-spend и /ad-spend/daily: расход, клики, обращения, цена клика и обращения по каналам. Себестоимости сервиса там нет. Осталось поле в интерфейсе.
feature
645 886 старых дублей снимков: чистить или оставить
На вывод больше не влияют (чтение берёт последний за день), рост остановлен. Массовое удаление — решение владельца, само не делаю.
Вычищено 620 879 дублей из 621 291 строки, уникальных было всего 412. Копия снята заранее (23 МБ), суммы после чистки совпали до рубля. Таблица 289 МБ → 208 КБ. Повтор невозможен: уникальный индекс + запись через обновление по конфликту, проверено прогоном сбора.
chore
Ещё 3 места работали нашим кабинетом за клиента
apply-brief СОЗДАЁТ кампании (появились бы в нашем кабинете с нашего баланса), avito-send пишет покупателю (из нашего профиля, ответ пришёл бы нам), yd-full-refresh пересобирает кампанию целиком. Получают orgId не через цикл по компаниям, поэтому в прошлую чистку не попали.
fix
Картинки клиента лежали в общей папке
Проверка изоляции нашла: сгенерированные картинки писались в /public/avito-images всем вместе, имена предсказуемы (номер объявления, ниша, время) — чужую обложку можно было угадать по адресу. Разложены по /public/org/{orgId}/, лишний путь убран в 5 местах.
fix
Фид Авито был один на всех
Фиксированное имя avito_feed.xml в общей папке: второй клиент затёр бы фид первого и его объявления уехали бы в чужой кабинет. Разложен по папкам компаний; наш фид продолжает лежать и по прежнему адресу, пока не переставим его в кабинете Авито руками.
fix
Переставить адрес фида в кабинете Авито на папку компании
Оба адреса живые (проверено 09.08, оба 200): новый https://leadforge.myvisionagency.ru/org/92f39df0-46cf-46e2-a7a0-50c6b5f0c6cb/avito-feeds/avito_feed.xml, старый https://leadforge.myvisionagency.ru/feeds/avito/avito_feed.xml. Осталось одно действие владельца: вписать новый адрес в настройки автозагрузки кабинета Авито. После этого убрать из кода запись в старую папку.
chore
ВК: научиться создавать кампанию, группу и объявление в новом кабинете
Разведка сделана на живом кабинете. POST /v2/banners.json и /v3/banners.json отвечают 405 supported_methods GET - объявления там не создаются, путь другой. POST /v2/ad_plans.json требует вложенный массив campaigns, каждая группа требует name и package_id - значит нужен справочник пакетов (v2/packages.json). Права в кабинете есть на всё: ad_plans, ad_groups, lead_forms, segments, counters отвечают 400 валидацией, а не 403. ВАЖНО: разведку вести на ОДНОМ токене из ad_accounts, иначе упираемся в token_limit_exceeded и кабинет перестаёт отвечать всем (лечится POST /v2/oauth2/token/delete.json).
Создание кампаний написано и проверено боем: createAdPlan, setAdPlanStatus, getPackages в vk-ads-new.ts. Разобрано на живом кабинете: всё создаётся ОДНИМ запросом POST /v2/ad_plans.json, где campaigns это группы, а banners внутри них - объявления; отдельно ни группу (Invalid package), ни объявление (405, только GET) создать нельзя. package_id обязан совпадать с целью кампании, список в /v2/packages.json (limit максимум 20), у кабинета ISKRA 174 пакета. Удаления DELETE нет - только POST со статусом deleted. Тестовая кампания создавалась и убрана, в кабинете осталась только кампания клиента. Всё занесено в docs/VK-MACHINE.md разделы 0.1, 0.15, 0.2. ОСТАЛОСЬ: объявления требуют patterns (форматы пакета) - их состав ВК отдаёт в тексте ошибки, надо разобрать и собрать creative; пакеты site_conversions кабинет отвергает, похоже нужен счётчик ВК на сайте клиента.
task
Директ ISKRA: кабинет подключён, ждём одобрения заявки на API
10.08 клиент завёл кабинет Директа (логин directiskra, баланс 0). OAuth пройден: токен получен и лежит в ad_accounts ISKRA, статус active, аккаунт подтверждён через login.yandex.ru (directiskra, id 2416835596). НО campaigns.get отвечает ошибкой 58 - у приложения YANDEX_OAUTH_CLIENT_ID=354e9b45660643e5b9fd8114362e90ff нет одобренной заявки на доступ к API Директа. Наш собственный токен работает, потому что он от другого аккаунта (e-16707300, кабинет eLama). Что нужно: подать заявку на доступ к API в интерфейсе Директа под аккаунтом, где зарегистрировано приложение 354e9b45, и дождаться подтверждения (до нескольких дней). Доступы клиента при этом рабочие, переподключать не нужно.
Директ клиента подключён и отвечает: наш код видит кабинет directiskra, кампаний 0 (кабинет новый). Разгадка ошибки 58: заявка на доступ к API у нас ОДОБРЕНА ещё 03.04.2026 (полный доступ), но для приложения leadforge ca776098eb424a0497b9f887ad9099d0, а сервис ходил приложением 354e9b45660643e5b9fd8114362e90ff, у которого заявки нет. У одобренного приложения Redirect URI = https://oauth.yandex.ru/verification_code и сменить его Яндекс не дал, поэтому токен получен ручным путём: authorize с force_confirm под directiskra -> код на экране -> обмен на токен через POST oauth.yandex.ru/token с client_id и secret. Токен живёт год, записан в ad_accounts ISKRA (external_id=directiskra). ОСТАЛОСЬ для потока подключения других клиентов: либо подать заявку для 354e9b45 (кнопка Новая заявка в Директ -> Настройки API -> Мои заявки), либо добавить в ЛК ввод кода руками под приложение ca776098.
task
Директ: подключение по коду в кабинете
Сделан второй способ подключения Директа: клиент открывает страницу Яндекса, копирует код с экрана и вставляет в кабинете. Нужен потому, что заявка на API одобрена приложению ca776098, а сменить ему Redirect URI Яндекс не даёт. GET /integrations/oauth/yandex/manual отдаёт ссылку, POST принимает код: меняет на токен, проверяет чей аккаунт через login.yandex.ru, дёргает campaigns.get и только потом пишет в ad_accounts - подключено значит работает, а не просто записано. В кабинете свёрнутая строка под основной кнопкой. Ключи приложения в .env как YANDEX_OAUTH_APPROVED_CLIENT_ID/SECRET. Кабинет пересобран и выложен на 24leadforge.ru/app, прежняя сборка в /opt/lf-lp/app.bak-20260809-1736.
task
Авито ISKRA: два объявления под правки клиента
Первая версия показана клиенту (https://myvisionagency.ru/lab/iskra-avito). Клиент прислал правки 10.08: размер фото 1240x960 вместо вертикальных, по 10 фото в каждом объявлении вместо 5, цена от 990 руб, характеристики внизу текста обязательны (размер, цвет, артикул) иначе блокировки, публикуем только Москву и проверить по блокировке, телефон +7 991 143 73 70, а тираж/срок/число видов спорта клиент уточнит у Дмитрия. СДЕЛАНО: запущена генерация 20 кадров в 4:3 (по 10 на объявление), сюжеты разведены - вратарь, номера, тренировочная, сумки, детская команда, по видам спорта. ОСТАЛОСЬ: привести кадры к точным 1240x960, обновить тексты (цена от 990, телефон в тексте, расширенный блок характеристик), пересобрать страницу согласования.
Оба объявления опубликованы 12.08: 8353601405 хоккей и 8353626334 школа, активны до 11.09, оба под управлением автозагрузки по нашим ключам iskra-hockey-team-kit и iskra-school-team-kit. Ссылку на фид вставили в кабинете, после этого профиль автозагрузки открылся и по API - правим тексты, картинки и цену из кода. Параметры объявления взяты с живой карточки клиента, ключевой Specialty Пошив одежды: название ветки каталога про ремонт одежды, а за выдачу отвечает этот параметр.
task
Директ ISKRA: Поиск и РСЯ по 8 городам
Кабинет directiskra подключён и отвечает, кампаний 0, баланс 0. Задача: собрать семантику, поднять Поиск и РСЯ по восьми городам из брифа (Москва, Санкт-Петербург, Екатеринбург, Новосибирск, Казань, Нижний Новгород, Ростов-на-Дону, Краснодар), офферы и картинки как в Авито. Учесть: Вордстат идёт через наш кабинет порциями по 4 отчёта (у клиента своего Директа не было), у аккаунта нулевой баланс - без пополнения кампании не открутятся.
task
Директ ISKRA: 16 кампаний собраны черновиками
Собрано в кабинете directiskra: 16 кампаний (Поиск и РСЯ на каждый из 8 городов), 80 групп, 193 объявления, 2336 фраз, 128 корректировок ставок. Все в состоянии OFF/DRAFT - откручиваться начнут только после пополнения и запуска владельцем. Дробление: город даёт свою кампанию (свои ставки и бюджет), направление свою группу; в Поиске 7 групп, в РСЯ 3 более крупные. В каждой кампании счётчик Метрики 109572218, 186 минус-слов, в РСЯ дополнительно 1000 минус-площадок, перенесённых из нашего кабинета. Корректировки: младше 18 отключены полностью, ядро 25-44 поднято, платёжеспособные подняты. Для РСЯ сгенерировано 15 квадратных креативов в стиле клиента (форма с ISKRA и молнией), 12 загружены в кабинет и стоят в 24 объявлениях. Быстрые ссылки набором на 4 раздела сайта. ГРАБЛИ, записать в карту: AdExtensionIds в объявлении Директ не принимает (Расширение не найдено) и роняет создание всего объявления; минус-фраза 18+ валит создание кампании целиком (в минус-словах разрешены только буквы, цифры, пробел и дефис); getAds и getKeywords принимают ID ГРУПП, а не кампаний - иначе аудит показывает нули на живых кампаниях.
task
Директ ISKRA: пересобран в 3 кампании, гео на уровне групп
Переделано по замечанию владельца. Было 16 кампаний (по одной на город на каждый тип) - бюджет дробился на восемь частей и стратегии не на чем было обучаться. Стало три: [Поиск] ISKRA - Лиды (56 групп, 1328 фраз, 56 объявлений), [РСЯ] ISKRA - Лиды (24 группы, 1016 фраз, 24 объявления с картинками), [Ретаргет] ISKRA - Лиды (24 группы, 24 объявления с картинками). ГЕО задаётся полю RegionIds ГРУППЫ, кампания общая; группы называются по образцу Москва - Футбольная форма. Недельные бюджеты общие на кампанию: Поиск 7000, РСЯ 9000, Ретаргет 2000. Все три OFF/DRAFT. Прежние 16 кампаний остановлены, не удалены. Правило записано в память ad-structure-and-formats, чтобы LeadForge собирал так автоматом.
task
ВК ISKRA: лид-форма и кампании упёрлись в два ручных шага
Схема лид-формы разобрана перебором и записана в docs/VK-MACHINE.md раздел 0.3: обязательные поля name, title, company_title, logo_id, contact_fields, first_screen_type, result_info, agreement; contact_fields это массив СТРОК а не объектов; logo_id принимается СТРОКОЙ. Главная ловушка: поле неверного типа превращает подробный ответ в безликий bad_request без указания поля - разбирать, посылая поля по одному. ТУПИК: загрузчика картинок в новом кабинете нет (content/static_images и images.json в трёх версиях отдают 404; lead_ads/lead_forms/logo.json отвечает bad value in query param на GET, POST и multipart), id картинок из существующего баннера logo_id не принимает (bad_value). РЕШЕНИЕ: форму создать руками в кабинете (там визуальный редактор), дальше кодом подхватить её id через getLeadForms - автосбор заявок уже написан. Текст формы подготовлен и отдан владельцу. Второй блокер: пакеты site_conversions (3104, 3105, 3113) кабинет отвергает как Invalid package - нужен счётчик VK на 1skra.ru.
task
готовS17 · Контент, СЕО и лендинги под клиента10/10

Цель: docs/SEO-FACTORY.md: бриф → ключи по полкам НЧ/СЧ/ВЧ → статьи в стиле сайта → публикация по FTP → экран в ЛК. Плюс лендинги клиента с его формой и разметкой.

Замысел завода описан
docs/SEO-FACTORY.md: бриф, три полки ключей, статья и проверки, стиль сайта, СЕО+ГЕО, четыре способа публикации, экран в ЛК, деньги и потолок, критерии готовности. Под согласование.
doc
🔴 Выяснить доступ к сайту клиента: SSH, FTP или git
Сайт на nic.ru, собран кодом, без админки. У них есть тарифы и с SSH, и без — надо посмотреть в панели клиента. Без доступа запасной вариант: блог на поддомене у нас.
FTP. Доступ есть и проверен на деле — сайт по нему уже выкачивали. SSH выяснять не нужно, поддомен остаётся запасным вариантом.
check
Перенести механику из bo-seo-team.mjs в мультиарендный вид
СДЕЛАНО: схема под RLS (seo_briefs/keywords/articles/publish_targets), банк ключей с полками НЧ/СЧ/ВЧ, счёт спрос×интент×выигрываемость, сбор через Вордстат. Правило «начинаем с низкочастотных» записано кодом: nextKeyword не поднимется выше, пока на низкой есть очередь. 14 тестов на чистый счёт. Найдена и исправлена ошибка, унаследованная из bo-seo-team.mjs: надбавка за вопросные запросы не срабатывала никогда ( в JS опирается на латиницу). ОСТАЛОСЬ: генерация самой статьи с тремя проверками.
Схема под RLS, банк ключей с полками НЧ/СЧ/ВЧ, счёт спрос×интент×выигрываемость, сбор через Вордстат, генерация статьи с тремя проверками, цикл с расписанием и потолком себестоимости. Правило «начинаем с низкочастотных» записано кодом. 14 тестов. Попутно исправлена ошибка из исходного движка: надбавка за вопросные запросы не срабатывала никогда ( в JS опирается на латиницу).
feature
Публикатор с копией и откатом
Адаптеры git/SSH/FTP/поддомен. Кладёт статью, дописывает в список блога, обновляет карту сайта, шлёт на переобход. Первая публикация — в черновой путь, показ клиенту.
FTP с копией и откатом. Перед изменением файла копия рядом, ничего не удаляем, первая публикация в черновой путь _draft мимо живого блога. Список статей и карта сайта правятся добавляюще. Проверено на настоящем FTP-сервере: 10 из 10, включая откат и отсутствие дублей при повторе. scripts/seo-publisher-smoke.ts + seo-ftp-test-server.py
feature
Снимок стиля сайта клиента
Шрифты, цвета, ширина колонки, вид заголовков и кнопок — статья собирается в вёрстке клиента, а не в нашем шаблоне.
Шрифты, цвета, ширина колонки, скругления берутся КОДОМ из разметки и стилей сайта; спрашивать у модели про фирменный цвет бессмысленно. Отдельно проверяется контраст: у обоих наших сайтов фон тёмный, а цвет текста не объявлен — статья вышла бы нечитаемой.
feature
Экран «СЕО контент-завод» в ЛК
Четыре вкладки: обзор, ключи по полкам, статьи, настройки. Смотреть и запрещать можно, запускать генерацию руками нельзя.
GET /seo/overview, /keywords, /articles, /articles/:id, /brief; PUT /brief, /target (с проверкой доступа боем); POST reject для ключа и статьи. Смотреть и запрещать можно, запускать генерацию руками нельзя. Себестоимость клиенту не отдаётся.
feature
Опубликовать правки сайта клиента на живой 1skra.ru
SEO+GEO, мобильная адаптация, сжатие картинок в webp, блог и 2 статьи. Клиент дал разрешение на публикацию 10.08.
Залито по FTP и проверено на живом сайте. Порядок: полный бэкап (C:/tmp/iskra-BACKUP-pered-zalivkoy, 161 файл, 57,2 МБ) -> 169 новых файлов (134 webp, блог, css/blog.css) -> 11 изменённых страниц. Проверка: 13 страниц и 119 ресурсов отдают 200, битых ссылок нет; обе формы целы (api/lead.php, GET 405); Метрика 109572218 шлёт хит; блог и 2 статьи открываются, блог в меню и sitemap; на мобильном горизонтального скролла нет. Вес 57 -> 8 МБ. Откат = вернуть 11 файлов из бэкапа, старые png/jpg на сервере не удалялись. Грабли: сразу после заливки браузер показал 28 битых картинок - это lazy-загрузка ниже экрана, считать только после прокрутки.
task
SEO-завод: запустить на ISKRA (2 статьи в день)
Завод запущен на ISKRA: бриф в работе, 12 тем в очереди, кроны стоят (ключи 05:20, статьи 10:10 и 16:10 МСК). Цель публикации намеренно НЕ заведена - статьи копятся в статусе ready и на сайт не уходят, показываем владельцу на myvisionagency.ru/lab/iskra-articles. Себестоимость 8 руб за статью при потолке 4000 в месяц. ОСТАЛОСЬ: получить от клиента размерную сетку и названия тканей (без них самая ходовая тема ниши, размеры детской формы на 473 показа, не закрывается), настроить публикацию в /blog/ папками как у ручных статей, добавить RSS новостей спорта вторым источником тем.
Завод выпустил и опубликовал первые 2 статьи на 1skra.ru/blog/. Проверки усилены: запрет таблиц, объём считается по телу (порог 3500 знаков), дубли ловятся по ядру темы, пропажа каркаса теперь ошибка вместо тихой подмены оформления. Модель вынесена в SEO_ARTICLE_MODEL - gpt-4o-mini упирается в 3200 знаков и в эталон не может.
task
Лендинг с формой клиента + UTM + связь с кампанией
Лендинг вёл в НАШ личный телеграм: заявка уходила к нам, а не к клиенту, и переход в мессенджер не отследить. Теперь форма, отправка по ключу компании туда же, куда заявки с сайта, UTM из адреса уезжают вместе с заявкой. Проверено сквозным прогоном.
feature
Форма захвата в воркерном генераторе (сейчас ссылка на личный телеграм)
Закрыто той же правкой: ссылка на телеграм заменена формой с ключом компании.
feature

Ворклог (места остановки)

28.08.2026, 05:40:56 · · claude

Разбор всплеска расхода OpenRouter 27.08 привёл к находке в research-daily: сбор источников сидел внутри forEachOrg, поэтому одни и те же 9 статей пересказывались на каждую из 108 организаций — 972 запроса к LLM в сутки, 1107 находок при 418 уникальных заголовков, около 45 руб/день против 14 руб по COST-MODEL.md. Переделано: источники разбираются один раз за прогон (collectResearchFindings / collectExtraFindings), находки раскладываются по org отдельным шагом (saveResearchFindings / saveExtraFindings); добавлен дедуп по source_url — уже разобранную статью в LLM повторно не отправляем; расписание переведено с ежедневного на 1 и 15 число в 22:00 МСК; окно дайджеста расширено с суток до 15 дней (getYesterdayFindings -> getRecentFindings), иначе дайджест был бы пустым 13 дней из 14. Ручные точки запуска в apps/api/src/routes/advertising.ts продолжают работать через обёртки. Заодно в research-extra убрана сборка SQL конкатенацией строк (sql.raw с текстом от LLM) — теперь параметризованный запрос. Отдельно сделана атрибуция расхода: в packages/ai/src/llm.ts клиенту OpenRouter добавлены defaultHeaders с HTTP-Referer и X-Title, иначе в кабинете OpenRouter весь расход идёт как App=Unknown (ключ общий примерно на 20 сервисов двух серверов). Проверено: tsc по изменённым файлам чист (272 ошибки в репозитории предсуществующие, в других модулях), leadforge-api и leadforge-workers перезапущены и online, в Redis repeatable-job пересоздан — следующий прогон 1 сентября 19:00 UTC. Обновлён docs/ACCEPTANCE.md, блок Researcher. Бэкапы рядом с файлами: *.bak-2026-08-28.

Боевой прогон новой механики не делал — это около 9 платных запросов, ждёт решения владельца (либо прогнать вручную через API-эндпоинт, либо дождаться 1 сентября). После первого прогона проверить: в логе строка 'Sources parsed once for all orgs' со счётчиком skippedAlreadySeen, и что в research_findings за дату число уникальных заголовков совпало с числом находок на организацию. Отдельно стоит решить, нужны ли находки всем 108 организациям — большинство из них, судя по всему, неживые.

21.08.2026, 04:24:45 · · claude

ISKRA: две статьи опубликованы, продвижение Авито запущено, разобран бюджет Директа, наведён порядок в контексте проекта. СТАТЬИ. Опубликованы две: «Форма для пляжного волейбола на заказ» и «Форма для спартакиады и корпоративных команд». Карта сайта 21 → 23 адреса, обе отдают 200, в списке блога появились. Темы выбраны по Вордстату и по заявкам, которые уже приходили из Директа по этим запросам (пляжный волейбол 1236 запросов в месяц, спартакиада и корпоративный сегмент 294). Стоимость 22 рубля на две. Отдельно собраны посадочные разделы под те же темы: статья ловит информационные запросы, раздел коммерческие. НАХОДКА ПО СПРОСУ: «купальник для художественной гимнастики» — 23 740 запросов в месяц, и заявка по гимнастике из Директа уже была. Но клиент такого не шьёт (на сайте шесть видов спорта, купальников нет), страницу не делал — нужен ответ клиента, берётся ли он. АВИТО. Куплено продвижение x2_1 на футбольное 8353542067 и волейбольное 8353383502 объявления в товарной рубрике, списано 300 рублей с кошелька. Закрыта проверка по сроку: продвижение в услуговой рубрике не работает вообще — на хоккейном 8353601405 бюджет 350 рублей в день стоял с 14.08, за неделю ноль списаний и 20 показов. Пакетов больше просмотров в услугах нет. Механика записана в карту: PUT /core/v2/accounts/{uid}/items/{id}/vas_packages телом package_id, старый /vas для пакетов даёт 400. ДИРЕКТ. Клиент просил поднять бюджет из-за малого числа лидов — поднимать нечего: недельный лимит 10 000 рублей на кампанию не выбирается (4 450 за четыре дня при 20 000 доступных). Кампании платят за конверсию, рычаг это цена конверсии, сейчас 1 000 рублей при фактической цене обращения около 890. РСЯ дала 474 визита и ноль заявок. КОНТЕКСТ ПРОЕКТА. Владелец: «если это LeadForge и клиент ISKRA, то задача по Директу делается так, по SEO так, по Авито так — почему каждый раз заново». Заведены docs/SEO-MACHINE.md (весь путь статьи от Вордстата до публикации с граблями каждого шага) и docs/clients/ISKRA.md (маршрут «какая задача каким инструментом», доступы, что клиент умеет, что обещали, гейты). В глобальный CLAUDE.md вписан порядок чтения тремя уровнями: проект → клиент → канал.

Ждут решения владельца: цена конверсии в Директе (поднимать ли с 1 000 до 1 300–1 500), что делать с РСЯ и черновиком ретаргета, расширять ли семантику под ниши с заявками (пляжный волейбол, гимнастика, спартакиада), спросить клиента про купальники для художественной гимнастики. Открыто: фотографии для двух новых посадочных разделов (сейчас волейбольные с исходного каркаса), свежая выгрузка Вебмастера — без неё результат блога не измерить, статистика объявлений Авито по клиентским организациям не собирается (дефект заведён отдельной задачей). Проверка теста товарной рубрики Авито — 9 сентября.

19.08.2026, 03:07:20 · · claude

ТОВАРНАЯ РУБРИКА АВИТО ЗАПУЩЕНА. Три объявления клиента опубликованы в «Спорт и отдых»: футбольная форма 8353542067 (узел Футбол → Форма, единственный вид с отдельным подтипом «Форма»), волейбольная 8353383502, баскетбольная 8353161233. Все active до 18.09, по четыре предметных кадра, цена 990 рублей как у клиента. Размещение бесплатное: аванс и кошелёк совпали до копейки до и после. Продвижение не включали. ГЛАВНОЕ: сборщик фида никогда не обслуживал кабинет ISKRA — фид туда писали руками, и первая же сборка кодом дала бы НОЛЬ объявлений, то есть сняла бы все пять с площадки. В базе от них были только заголовок и цена: описания пустые, картинок ноль, статус published при фильтре active. Содержимое перенесено в базу из живого файла, сборка теперь воспроизводит живой фид байт в байт. ЧТО ПОЧИНЕНО ПО ДОРОГЕ: категория была константой в генераторе (Предложение услуг → Деловые услуги), теперь набор тегов лежит в avito_ad_map.category_fields и товар выразим вообще; имя менеджера у каждого объявления своё (Альбина, Марина, Ольга, Татьяна, Елена), а в коде стояли имя и телефон нашего агентства, то есть клиентские объявления получили бы чужие контакты; адрес картинки строился в общую папку вместо папки компании, поэтому свежие фото уехали бы по несуществующему адресу; пустой ответ площадки на запуск выгрузки считался ошибкой разбора. Отдельно: jsonb не хранит порядок ключей, набор полей держим массивом пар. Значения товарных категорий не сочинены: запрошены у площадки (узлы forma, voleibol, basketbol) и записаны в docs/AVITO-MACHINE.md вместе с уроками сборки и публикации. Картинки — 12 кадров через Kie, около 30 рублей, предметная съёмка без надписей: в товарной рубрике смотрят на товар, а не на баннер.

Тест идёт три недели, до 09.09 — заведена проверка по сроку с командой замера. Считаем обращения на объявление против наших же волейбола и баскетбола в услугах. ВАЖНОЕ ИЗ ЗАМЕРА: наши пять объявлений в услугах за 01.08–18.08 набрали суммарно 22 показа и 1 обращение. Это почти нулевая видимость, и она ставит под вопрос саму постановку теста: возможно, упираемся не в рубрику, а в отсутствие продвижения. Товарные объявления как раз и покажут, что из двух. Открыто и ждёт решения владельца: продвижение на четыре объявления (в услугах пакеты площадка не продаёт, в товарах надо смотреть цену); форма приёма заявок или Турбо-страница для контактов из Директа. Отдельно заведён дефект: статистика объявлений собирается только по нашему кабинету, у клиента поля пустые, из-за чего авто-улучшение выбирает объявление наугад.

19.08.2026, 02:04:25 · · claude

Подготовка теста рубрики Авито: замерен спрос и составлена карта занятости кабинета. Объявления ещё не сделаны — выбор тем на согласовании у владельца. КАРТА КАБИНЕТА (30 дней). В товарной рубрике «Спорт и отдых» у клиента: футбол 17 объявлений (331 просмотр, 44 обращения, но 12 из 17 дают 0-7 просмотров и мертвы), волейбол 1 (497/15), баскетбол 1 (295/5), хоккей 1 (57/3), регби 1 (57/2). В услугах: флаги и виндеры 7 объявлений (702 просмотра, 204 обращения — лучшее в кабинете), общая форма 3 (104/29), плюс наши пять. СПРОС ПО ВОРДСТАТУ (Россия, месяц): футбольная форма на заказ 2205, спортивная форма на заказ 879, пошив спортивной формы 538, волейбольная 456, баскетбольная 310, хоккейная 163, форма для регби на заказ 0. СВОБОДНЫЕ НИШИ ОКАЗАЛИСЬ ПУСТЫМИ ПО СПРОСУ: гандбол 199, кимоно 119, гимнастика 101, черлидинг 92. Владелец отклонил их справедливо: объявление без спроса не даст обращений, и тест рубрики станет неинтерпретируемым — не отличить «плохая рубрика» от «нет спроса». ГЛАВНАЯ НАХОДКА: общие запросы «спортивная форма на заказ» (879) и «пошив спортивной формы» (538) в товарной рубрике не закрыты вообще — ни нашими объявлениями, ни клиентскими, они висят только в услугах. Это 1417 запросов в месяц свободного места со спросом. ОТДЕЛЬНО: у регби ноль запросов по «форма для регби на заказ» — расширять эту тему платно не стоит.

Ждём выбор тем от владельца: предложены «спортивная форма на заказ» + «пошив спортивной формы» (обе свободны в товарах) + футбол либо волейбол. Футбол это максимальный спрос 2205, но пересечение с мёртвой частью карточек клиента; волейбол даёт самый чистый тест — у клиента там одно объявление и оно лучшее в кабинете. После выбора: три объявления, цена минимального пакета продвижения в товарной рубрике, срок теста три недели, метрика — обращений на рубль против наших же объявлений в услугах.

18.08.2026, 09:20:43 · · claude

Опубликованы две статьи в блоге ISKRA под незакрытые запросы Вебмастера: «Шапки и аксессуары для хоккейной команды на заказ» (запрос с 28 показами, ничем не был закрыт) и «Форма для регби на заказ» (10 показов, позиция 10,2, страница /rugby без текста). В блоге теперь 10 статей, в карте сайта был 19 адрес, стал 21. ПОРЯДОК СОБЛЮДЁН: свежая копия живого блога -> сборка поверх неё -> сверка -> заливка. Сверка отказала с первого раза и правильно: реестр _articles.json был записан с отступом 1 и переносами LF вместо 2 и CRLF, построчное сравнение увидело это как пропажу 80 строк. Починена запись, а не проверка. После правки только добавления: index +18/-0, реестр +20/-0. Залит 21 файл, ошибок ноль. Восемь прежних статей на месте. СОЗДАН ПОСТОЯННЫЙ СБОРЩИК C:\tmp\iskra-blog-build.py: каркас страницы берётся у живой статьи (иначе новая статья унаследует позапрошлую шапку — та же причина, по которой существует blog-publish.py), добавляется запись в реестр, пересобирается список блога, дописывается карта сайта. Публикация статьи теперь две команды. СТАНДАРТ СОГЛАСОВАНИЯ (C:\tmp\articles-preview.py): разводная страница с карточками, клик открывает статью отдельной вкладкой в оформлении сайта. Обязательно вырезать style генератора — он сужает обложку до 900px и отменяет uppercase заголовков; на живых страницах его нет. Владелец: «сделай стандарт как отдавать мне на согласование и все» — до этого я три раза подряд собирал превью по-новому. В базе обе статьи помечены published со ссылками.

Дефект генератора статей не починен: seo-article кладёт в html свой блок <style>, который перебивает оформление сайта. Сейчас его вырезает сборщик блога, но при любой другой публикации статья выглядит неправильно — стоит убрать из генератора. Ждут решения владельца: тест 2-3 объявлений Авито в товарной рубрике (нужна цена минимального пакета продвижения), приём форм сайта к нам или Турбо-страница для контактов из Директа, продвижение на четырёх объявлениях Авито. Просрочена проверка: дозамер семантики 5 кампаний Директа (упирались в суточный лимит Вордстата, 8 дней). Проверки 30.08: новая выгрузка Вебмастера для сравнения позиций, итог теста Директа на 15 тысячах.

17.08.2026, 07:41:09 · · claude

Кабинет клиента доведён до рабочего места маркетолога. РАЗРЕЗЫ ДИРЕКТА: эндпоинт /ads/direct/goals — матрица «цель × кампания × цена цели». Вскрылось, что «37 целевых действий» это сумма несопоставимого: заявок 2, остальное вовлечённость (просмотр второй страницы, задержка 15 секунд). Цели теперь делятся на заявка/обращение/вовлечённость по классификатору имён; в сводке стоят заявки с ценой. Сбор ad-analytics-collect для Директа запрашивает отчёт только по целям-заявкам — иначе в конверсии попадает всё подряд. Ловушка API: с указанными целями колонка называется Conversions_<goalId>_LSCCD, а не Conversions, и складывать колонки нельзя (одно действие засчитывается нескольким целям) — берём максимум. Записано в docs/YD-MACHINE.md. ПОГРУЖЕНИЕ: раздел в аналитике с четырьмя вкладками — поведение (часы, дни, устройства, города, страницы с долей заявок), поисковые запросы Директа, объявления, география. Видно, что ПК конвертит втрое лучше смартфонов, вторник в 9 раз лучше четверга, и 424 руб ушло на клики без заявок («canva», «готовый план помещения салона красоты»). ФИЛЬТРЫ ЛИДОВ: по источнику, чьей рекламе и типу обращения — в API и в интерфейсе. ДАШБОРД переделан: вместо агентов и рассылок — заявки с недельной динамикой, расход, цена заявки, последние заявки с текстом и пометкой чьей рекламы, состояние Директа и Авито. ЗАПУСК КАМПАНИЙ: apply-brief перед созданием проверяет счётчик и при наличии заявок запускает на WB_MAXIMUM_CONVERSION_RATE с ключевой целью вместо кликов (правило владельца: чей код собрал статистику, в том кабинете и стратегия за конверсии). СТАТЬИ: две новые под незакрытые запросы Вебмастера — шапки/аксессуары (28 показов, тема не закрыта) и форма для регби (10 показов, позиция 10,2). Обе прошли проверки на повтор, лежат в базе как ready, не залиты. Заведён стандарт согласования: C:\tmp\articles-preview.py — разводная страница + полные статьи в оформлении сайта; обязательно вырезать style генератора, он сужает обложку до 900px и отменяет uppercase заголовков. АНАЛИТИКА ДЛЯ ВЛАДЕЛЬЦА: https://myvisionagency.ru/lab/iskra-results/ — поиск, Авито, Директ с честными сроками (Авито 3-5 дней, Директ второй день). ПРОВЕРЕНО ФАКТАМИ: расход Авито ноль честно — площадка не списала ни рубля за наши объявления, пакеты продвижения в рубрике услуг недоступны (только оформление). Наши объявления показываются как клиентские в той же рубрике (~2 просмотра в день), разница лишь в возрасте. В услугах конверсия 25% бесплатно против 4,8% и 420 руб за обращение в товарах — вывод «переносить всё в Спорт и отдых» был неверным, снят. Заявки с контактами Директ отдаёт только с Турбо-страниц (leads.get требует TurboPageIds), их у клиента нет.

Заливка двух статей — владелец сказал через полтора часа (снять копию блога, добавить, сверить что 8 существующих на месте, обновить список и sitemap). Ждут решения: тест 2-3 объявлений Авито в товарной рубрике (нужна цена минимального пакета продвижения); приём форм сайта к нам или Турбо-страница, чтобы получать контакты; продвижение на четырёх объявлениях Авито. Проверки: 30.08 новая выгрузка Вебмастера, 30.08 итог теста Директа на 15 тысячах.

16.08.2026, 07:35:10 · · claude

Переделан кабинет клиента (ISKRA). Раздел Реклама разбит на вкладки Авито и Яндекс Директ: в каждой деление наши/клиентские, полная статистика, карточки с картинками и модалкой, статусы по-русски. Из меню клиента убраны Кампании и Каналы (они про рассылки). Лиды: вместо одной сводки в день — 402 заявки поштучно (75 с сайта из журнала визитов Метрики, 327 обращений с Авито с именем и текстом, с пометкой чья реклама). Аналитика перестроена под клиента: заявки вместо агентов и рассылок, разбор по источникам и типам обращений. Добавлены блок Яндекс Метрики (расшифровка целевых действий + источники) и блок Поиск и статьи (органика по неделям +42% и позиции из Вебмастера). Заведена таблица seo_search_positions с RLS, загружена выгрузка Вебмастера 138 запросов за 01-14.08. ПОЧИНЕНО: (1) сбор статистики Директа запускался только вручную кнопкой, расписания не было вовсе — заведён ежедневный воркер ads-analytics-cron на 6:30 МСК, он же подтягивает чужие кампании кабинета; (2) счётчик Метрики клиента не был зарегистрирован — 35 заявок за месяц шли мимо кабинета; (3) кампании Директа висели черновиками, кабинет писал «на паузе»; (4) статистика не показывалась из-за обращения на уровень глубже в коде экрана. НАЙДЕНО ПО АВИТО: у площадки два независимых продвижения — ставка за просмотры (cpxpromo) и пакет услуг (vas), проверяются разными вызовами и не связаны. Записано в docs/AVITO-MACHINE.md. Продвижение стоит только на 1 из 5 наших объявлений, владелец решил пока не трогать. ЧЕСТНОСТЬ ЦИФР: сначала засчитал себе все 56 заявок с рекламы за месяц, но наши кампании запущены 15-16.08 — до этого крутилась реклама прежнего подрядчика (350+ визитов в день до 5 августа). Исправлено: своими считаются только заявки после начала наших показов, остальные идут строкой «реклама, что шла до нас». Цена заявки не показывается, пока их меньше пяти.

Не сделано: экран Дашборд (главная) не трогали — там осталась старая раскладка. Продвижение на четырёх объявлениях Авито не поставлено по решению владельца. Модерация Директа пройдена, обе кампании ACCEPTED, идут показы: 1173 показа, 43 клика, 554 руб за двое суток. Проверка 30.08 — новая выгрузка Вебмастера для сравнения позиций. Проверка 30.08 — итог теста Директа на 15 тысячах.

16.08.2026, 05:50:31 · · claude

Три вещи по итогам разбора Авито. Первое и главное: статистика не показывалась в кабинете вовсе - блок был добавлен, данные собирались, эндпоинт отдавал их правильно, а экран молчал. Причина в коде экрана: хук useApi уже разворачивает поле data ответа, а обращение шло к adSpend.data.channels, то есть искали data внутри data. Ошибка тихая, ни в консоли ни в запросах ничего. Исправлено, кабинет пересобран и выложен с бэкапом app.bak-2026-08-16. Проверено вызовом эндпоинта от лица владельцев обоих кабинетов: MyVision видит Директ 59089 руб на 2159 конверсий и Авито отдельно наше и клиентское, ISKRA видит наши 13 показов и клиентские 2122 показа при 291 обращении. Второе: очередь предложений расчищена - 287 штук (234 proposed и 53 pending_review) помечены cancelled_stale, не удалены, чтобы осталась история решений критика. Третье: моё утверждение про разошедшиеся статусы оказалось неверным - я считал записи со статусом published, а в кабинете MyVision схема active/exhausted/archived/draft. Сверка по номерам объявлений: в кабинете 17 активных, в базе живыми помечены 15, расхождение одно и оно намеренное - авто-возврат объявлений в фид отключён после инцидента 16 июля, когда создал 4 дубля. Страница разбора поправлена.

Через неделю смотреть исправленный замер экспериментов (проверка на 23.08). Очередь теперь копится с чистого листа - через неделю будет видно, сколько машина предлагает в норме и сколько из этого доходит до объявлений.

16.08.2026, 05:34:11 · · claude

Разбор механики улучшений Авито по двум кабинетам, страница myvisionagency.ru/lab/avito-mehanika. Найдена системная ошибка измерения: показатели до снимались за 7 дней, результат считался за 3, сравнивались суммы. Из-за этого почти любая правка выглядела провальной - отношение стало к было держится в районе 12-43 процентов, то есть ровно 3/7, это арифметика окна а не качество работы. Итог: из 389 измеренных правок лучше признаны 24, хуже 365. Вторая находка: авто-откат не сработал ни разу за всю историю, потому что его условие требовало чтобы просмотров было не меньше прежнего, а при вдвое коротком окне это почти невыполнимо. Предохранитель был, но сработать не мог. Третья: очередь предложений стоит - 234 предложено и 53 ждут решения человека, самые старые с апреля и мая. Исправлено: окно результата приведено к 7 дням, вердикт выносится по доле обращений на просмотр а не по сумме, на малых числах вердикт не выносится вовсе. Что работает хорошо: критик отсеивает разумно (72 отклонил при уверенности 0.35, 53 применил при 0.89), связка объявлений с площадкой держится, категории не схлопнулись в одну.

Через неделю смотреть, что покажет исправленный замер - проверка заведена на 23.08. Стоит синхронизировать статусы объявлений: в базе 0 опубликованных и 20 в архиве, тогда как на Авито активны 18, машина решает по устаревшей картине. Разобрать очередь из 287 предложений - часть устарела с апреля.

15.08.2026, 23:26:40 · · claude

Директ ISKRA ЗАПУЩЕН. Деньги на счету нашлись - 24590 руб, пополнение прошло между проверками. Кампании Поиск и РСЯ включены: State ON, Status MODERATION, 169 объявлений отправлено на модерацию. Бюджеты как договорились: 5000 и 2500 руб в неделю, итого 15000 за две недели. Перед запуском предполётная проверка: 56 и 32 группы, пустых нет, 2352 фразы, 8 городов, посадочные ведут на разделы видов спорта. По дороге три грабли, все записаны в карту. Первая: гейт запуска работает на отказ и не дал включить кампании, потому что их не было в ad_campaigns - создавались скриптом мимо базы. Это же означало, что и аналитика Директа не собиралась бы. Завёл три кампании. Вторая: campaigns.resume на черновике отвечает что кампания является черновиком и не может быть остановлена - сначала нужен ads.moderate, и только потом resume. Третья, из прошлого шага: PriorityGoals принимает только Operation SET. Отдельно решён вопрос конверсий: кабинет Директа не имел доступа к счётчику Метрики, выдали сами через API, иначе цена заявки не посчиталась бы вовсе.

Завтра проверить что модерация приняла объявления и пошли показы. Через две недели посчитать цену заявки отдельно по Поиску и РСЯ, сравнить с планкой 500-700 руб. Ретаргет не запускали - аудитории мало.

15.08.2026, 23:18:18 · · claude

Директ ISKRA: денег на счёте нет, но найдена и устранена проблема поважнее. Проверен баланс - счёт 713437598 логин directiskra, ноль рублей, счёт в кабинете один, деньги не поступали. Способа узнать баланс в карте не было: v5 accounts отвечает 404, работает старый живой API v4 AccountManagement. Главное: счётчик Метрики 109572218 был ПРОПИСАН в кампаниях, но кабинет Директа доступа к нему не имел - счётчик принадлежит логину printflag-direct, доступ был выдан только advcreative и ShamrayGroup1. При таком раскладе в отчётах Директа был бы ноль конверсий при любом расходе, и задача посчитать цену заявки провалилась бы через две недели над пустым отчётом. Доступ выдали сами через API Метрики (у нашего токена права edit на счётчик), клиента дёргать не пришлось. Кампании подготовлены к тесту: Поиск 5000 руб/нед, РСЯ 2500 руб/нед, приоритетные цели Оставил заявку и Клик на телефон. Отдельная грабля: PriorityGoals принимает только Operation SET, без поля и с ADD падает вся правка кампании включая бюджет. Всё записано в docs/YD-MACHINE.md.

Ждём пополнения счёта. Как придут деньги - включить Поиск и РСЯ (campaigns.resume), через две недели посчитать расход делить на конверсии по целям заявка и звонок. Ретаргет не трогаем: аудитории мало. Проверка баланса заведена на 18.08.

14.08.2026, 09:59:13 · · claude

Две статьи опубликованы, в блоге 1skra.ru теперь восемь. Порядок прежний: свежая выкачка живого сайта (15 файлов), сверка с рабочей копией - расхождений ноль, клиент за сутки сайт не трогал, сборка поверх живого состояния, проверка что ничего не исчезает, заливка. В карте сайта стало 19 адресов против 17, ни один не пропал. Проверено на живом: все восемь статей открываются, обложки отдаются, счётчик Метрики на новых страницах на месте, главная и страницы видов спорта целы. Ротация обложек сработала как задумано: у новых статей баскетбол и лёгкая атлетика, хоккея в ленте больше не прибавилось. По дороге поправлен сборщик списка - имя файла обложки теперь содержит метку вида спорта, и собирать путь из адреса статьи больше нельзя, ищем файл на диске.

В очереди остались две свободные темы: влияние формы на результаты и анатомические особенности кроя. Крон на Sonnet работает без холостых прогонов. Проверка захода блога в индекс уже стоит. Директ по-прежнему с нулём на счету.

14.08.2026, 09:47:10 · · claude

Три новых объявления ISKRA залиты и работают: волейбол, баскетбол, регби. Владелец решил цену не снижать - все пять идут по 990 руб, проверка гипотезы про цену на них отменена. Фид собран из пяти объявлений (прежние два обязаны оставаться в файле, иначе автозагрузка их снимет), валидатор дал 6 зелёных без ошибок, выгрузка отработала: активных объявлений стало 39 против 36, ничего не снялось. Все пять заведены в карту avito_ad_map - без записи там машина объявление не видит вовсе. Выгрузка last_successful обновляется с задержкой в часы, поэтому три новых связаны по заголовку, штатный seed-ad-map подтвердит связку из источника правды позже. На хоккейное включено продвижение 350 руб/день авто-бюджетом. По дороге: ступени ровно 400 руб у Авито нет (200, 250, 350, 450, 550, 650), и в ответе getBids отсутствует поле isActive - установленный бюджет лежит в auto.budgetPenny, из-за чего я сначала решил что включение не сработало. Оба факта записаны в карту механики.

Через неделю смотреть отдачу пяти объявлений и что дало продвижение на одном против четырёх без него - проверка заведена на 21.08. Ждут ок две статьи на lab/iskra-articles. Директ по-прежнему с нулём на счету, кампании в черновиках.

14.08.2026, 06:47:42 · · claude

Страница аналитики для клиента дополнена нашей работой: myvisionagency.ru/lab/iskra-avito-stat. Добавлены три раздела. Первый - как идут наши два объявления: 9 просмотров за два дня против среднего по кабинету 5.4 на объявление, то есть пока на уровне его собственных, с оговоркой что два дня это мало и Авито поднимает новые объявления постепенно. Второй - три новых объявления с превью креативов и подписью стилистики: волейбол светлый студийный, баскетбол яркий контрастный, регби репортажный. Третий - прямой вопрос по цене: в новых стоит от 100 руб вместо 990, основание приведено на его же данных (23.4 процента против 5.0 на одном товаре), объяснено что цена в карточке работает как приглашение, и что прежние два оставляем по 990 намеренно ради честного сравнения через неделю. Вопрос вынесен отдельной плашкой: запускаем три новых с ценой от 100 или ставим 990.

Ждём ответ владельца по цене в новых объявлениях. После ответа - фид из пяти объявлений через валидатор и заливка. Отдельно ждут ок две статьи на lab/iskra-articles. Директ по-прежнему с нулём на счету.

14.08.2026, 06:43:01 · · claude

Данные Авито теперь доходят до кабинета клиента, и своя работа отделена от клиентской. Раньше по Авито в кабинете было пусто: общий сборщик умеет только ВК и Директ, у него модель есть-кампания-сходи-за-цифрами, а у Авито кампаний нет. Сделан отдельный сбор avito-analytics: единица учёта объявление, дневные снимки в общие таблицы, расход из истории операций и обязательно по дням - иначе кабинет показывает ноль при потраченных десятках тысяч. Воркер ежедневно в 6:00 МСК с окном в неделю. Ключевая правка по замечанию владельца: у ISKRA 36 объявлений, ведём мы два, остальное клиент завёл сам, и там его флаги с сотней обращений - показывать это одной цифрой значит записывать себе чужую работу. Признак наше берётся из карты avito_ad_map, эндпоинт ad-spend отдаёт две части: channels наша работа, clientOwn клиентская. Заодно заведены в карту два наших объявления ISKRA - без записи там машина их не видела вовсе: ни ставок, ни продвижения, ни сверки. На экране аналитики два блока, кабинет собран под боевой домен и выложен с бэкапом app.bak-2026-08-14.

Проверить экран после входа под клиентом. Цифры сейчас: наши два объявления 9 просмотров и ноль обращений (опубликованы 12.08), клиентские 2096 просмотров и 279 обращений при расходе 23660 руб. По ВК и Директу разделения нет намеренно - их ведём мы целиком, но Директ пока стоит без денег.

14.08.2026, 06:02:57 · · claude

Три новых объявления Авито для ISKRA готовы и ждут ок: myvisionagency.ru/lab/iskra-avito-new. Волейбол, баскетбол, регби - виды, где у клиента по одному-два объявления. У каждого своя стилистика креативов, потому что прежние два были оба тёмно-синие дымные и в выдаче читались как одно: волейбол светлый студийный на белом фоне, баскетбол тёмный с контровым оранжевым светом, регби репортажный на настоящем поле при дневном свете. Форма и бренд взяты с фотографий клиента, свет и фон заданы промптом отдельно - иначе image-to-image наследует подачу референса и вышел бы третий дым подряд. 30 кадров 1240x960, русский текст запечён в картинку, потрачено 90 руб. Цена в новых объявлениях от 100 руб вместо 990 - проверяем гипотезу, что 990 отсекает обращения. Имена швей разные: Ольга, Татьяна, Елена. Собран генератор фида на пять объявлений: два прежних обязаны остаться в файле, иначе автозагрузка их снимет.

Ждём ок по объявлениям и по двум статьям (требования к форме, лёгкая атлетика). После ок: фид из пяти объявлений через валидатор, картинки выложить в org-папку, залить. Директ стоит без денег - на счету 0, кампании в черновиках.

14.08.2026, 04:23:28 · · claude

Статистика по всем каналам ISKRA. ДИРЕКТ: денег НЕ залили, на счету 0 руб, все три кампании в черновиках и выключены. Способ узнать баланс в карте отсутствовал - v5 accounts даёт 404, работает v4 Live AccountManagement с Action Get, кабинет directiskra, счёт 713437598. АВИТО клиента за неделю: 554 просмотра, 84 обращения, 15.2 процента. Наши два объявления за неполные двое суток: 6 и 3 просмотра, ноль обращений - это ровно уровень среднего по кабинету (5.4 просмотра на объявление за тот же срок), оба активны, не заблокированы. Гипотеза про цену на этих же двух днях только укрепилась: дорогие объявления по 990 руб дали 104 просмотра и 1 обращение, флаги по 140-150 руб - 50 просмотров и 10 обращений. НАШ кабинет Авито: аванс 2698 руб, пополнен. Написаны две новые статьи не про хоккей - требования к форме (обложка баскетбол) и особенности лёгкой атлетики (обложка атлетика), обе с первой попытки, ждут ок на lab/iskra-articles.

Директ не тронется, пока не пополнят счёт - сказать владельцу. По Авито предложить 2-3 новых объявления по другим видам спорта в другой стилистике креативов (сейчас все тёмно-синие), с гейтом по деньгам: 10 картинок на объявление по 3 руб. Отдельно предложить проверить гипотезу цены - поставить на одно объявление 100-150 руб вместо 990.

13.08.2026, 10:15:48 · · claude

Обложки статей перестали быть хоккейными по умолчанию. Владелец заметил: из шести статей блога пять с хоккеем. Причина в коде - если тема не про конкретный вид спорта (а таких большинство), выбор образца брал просто первый кадр пула, а первым там лежит hockey-hero. Ротации не было вовсе, хотя у клиента в пуле шесть видов спорта. Теперь для общих тем берётся вид, которого дольше всего не было в ленте. По дороге вскрылась вторая половина проблемы: сравнение шло по имени файла, а имя генерируемой обложки собирается по адресу статьи и с образцом совпасть не может никогда - история читалась как пустая. Вид спорта теперь пишется в колонку images и в имя нового файла, а история берётся из записанного вида. Шести опубликованным статьям вид проставлен вручную по факту их картинок. Проверено без генерации: для очереди выбираются basketball, volleybal, athletics, rugby - ни одного хоккея, он занимает всю свежую историю.

Лента сейчас всё ещё 5 хоккеев из 6 - это прошлые статьи. Предложить владельцу перевыпустить 2-3 обложки, чтобы выровнять сразу (около 3 руб за картинку плюс перезаливка блога). Завтрашние статьи уже пойдут с разными видами.

13.08.2026, 09:19:17 · · claude

Две новые статьи опубликованы на 1skra.ru/blog, в блоге теперь 6 штук. Порядок соблюдён тот, о котором просил владелец: сначала свежая выкачка живого сайта (11 файлов), сверка с моей копией - расхождений ноль, клиент за сутки ничего не менял, - и только потом сборка ПОВЕРХ живого состояния. Предохранитель сработал на карте сайта и остановил заливку: строка блога выглядела исчезнувшей, хотя у неё лишь поменялась дата lastmod. Разобрано по адресам: пропадает ноль, добавляется два. Сверку карты сайта научил сравнивать адреса, а не строки - иначе он кричал бы при каждой публикации, а предохранитель, срабатывающий без повода, перестают читать. Проверено на живом: 6 статей и обе новые открываются, обложки отдаются, счётчик Метрики на месте, в карте сайта 17 адресов, главная и страницы видов спорта целы.

В очереди 4 свободные темы: требования к спортивной форме, влияние формы на результаты, особенности лёгкой атлетики, анатомические особенности кроя. Крон на Sonnet теперь должен работать без холостых прогонов - обе причины устранены. Через неделю смотреть, зашли ли статьи в индекс (проверка уже стоит).

13.08.2026, 09:07:53 · · claude

Две новые статьи для ISKRA готовы и ждут ок владельца: myvisionagency.ru/lab/iskra-articles. Темы взяты из очереди по свободным ядрам - подготовка к сезону (16629 показов, самая спрашиваемая фраза кабинета) и печать на форме (про сублимацию, то есть про отличие компании). Обе прошли с первой попытки, 7811 и 7224 знака, по 4 раздела и 4 вопроса, обложки сгенерированы автоматически в стиле съёмки клиента. По дороге починены две вещи, из-за которых крон работал вхолостую два дня: критик Авито блокировал статью за домен в тексте, и фразы отбракованных дублей я вернул в очередь, откуда завод брал их снова. Также страница с двумя объявлениями Авито была затёрта аналитикой по тому же адресу lab/iskra-avito - восстановлена из локальной копии, аналитика переехала на lab/iskra-avito-stat, правило про проверку занятости адреса записано в скилл и память.

Ждём ок по статьям. После ок: сборка iskra_blog.py поверх свежей выкачки (blog-publish.py backup, потом check, потом upload), обложки забрать с aitodo /var/leadforge/seo-covers и залить первыми. В очереди остались 4 свободные темы: требования к спортивной форме, влияние формы на результаты, особенности лёгкой атлетики, анатомические особенности кроя.