Commit Graph

2799 Commits

Author SHA1 Message Date
Дмитрий a2e5fdd7fd docs(autopodbor): спека «свой канал 2ГИС+Яндекс на виртуалке» (замена xf4)
Дизайн утверждён владельцем в брейншторме: рендер своим браузером с
маскировкой + ротация RU-прокси вместо платного xf4, чистый разбор 2ГИС
через перехват встроенного JSON (убирает трэш), постоянный браузер,
всё на выделенной виртуалке (не на боевом портале), за флагом self_render
с откатом на xf4. Планка приёмки — фирма-в-фирму с живым 2ГИС.
UI/кнопки/функции не трогаются. Замер: 25 мин xf4 → 9 мин свой рендер.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 17:17:11 +03:00
Дмитрий 5c8b344bcf fix(autopodbor): разворот глубина 1 по умолчанию + массовое удаление предложений
Разворот по телефонам 2ГИС и Яндекс больше не уходит цепочкой «до талого»:
по умолчанию берём только фирмы с ЛИЧНЫМ номером фирмы — глубина 1. Именно
неограниченная цепочка уводила в чужие фирмы, давая мусорные сайты в
предложениях холдинга. Многошаговый разворот сохранён за параметром maxDepth,
по умолчанию 1. Изолировано: работает только под флагом phone_reverse, основной
пул сбора не затрагивается. Бэкенд автоподбора 430 из 430.

Фронт: на вкладке «Предложения» добавлена кнопка массового удаления выбранных
источников — bulkDeleteProps через removeSource, покрыта тестами.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 15:33:31 +03:00
Дмитрий 43e29823a8 perf(autopodbor): разнести шаги по очередям — find (ИИ) и study (тупой слой)
Раньше поиск, резолв и изучение делили одну очередь autopodbor — при одном
воркере быстрый шаг 2 (изучение) стоял за тяжёлым шагом 1 (поиск с ИИ) другого
клиента. Теперь два процесса:
  • шаг 1 «собрать поле» (поиск + резолв по имени, ИИ+внешние) → autopodbor-find
  • шаг 2 «дайте источники / изучение» (без ИИ) → autopodbor-study
Идут параллельно, друг друга не держат. Замок WithoutOverlapping по runId цел.

Запуск теперь двумя воркерами:
  queue:work redis --queue=autopodbor-find  --timeout=3600
  queue:work redis --queue=autopodbor-study --timeout=3600

TDD: AutopodborQueueThrottleTest 4/4, автоподбор 434/434.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 15:28:51 +03:00
Дмитрий bdecd08dcb perf(autopodbor): мульти-ключ xfetch round-robin — параллельность ключи×concurrency
Сбор 2ГИС упирался в лимит xf4.ru ~3-4 запроса за раз на КЛЮЧ (выше 429).
XfetchClient теперь принимает список ключей и раскидывает запросы по кругу:
размер пачки = concurrency × число ключей, каждому URL — свой ключ. Живой залп
подтвердил: 9 параллельно (3 ключа × 3) без 429 → лимит per-key, ключи дают ×3.

Ключи — только в .env (XFETCH_API_KEYS через запятую), в код/гит не идут; пусто →
работает по-старому на одиночном XFETCH_API_KEY. Совместимость: конструктор
принимает и строку, и список. TDD: XfetchClientTest 11/11, автоподбор зелёный.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 15:28:19 +03:00
Дмитрий da8e24dda6 chore(schema): canon-sync автоподбора v8.61 — хвост competitors/runs + журнал слияний
Завершён отложенный canon-sync автоподбора в теле db/schema.sql (в v8.60 явно
помечен «⏸ ХВОСТ»). Свёрнуты ранее отложенные инкременты + добавлена новая таблица:

- autopodbor_competitors +box (+chk proposal|field|archived) +индекс tenant_box
  +phones JSONB +elements JSONB.
- autopodbor_runs +progress +result JSONB.
- НОВАЯ autopodbor_merge_events (журнал слияний + снимок absorbed; RLS ENABLE+FORCE
  tenant_isolation; FK user_id/survivor_id SET NULL; индекс tenant_id,created_at).

ALTER-миграции доguard-ены (elements/runs_progress/runs_result — Schema::hasColumn
early-return) → migrate:fresh зелёный end-to-end, автоподбор 428/428, squawk 0,
rls-reviewer OK. Снят предвыкатный блокер по схеме. Воркстри avtopodbor, НЕ на проде.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 14:28:38 +03:00
Дмитрий 7d6516e6b2 feat(autopodbor): журнал слияний + возврат поглощённой карточки
Слияние конкурентов больше не «чёрная дыра» (баг «САПС/Метрополис»: карточка
исчезла без следа, вернуть было нечем). Теперь каждое слияние пишет событие в
autopodbor_merge_events со СНИМКОМ поглощённых карточек (имя/сайт/телефоны/
справочники), кто и когда слил.

- Таблица autopodbor_merge_events (+RLS tenant_isolation, паттерн 1:1 с sources,
  rls-ревью OK; nullOnDelete на survivor_id/user_id — история не рушится).
- AutopodborCompetitorMerger::merge($tenantId,$ids,$name,$userId) пишет событие.
- GET /field/merge-events — история; POST /field/merge-events/{id}/restore —
  возврат поглощённых как предложения (защита от повторного возврата).
- Фронт: панель «🕘 История слияний» + «↩ Вернуть карточку».

Бэк 428/428, фронт 12/12, Pint чистый, build ок. schema.sql канон-синк всех
таблиц автоподбора — предвыкатный TODO (вся фича migration-only в этой ветке).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 13:52:43 +03:00
Дмитрий 7d46548c6e fix(autopodbor): окно слияния показывает выживающую карточку и её имя по умолчанию
Баг «САПС/Метрополис»: клиент переименовал свежую карточку и слил — а выжила
ДРУГАЯ (с проектами/в поле), имя переименованной затёрлось вслепую, карточка
пропала. Теперь окно «Найти дубли» помечает карточку, которая ОСТАНЕТСЯ
(«· останется»), и берёт ЕЁ имя как имя объединённого по умолчанию — клиент
видит исход до подтверждения и не теряет карточку случайно.

Бэкенд (survivor-метка в duplicate-groups + AutopodborCompetitorMerger::survivorId)
уже в 928561bd; здесь фронт: api-тип, окно, метка, тест. Фронт 11/11.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 13:32:36 +03:00
Дмитрий 928561bd12 fix(autopodbor): переименование конкурента тянет имена проектов + слияние не роняет карточку в предложения
Две починки в «Конкурентном поле» + превью выжившего в окне склейки:

1. Переименование конкурента (PATCH competitors/{id}) не обновляло имена
   уже созданных проектов — они носят имя-снимок конкурента. Теперь при
   смене имени проекты синхронизируются (syncNamesForCompetitor): меняется
   только отображаемое имя, signal_identifier поставщика не трогаем.

2. Слияние дублей не пересматривало ящик выжившего. Если выжившим по
   возрасту/деньгам оказывалось предложение, объединённая карточка уезжала
   в «Предложения», даже когда одна из склеиваемых была в «Поле». Теперь
   объединённая получает сильнейший ящик (поле > предложение > архив) —
   только повышаем, никогда не понижаем.

3. Окно «Почистить поле» показывает, какая карточка останется после склейки
   (survivor во duplicateGroups) — не затираем имя вслепую.

Тесты: весь блок автоподбора зелёный (426). Larastan в этой рабочей копии
падает без вывода на любом файле — среда, не код.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 13:29:16 +03:00
Дмитрий a28058779b fix(autopodbor): дубли по телефону застройщика — снят порог «людного» номера
Кейс «Образцово»: у застройщика (СМ.Сити) один номер отдела продаж легитимно
висит на всех его ЖК (277-99-01 на 9 проектах). Прежний порог dropCrowdedKeys
(>4 карточек → «рекламный», выкинуть) прятал это, и окно «Найти дубли» не
показывало проекты застройщика — systematically (6 таких номеров в данных).

Решение владельца 05.07: порог по ТЕЛЕФОНУ (p:) убрать — клиент подтверждает
склейку вручную («Это разные»), тихой ложной склейки нет; рекламные-подменыши
и так отсекаются на сборе. Порог по АДРЕСУ (a:, бизнес-центр) оставлен.
Проверено на AutoMoney: его номер у 3 карточек — все реально Автодом24, группа
верная, монстр-группы снятие порога не даёт.

Тесты переписаны со старого поведения на новое (unit + feature), 421/421.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 11:47:40 +03:00
Дмитрий f06b336363 feat(autopodbor): кросс-ящик дублей поле↔предложения на экране поля (доведён до рабочего)
Кнопка «Найти и объединить дубли» на экране поля теперь ловит и предложения,
дублирующие карточки поля (scope=cross): счётчик учитывает их, окно помечает
«· предложение», объединение сливает предложение в карточку поля (выживает поле,
merger не трогали). Бэкенд оставляет только группы с ≥1 карточкой поля — пары
чисто-предложений на экране поля не мусорят.

Файл-статус сессии — docs/superpowers/findings/2026-07-05-avtopodbor-session-status.md.

Feature 154/154, фронт 32/32, Pint чистый, билд собран.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 11:19:38 +03:00
Дмитрий e8c53f80e7 feat(autopodbor): гейт «сайт-якорь» для разворота + кросс-ящик дублей + счётчик на кнопке
1. Разворот по телефонам запускается ТОЛЬКО при наличии своего сайта (seedDomain).
   Без сайта имя размыто (напр. «Южный берег» → автосервисы/гостиницы), сеедные
   телефоны грязные, а разворот их лишь умножает. Доказано вживую: ДСК/СМ-сити
   (сайт есть) — чисто; «Южный берег» (нет) — 70% мусора.

2. Поиск дублей научился кросс-ящик поле↔предложения (scope=cross): предложение-
   дубль карточки поля теперь всплывает (merge кросс-ящик уже умеет). В выдаче
   виден box каждой фирмы. Без scope — прежнее поведение (один ящик).

3. На кнопке «Найти и объединить дубли» показывается число найденных групп-дублей
   (считается на загрузке, обновляется после слияния/«это разные»).

Юнит 267/267, feature 153/153, фронт 15/15.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 11:01:34 +03:00
Дмитрий 9fce28fda8 feat(autopodbor): Яндекс-разворот по телефонам на шаге 2 (рядом с 2ГИС)
Для застройщиков, которые сидят только в Яндексе. По каждому номеру ищем в
Яндекс.Картах, но список рыхлый — поэтому КАЖДУЮ карточку открываем и оставляем
только те, где искомый номер реально есть. Это отсекает «Похожие места рядом»,
рекламу и рыхлые совпадения по бренду. Оба справочника объединяются
(CompositePhoneReverse), дубли по домену схлопываются.

Переиспользована готовая механика Яндекса: render-yandex-list.cjs (список) +
DirectoryParser::parseYandexCard (карточка). Браузерные адаптеры за интерфейсами
(YandexPhoneSearch/YandexCardReader) — логика TDD-ится на фейках; порог общей
линии считается по подтверждённым карточкам.

За отдельным тумблером AUTOPODBOR_PHONE_REVERSE_YANDEX (по умолчанию ВЫКЛ,
требует phone_reverse). Юнит 267/267, feature 150/150. План и находки —
docs/superpowers/{plans,findings}/2026-07-05-*.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 09:30:27 +03:00
Дмитрий 0e47b24dfc feat(autopodbor): заметная ошибка в окне создания и кнопка «Проверить дубли»
Ошибка создания проекта показывается заметно прямо в окне (красный блок), а не тихим
тостом внизу. При дубле источника — подсказка «проверьте на дубли» и кнопка, которая
перекидывает в «Конкурентное поле» и сразу открывает окно объединения дублей.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 09:27:39 +03:00
Дмитрий bcb327aa13 fix(autopodbor): проект принадлежит ровно одному источнику и понятная причина отказа
Инвариант «один проект = один источник»: при переносе проекта на новый источник
снимаем привязку со всех прочих источников — проект больше не может висеть в двух
конкурентах сразу (жёсткий баг с дублями). Плюс разбор ошибки в автоподборе
показывает конкретную причину бэкенда вместо общей фразы «не удалось».

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 09:02:40 +03:00
Дмитрий 36c3a7fe7f feat(autopodbor): разворот по телефонам на шаге 2 (сайты проектов застройщика)
По личным телефонам фирмы обратным поиском в 2ГИС вскрываем связанные карточки
холдинга (проекты застройщика) — забираем их сайты и телефоны, цепочкой «до талого».
Общий номер (у >4 фирм) пропускаем; visited-set + потолок карточек; уже известную
главную карточку не дублируем. Защита от AutoMoney: реклама отсечена парсером,
общий номер обрублен до разворота, находки не клеятся молча.

За тумблером AUTOPODBOR_PHONE_REVERSE (по умолчанию ВЫКЛ). Юнит 259/259, feature
146/146. Решение и план — в docs/superpowers/{findings,plans}/2026-07-05-*.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 07:55:03 +03:00
Дмитрий f1352083a1 docs(autopodbor): решение по сайтам проектов застройщика (ДСК) — что упустили и план
Застройщик = холдинг из проектов-ЖК, каждый со своим сайтом; шаг 2 берёт только
главную карточку. Решение: проекты = элементы конкурента, авто-открытие из 2ГИС/
сайта (нужен го владельца), не переобрабатывать уже собранную главную. Эталон —
ДСК (tenant 38, competitor 720). Открытые вопросы О-1..О-4.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 06:49:16 +03:00
Дмитрий 6a0635e60a fix(autopodbor): индикатор сбора подхватывается при возврате на карточку
Клиент ушёл со страницы во время сбора и вернулся — индикатор пропадал (жил только
на опросе в памяти браузера), казалось, что процесс исчез.

- competitor-эндпоинт отдаёт active_run (идущий по конкуренту сбор) — тест
- loadCompetitor подхватывает active_run в currentRun (не затирая итог завершённого)
- onMounted возобновляет опрос, если сбор ещё идёт → индикатор оживает, дожидаемся итога
- тесты: active_run (бэк), loadCompetitor подхват/сохранение, подхват опроса на экране

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 06:40:10 +03:00
Дмитрий 001ccbd9a7 fix(autopodbor): спиннер крутится при «уменьшить движение» (не выглядит зависшим)
У клиента включено «уменьшить движение» (Windows/браузер) — глобальное правило
motion.css гасило ВСЕ анимации (animation-iteration-count: 1 !important), поэтому
любой кружок замирал после одного оборота и казался зависшим.

Спиннеры-загрузчики (.ld-spin, .ld-collecting__spin) — законное исключение (WCAG
допускает индикатор загрузки): возвращаем медленное непрерывное вращение. Чинит
все кружки в приложении разом, не только автоподбор.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 06:28:08 +03:00
Дмитрий 2da6273784 fix(autopodbor): живой индикатор сбора на экране (кружок крутится, виден без окна)
Клиент жаловался: кружок «завис» и прогресс не видно, когда окно сбора закрыл.

- CollectingIndicator: собственный гарантированно крутящийся кружок (старый ld-spin
  из @import в scoped не анимировался — известный баг Vue) + текст очередь/этап.
- Индикатор ставится прямо на экран (конкурент и «поле») — виден, даже если окно закрыли:
  «вы в очереди №N» / «этап N из M» / «идёт сбор…».
- В окнах сбора заменил статичный кружок на этот индикатор.
- 4 теста компонента + тест экрана.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 06:22:48 +03:00
Дмитрий 26bebf4b7e feat(autopodbor): при слиянии конкурентов проекты переименовываются в имя выжившего
Имя проекта следует за конкурентом: после склейки дублей все проекты объединённого
получают имя выжившего конкурента, при совпадении различаем источником, а не цифрой.
Проекты не удаляются и не рвутся — меняется только имя.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 06:10:18 +03:00
Дмитрий 505b8ed059 feat(autopodbor): повторный сбор источников — фронт
Кнопка «🔄 Собрать источники ещё раз» вместо мёртвой «✓ Источники собраны».
Окно предупреждает, что повтор платный (даже если нового нет). Честный итог
после сбора (N новых / M ранее удалённых). Блок «ранее удалённые — вернуть?»
с кнопкой «Вернуть» (box archived→proposal).

- RunDto.result + collectResultMessage (чистый хелпер) + тесты
- store.restoreSource + тест
- компонент RefoundDeletedSources + тест
- FieldCompetitorScreen: кнопка-повтор, честный итог, блок «вернуть», текст окна

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 06:08:53 +03:00
Дмитрий 892ca06093 feat(autopodbor): повторный сбор источников — бэкенд
Клиент может собрать источники по конкуренту ещё раз. Новые → в предложения,
ранее удалённые (найдены снова) → помечаются для возврата, уже известные не
задваиваются и не трогаются.

- удаление источника стало мягким (box=archived) — помним, чтобы показать «ранее удалён»
- снят жёсткий стоп «уже изучали» в startStudy (повтор разрешён; от нахлёста — assertNoInFlight)
- колонка result (jsonb) на прогоне + cast + RunResource
- джоба изучения классифицирует источники и пишет итог {new_sources, refound_deleted, ids}
- тесты: мягкое удаление, повтор, классификация

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 06:08:12 +03:00
Дмитрий ec907d27fa feat(autopodbor): имя проекта без бессмысленной цифры и переименование при переносе
Имя проекта = имя конкурента; при совпадении различаем источником сайт/номер,
а не хвостом «2». Один проект у конкурента — просто «Сибиряк», несколько —
«Сибиряк · сибиряк.рф». При переносе источника к другому конкуренту проект
переименовывается на нового конкурента.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 05:28:24 +03:00
Дмитрий db3cb7473c feat(autopodbor): гейт реквизитов при создании проекта и защита от дублей источника
#1 requisites_required — показываем короткую форму реквизитов прямо в экране
Конкурентного поля и повторяем создание проекта после сохранения.

#4 дубль источника — при добавлении проверяем, нет ли такого же источника у другого
конкурента или уже созданного по нему проекта. Отдаём клиенту выбор: убрать дубль или
перенести проект к новому источнику по идентификатору. Проект не пересоздаётся.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 05:13:28 +03:00
Дмитрий 3b32efb871 fix(autopodbor): пустые сайт/карточка элемента не ломают сохранение конкурента
Форма шлёт пустую строку в незаполненной строке сайта/карточки, middleware
ConvertEmptyStringsToNull делает из неё null — валидация elements.*.sites.*/
cards.* теперь допускает nullable (иначе 422). Ручной источник заводится сразу
в «работу» (box=field). Найдено незакоммиченным в воркстри (доделка #2 «элементы»),
тесты зелёные — коммичу отдельно, чтобы не потерять и не смешать с прогрессом.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 04:31:38 +03:00
Дмитрий ffc5da7543 feat(autopodbor): показ очереди и этапа клиенту во время сбора (фронт)
Компонент RunCollectStatus: «вы в очереди №N» (пока прогон ждёт) или «этап N
из M: подпись» (пока идёт). Встроен в оба окна сбора (конкуренты/источники) и
экран загрузки ручного изучения. RunDto получил queue_position и progress.
Никаких фейковых процентов — только реальные этапы движка. 4 теста Vitest.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 04:31:19 +03:00
Дмитрий 428b7b0f01 feat(autopodbor): прогресс прогона — очередь и этапы (бэкенд)
Клиент во время сбора видит место в общей очереди (пока ждёт) и текущий
этап (пока идёт). Очередь — длина общей Redis-очереди (честное ожидание,
без RLS, одинаково dev/прод). Этапы пишет сам движок через RunProgressChannel:
поиск (анализ→справочники→федералы→сбор→отбор), изучение — по каждому элементу.

- миграция progress (jsonb) на autopodbor_runs + cast
- RunResource отдаёт queue_position (AutopodborQueue) и progress
- RunProgressChannel (синглтон), джобы привязывают его к своему прогону
- SearchStages + инструментовка LiveFindCompetitors и RealCompetitorAgent
- 16 тестов (Feature+Unit), все зелёные

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 04:31:01 +03:00
Дмитрий f757d8adaf docs(autopodbor): handoff сессии 04-05.07 - что сделано по #2, что открыто (#1 прогресс, баг городов, похожесть)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 03:42:41 +03:00
Дмитрий b78babe7b4 feat(autopodbor): при слиянии выбор имени объединённого из найденных
Диалог дублей: селект имени среди выбранных к слиянию, по умолчанию первое.
Merger и ручка принимают опциональное имя. Обе экрана.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 19:07:59 +03:00
Дмитрий bd425308e6 feat(autopodbor): карточка конкурента показывает состав холдинга (элементы)
Если конкурент из 2+ элементов - блок со списком: имя, сайты, число карточек.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 18:45:46 +03:00
Дмитрий 5d19114c24 feat(autopodbor): при слиянии дублей выбор подмножества - галочки, слить 2 из 3 и т.п.
В группе из 3+ клиент отмечает, кого объединить. По умолчанию выбраны все
(группа из 2 - как раньше). Слить можно любое подмножество >=2. На обоих экранах.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 18:44:02 +03:00
Дмитрий 50d6da5931 feat(autopodbor): шаг 2 изучает каждый элемент конкурента отдельно
Глубокое изучение строит отпечаток на КАЖДЫЙ элемент холдинга - имя элемента плюс
его первый сайт - и сводит телефоны со всех. Без элементов - как раньше.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 18:39:37 +03:00
Дмитрий 2130cd74e9 feat(autopodbor): формы создания/правки конкурента через элементы - правка не теряет карточки
Бэк: хелпер CompetitorElements нормализует элементы и выводит легаси site_url/directory_urls
из ВСЕХ карточек. Ручки manual/update принимают elements.
Фронт: компонент CompetitorElementsEditor встроен в формы создания и правки на экранах
Поле и Предложения. Прежний баг - пересбор directory_urls из двух полей - закрыт.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 18:32:16 +03:00
Дмитрий 47bc508246 docs(autopodbor): находки похожесть-погода и конкурент-из-элементов + план Часть 1
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 18:14:54 +03:00
Дмитрий d7c63a2962 feat(autopodbor): конкурент из элементов - слияние без потерь
Конкурент хранит список элементов {name,sites,cards} - подкомпании/ЖК холдинга.
Слияние складывает элементы всех объединяемых, ничего не роняет.
Миграция бэкфилла: один элемент из текущих site_url + directory_urls.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 18:14:39 +03:00
Дмитрий d2f3a171a9 fix(autopodbor): источник исчезает сразу при удалении + формы не закрываются при выделении текста
- стор removeSource чистит store.sources - карточка конкурента обновляется без reload
- 8 оверлеев на экранах Поле/Предложения переведены на useOverlayDismiss

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 18:14:18 +03:00
Дмитрий 66a0f2bb67 docs(автоподбор): снимок 04.07 — движок шага 2 на ветке + приёмка 385 + UI + что осталось
Полный статус: движок перенесён (134 теста, ревью «Ready»), 385 подтверждён 1:1 с
ЭТАЛОНом живьём, корневой баг «нашлось мало» = завис queue:work (починен перезапуском),
UI (метки/регион-тайпахед/групповое создание) закоммичен ac3d6975. Осталось: приёмка
412/414/416/420, открытый вопрос дефолта «Вся РФ», перенос на прод по слову.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 11:13:25 +03:00
Дмитрий ac3d6975c1 feat(автоподбор/UI): понятные метки источников + впечатываемый регион + групповое создание
FieldCompetitorScreen:
1) метки ✓ настоящий номер / 🎭 рекламный подменный + плейн-язык «где нашли»
   + легенда «как читать» (данные в БД и сверка с ЭТАЛОНом НЕ тронуты — перевод только в показе);
2) регион «впечатывается» — свой тайп-ахед в стиле экрана (без Vuetify, чтобы не ломать тесты)
   в окнах «Создать проект» и «Настройки проекта»; чипы для мультивыбора, подпись округа;
3) галка «Вся РФ (все регионы)» даёт баннер-объявление;
4) групповое создание проектов из всех выбранных источников без проекта (source_ids пачкой),
   заголовок/текст под «несколько». +тест на групповое создание. Фронт-спеки 24/24 зелёные.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 11:12:16 +03:00
Дмитрий 82e30d0548 test(автоподбор): end-to-end хранение строк глубокого сбора — близнецы = две записи в БД 2026-07-03 23:59:00 +03:00
Дмитрий 34a43c3969 style(автоподбор): Pint по пакету Study + провайдеру 2026-07-03 23:46:28 +03:00
Дмитрий 8a7b2ec12d feat(автоподбор): DI-сборка DeepStudyCollector за тумблером 2026-07-03 23:43:45 +03:00
Дмитрий 8fafbc0ba8 feat(автоподбор): развилка studyCompetitor по тумблеру deep_study (интерфейс SourceCollector) 2026-07-03 23:40:44 +03:00
Дмитрий 1cd215c23f feat(автоподбор): DeepStudyCollector — движок глобального сбора (близнецы порознь) 2026-07-03 23:32:23 +03:00
Дмитрий 9ff837bdb9 feat(автоподбор): SiteOpener — вскрытие сайта фирмы
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 23:23:53 +03:00
Дмитрий 1f85403fca test(автоподбор): FootprintSearch — гарантия «пустой ключ = 0 запросов» (assertNothingSent) 2026-07-03 23:22:50 +03:00
Дмитрий 3ca6af7a65 feat(автоподбор): FootprintSearch — EXA-поиск следа конкурента 2026-07-03 23:19:59 +03:00
Дмитрий 103448a00b feat(автоподбор): AnchorGate — фильтр «точно она» для сайта и карточки 2026-07-03 23:17:02 +03:00
Дмитрий 677582bb0a test(автоподбор): точное имя теста отпечатка (path+utm, не схема) 2026-07-03 23:04:48 +03:00
Дмитрий 5826728590 feat(автоподбор): отпечаток конкурента + запросы EXA 2026-07-03 23:01:37 +03:00
Дмитрий be43d91424 feat(автоподбор): PlatformClassifier — площадки по корзинам 2026-07-03 22:58:24 +03:00