diff --git a/docs/superpowers/2026-07-12-HANDOFF-sales-finder-STATE.md b/docs/superpowers/2026-07-12-HANDOFF-sales-finder-STATE.md index d91fdc4d..b1705223 100644 --- a/docs/superpowers/2026-07-12-HANDOFF-sales-finder-STATE.md +++ b/docs/superpowers/2026-07-12-HANDOFF-sales-finder-STATE.md @@ -174,56 +174,60 @@ python -m uvicorn web.app:app --host 127.0.0.1 --port 8200 - Запрос, дающий ОДНУ фирму, 2ГИС показывает карточкой, а не списком — парсер вернёт 0. - **ПДн** (личный ИНН директора — персональные данные) — владелец сказал: **отдельная задача**. -## 7. Что осталось / следующие шаги (по приоритету) +## 7. Что осталось (пп.1-6 прежнего списка — СДЕЛАНЫ, см. §6.2) -1. **Приёмка в браузере** — поднять uvicorn, владелец прокликает нишу+город, скачает Excel. -2. **Поднять покрытие ДИРЕКТОРА** (сейчас 4/12): открывать карточку 2ГИС через xfetch и/или - страницу реквизитов сайта (`/kontakty`,`/o-klinike`,`/license`) → вытащить ИНН → ДаДата. - Альтернатива директору без ИНН: ДаДата по названию+городу (fuzzy) — проверить качество. -3. **Поднять покрытие ТЕЛЕФОНА** (10/12): структурный сбор с карточки 2ГИС (как боевой - `HtmlPhoneScanner` — брать из tel:/schema/microdata, не из тела), + xfetch-рендер сайтов, - что блокируют requests. -4. **Fix Important #1 из ревью:** `twogis.parse_listing` ставит `two_gis_promoted` НА ВСЮ - страницу (глобально), а не на карточку. Теперь есть реальный HTML 2ГИС (через xfetch) — - привязать метку «Реклама»/приоритет к конкретной фирме по её card-разметке. Иначе ранг врёт. -5. **Пагинация/объём:** `_real_pipeline` зовёт `collect_two_gis` с дефолтным max_pages=5 — - может быть медленно/дорого (xfetch-кредиты + фетч сайтов). Ограничить (напр. max_pages=1–2 - и/или cap N фирм) + прогресс в UI. -6. **Красота портала** — перенести стиль `ad-scan-v2/build_portal.py` (палитра Forest) в - экран результата (сейчас минимальный HTML). -7. **ПДн:** перед реальным использованием — короткий проход `pdn-152fz-audit` (ФИО директора, - телефоны — внутренний инструмент, не публикуем). +**Ничего срочного. Инструмент готов к использованию.** Открытые пункты: + +1. **ПДн-аудит** — личный ИНН директора = персональные данные (152-ФЗ). Владелец: **отдельная + задача**, не сейчас. +2. **Глубина 2ГИС** — берём верхушку (~50 фирм/город). Владелец: **«не надо, достаточно»**. + Если передумает: больше страниц + больше синонимов-запросов + не терять сорванные рендеры. +3. **Приёмка** — владелец смотрел списки, правил на ходу; финальной формальной приёмки не было. ## 8. Границы (НЕ нарушать) -- Боевой автоподбор (`.claude/worktrees/avtopodbor`, `worktree-avtopodbor`) и боевой - `моя/ad-scan/` — НЕ трогать, только читать/копировать приёмы. Прод liderra.ru — не трогать. +- Боевой автоподбор (`.claude/worktrees/avtopodbor`) и боевой `моя/ad-scan/` — **только читать** + (оттуда взяты: контракт xfetch, `keyso_api.domain_dashboard`, карта баз `regions.py`). + Прод liderra.ru — не трогать. - Ключи — только в `secrets/` (gitignore), НИКОГДА в код/git. +- **Keys.so: НЕ придумывать коды баз.** На неизвестный код он молча отдаёт московские цифры. + Список закрыт (`cities.KEYSO_BASE`, 19 шт.). +- **ФНС (ЕГРЮЛ): не долбить параллельно и НЕ обходить капчу.** Семафор=1. Если просит капчу — + честно возвращаем пусто. --- ## 9. RESUME PROMPT (вставить в новую сессию после компакта) ``` -Продолжаем портал поиска клиентов для отдела продаж (sales-finder). Прочитай сначала: -docs/superpowers/2026-07-12-HANDOFF-sales-finder-STATE.md (полное состояние), -затем при необходимости design/plan/brainstorm-notes от 2026-07-12. +Продолжаем портал поиска клиентов для отдела продаж (sales-finder). +Прочитай docs/superpowers/2026-07-12-HANDOFF-sales-finder-STATE.md — там полное состояние. -СОСТОЯНИЕ: v1 РАБОТАЕТ живьём end-to-end. Ветка feat/sales-finder, проект моя/sales-finder/, -42 теста зелёные (cd моя/sales-finder && python -m pytest -q). 2ГИС берётся через xfetch -(xf4.ru), Keys.so/ДаДата/телефон-с-сайта — работают. Секреты в secrets/. Границы: боевое -(автоподбор/ad-scan/прод) НЕ трогать, только копии; ключи только в secrets/. Коммит — сам, -у владельца уже есть общее «добро» на эту сборку (git add -f, т.к. моя/ в gitignore; -docs/observer/STATUS.md если пре-стейджен — git restore --staged перед коммитом). +СОСТОЯНИЕ: РАБОТАЕТ, готов к использованию. Ветка feat/sales-finder, проект моя/sales-finder/, +146 тестов зелёных (cd моя/sales-finder && python -m pytest -q). +Портал: cd моя/sales-finder && python -m uvicorn web.app:app --port 8200 → http://127.0.0.1:8200 -Живой прогон 12.07 (стоматология moscow): 12 фирм, телефон 10/12, директор 4/12. +ЧТО УМЕЕТ: менеджер выбирает нишу (реальный рубрикатор 2ГИС: 19 разделов, 100 ниш) и город +(столицы регионов по 12 макрорегионам, Москва≠Подмосковье, Питер≠Ленобласть; есть пункт +«★ ВЕСЬ РЕГИОН» — кластер по всем городам группы). Получает список на прозвон: телефон, сайт, +ГДЕ рекламируется (Директ/коллтрекинг/пиксели), БЮДЖЕТ Директа (вилка ₽/мес + «запросов +в рекламе»), ИНН, ОГРН, юр.адрес, директор + должность + ЕГО ЛИЧНЫЙ ИНН. Выгрузка в Excel. +Сортировка: готов к звонку (директор+его ИНН) → горячесть → есть ФИО → каналы → бюджет. -СЛЕДУЮЩИЙ ШАГ (спроси владельца, что первым — §7 HANDOFF): -1) приёмка в браузере (uvicorn web.app:app :8200); -2) поднять покрытие директора (карточка 2ГИС/страница реквизитов → ИНН → ДаДата); -3) поднять покрытие телефона (структурный сбор с карточки 2ГИС); -4) fix two_gis_promoted per-firm (ревью Important #1) — теперь есть реальный HTML 2ГИС; -5) пагинация/объём + прогресс; 6) красота портала (стиль build_portal.py); 7) pdn-152fz-audit. +ИСТОЧНИКИ (все проверены живьём): 2ГИС через xfetch(xf4.ru) — листинг + КАРТОЧКА фирмы +(в листинге сайт есть не у всех!); Keys.so domain_dashboard — бюджет, ОБЯЗАТЕЛЬНО с региональной +базой (cities.KEYSO_BASE, 19 кодов; на неизвестный код молча отдаёт МОСКОВСКИЕ цифры!); +ДаДата — ИНН/ОГРН/директор/адрес; ЕГРЮЛ ФНС (egrul.nalog.ru, бесплатно, без капчи) — ЛИЧНЫЙ +ИНН директора; сайт фирмы — телефон и ИНН (Контакты/Реквизиты смотреть РАНЬШЕ Политики — +там реквизиты хостера!). Секреты в secrets/. -Работай по TDD, субагентами (Sonnet+) как раньше. Ничего боевого не трогай. +ГРАНИЦЫ: боевое (автоподбор/ad-scan/прод liderra.ru) НЕ трогать, только читать. Ключи только +в secrets/. ФНС не долбить параллельно (семафор=1), капчу НЕ обходить. Коды баз Keys.so +не выдумывать. Коммит — сам, у владельца есть общее «добро» (git add -f — моя/ в gitignore; +git restore --staged docs/observer/STATUS.md перед коммитом; форсить КОНКРЕТНЫЕ файлы, не каталог). + +ОТКРЫТО: (1) ПДн-аудит личного ИНН директора — владелец сказал «отдельная задача»; +(2) глубина 2ГИС (берём верхушку ~50 фирм/город) — владелец сказал «не надо, достаточно». + +Работай по TDD. Спроси владельца, что делать дальше. ``` diff --git a/моя/sales-finder/salesfinder/render.py b/моя/sales-finder/salesfinder/render.py index 7895ace2..04ccb954 100644 --- a/моя/sales-finder/salesfinder/render.py +++ b/моя/sales-finder/salesfinder/render.py @@ -2,7 +2,7 @@ import csv, openpyxl COLUMNS = ["Фирма", "Город", "Телефон", "Сайт", "Рекламируется", "Где рекламируется", - "Бюджет Директ от, ₽/мес", "Бюджет Директ до, ₽/мес", "Ключей Директ", + "Бюджет Директ от, ₽/мес", "Бюджет Директ до, ₽/мес", "Запросов в рекламе", "Уверенность", "Доказательства", "ИНН", "ОГРН", "Директор", "ИНН директора", "Должность", "Юрлицо", "Статус", "Юр. адрес", "Горячесть"] @@ -16,7 +16,7 @@ def to_rows(firms: list) -> list: "Где рекламируется": ", ".join(f.channels or []), "Бюджет Директ от, ₽/мес": f.direct_budget_min or "", "Бюджет Директ до, ₽/мес": f.direct_budget or "", - "Ключей Директ": f.direct_keys or "", + "Запросов в рекламе": f.direct_keys or "", "Уверенность": f.confidence or "", "Доказательства": "; ".join(f.evidence or []), "ИНН": f.inn or "", diff --git a/моя/sales-finder/tests/test_ui.py b/моя/sales-finder/tests/test_ui.py index 18c84ee0..57b91f91 100644 --- a/моя/sales-finder/tests/test_ui.py +++ b/моя/sales-finder/tests/test_ui.py @@ -50,7 +50,7 @@ def test_results_shows_channels_and_budget(): assert "Яндекс.Директ" in html assert "Calltouch (коллтрекинг)" in html assert "77 922" in html and "177 570" in html # вилка бюджета с разрядами - assert "812 ключей" in html + assert "812 запросов в рекламе" in html # по-человечески, а не жаргон «ключи» assert "горячая" in html # понятная подпись вместо цифры diff --git a/моя/sales-finder/web/ui.py b/моя/sales-finder/web/ui.py index 6ee7de9a..cc24a024 100644 --- a/моя/sales-finder/web/ui.py +++ b/моя/sales-finder/web/ui.py @@ -177,7 +177,10 @@ def _budget_cell(f): return '—' rng = f"{_money(lo)} – {_money(hi)}" if lo and lo != hi else _money(hi) keys = f.get("direct_keys") or 0 - sub = f'{keys} ключей' if keys else "" + # «ключи» — жаргон Keys.so. По-человечески это поисковые запросы, по которым + # фирма показывает рекламу: чем их больше, тем плотнее она сидит в Директе. + sub = (f'' + f'{keys} запросов в рекламе') if keys else "" return f'{rng}{sub}' @@ -261,8 +264,9 @@ def results_html(run): '