Commit Graph

431 Commits

Author SHA1 Message Date
Дмитрий 56f06ac2c3 fix(портал-мобилка): деталь сделки на телефоне — на весь экран
Панель деталей сделки была фикс. ширины (inline 400px в «Сделках», drawer 480px
в Канбане) — на экране 390 она была шире экрана: в «Сделках» давала горизонтальный
скролл страницы и крошила карточки списка, в Канбане левый край уезжал за экран.
На телефоне:
- «Сделки» — inline-панель стала полноэкранным оверлеем (position:fixed inset:0).
- Канбан — ширина drawer = ширине экрана (useDisplay).
Десктоп/планшет — прежний master-detail 400px / drawer 480px, без изменений.
Тесты 103/103 зелёные.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 20:56:42 +03:00
Дмитрий cdd0237108 fix(портал-мобилка): диалоги на телефоне — на весь экран (fullscreen)
Узкие центрированные модалки на телефоне резали содержимое (ряды кнопок,
вкладки, дни недели, сетку регионов — контент вылезал за края, текст обрезался
слева и справа). Диалоги с богатым содержимым теперь на телефоне открываются
на весь экран (:fullscreen по useLayoutTier + scrollable):
- Проект (создание/редактирование) — NewProjectDialog
- Новая сделка — NewDealDialog
- Пополнение баланса — TopupDialog
- Дни оптом — DaysBulkDialog (те же кнопки дней)
- Регионы оптом — RegionsBulkDialog
- Импорт: сопоставление статусов — UnknownStatusesDialog
Десктоп/планшет — прежний центрированный модал, без изменений.
Тесты диалогов 59/59 (+2 skip) зелёные.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 20:46:47 +03:00
Дмитрий 5ec802212a fix(портал-мобилка): «Предложения» — кнопки «На актуализацию» не вылазят за карточку
В карточках «На актуализацию» три кнопки (Добавить/Заменить/Отказаться)
были шире контента и заезжали за правый край карточки (на ~18px, «Отказаться»
упиралась в бортик). На телефоне (media <600px) кнопки теперь во всю ширину
карточки поровну (flex:1) — держатся внутри паддинга. Десктоп без изменений.
Проверено сканом всех 39 карточек: заездов за паддинг больше нет.
Тесты 71/71 зелёные.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 20:24:31 +03:00
Дмитрий 432964cc28 fix(портал-мобилка): «Поле» — плашка предложений и строка выбора на телефоне
На телефоне (media <600px):
- Плашка «Лидерра подготовила N предложений… Разобрать предложения →»
  раскладывается в столбик: текст переставал крошиться по слову, а ссылка
  «Разобрать предложения →» больше не вылезает за край (была nowrap).
- Строка «Выбрать всех/все предложения» — flex-wrap: подсказка падает на
  новую строку во всю ширину, не жмётся в узкую колонку.
Правки в общем field-shared.css — покрывают и «В поле», и «Предложения».
Тесты «Поля» 71/71 зелёные. Десктоп/планшет без изменений.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 20:16:48 +03:00
Дмитрий 23c4179aff fix(портал-мобилка): небольшой зазор у «Поиска» в шапке на телефоне
При длинном заголовке («Конкурентное поле») кнопка «Поиск» стояла вплотную
к тексту (зазор 0). Добавлен margin-left 10px на телефоне (media <600px) —
теперь есть воздух. Десктоп/планшет без изменений.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 20:09:18 +03:00
Дмитрий f9e589497e fix(биллинг): метка для списаний автоподбора в истории транзакций
Списания type=autopodbor_charge шли без описания и показывались как «—»
и в таблице (десктоп), и в карточках (телефон). Добавлена метка
«Списание за автоподбор» в общий словарь операций TransactionsTable.

Тесты транзакций 9/9 зелёные.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 19:58:48 +03:00
Дмитрий fdcb7111cc fix(портал-мобилка): Настройки/Реквизиты — «Тип лица» в столбик на телефоне
Сегмент-контрол «Тип лица» (Физическое лицо/ИП/Юридическое лицо) на телефоне
не влезал в строку и наезжал; теперь раскладывается в столбик во всю ширину
(media <600px, скруглены верх/низ группы). Остальные поля реквизитов уже
адаптивны. Десктоп/планшет — горизонтальный переключатель, без изменений.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 19:54:11 +03:00
Дмитрий 7c303a748d fix(портал-мобилка): Проекты — фильтры в столбик во всю ширину на телефоне
На телефоне фильтры (Тип/Статус/Регион/День/Сортировка/Поиск) перестали
обрезаться («Р…», «Д…») — раскладываются в столбик во всю ширину
(перебит inline max-width через media <600px). Десктоп/планшет без изменений;
карточки проектов уже адаптивны.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 19:50:11 +03:00
Дмитрий 6b8f8da019 fix(портал-мобилка): Дашборд — переключатель периода во всю ширину на телефоне
На телефоне v-btn-toggle (Сегодня/7 дней/30 дней/Период) растянут на всю
ширину с равными кнопками — убрана внутренняя горизонтальная прокрутка.
Только media-запрос <600px; десктоп/планшет без изменений.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 19:46:55 +03:00
Дмитрий f0f98ad152 feat(портал-мобилка): планшет — узкая колонка-иконки (rail)
На планшете (600–1279px) сайдбар сжимается в rail: только иконки пунктов,
подписи/поиск/бренд-текст скрыты, контент шире. Иконки берутся из mdi,
уже заложенных в данные пунктов; на десктопе иконки скрыты — текстовый
сайдбар остаётся прежним. Отступы топбара и контента разведены по ярусу
(десктоп 232/240px, планшет 64/72px, телефон 0). Гамбургер топбара теперь
показывается только на телефоне (d-sm-none) — на планшете/десктопе он не нужен.

Тесты каркаса 24/24 зелёные. Проверено на 820 и 1440px; десктоп не изменился.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 19:42:50 +03:00
Дмитрий 9808bd00af feat(портал-мобилка): «Канбан» на телефоне — одна колонка + переключатель этапов
На телефоне 5 колонок больше не листаются вбок: сверху горизонтальный
переключатель этапов (чипсы со счётчиками), ниже — выбранная колонка на всю
ширину. Смена этапа сделки на телефоне — тапом по карточке через drawer
(drag вбок на узком экране неудобен). Планшет/десктоп — прежняя доска со всеми
колонками и перетаскиванием, без изменений.

Тесты Канбана 23/23 зелёные. Проверено на 390 и 1440px (+ переключение этапов).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 19:35:58 +03:00
Дмитрий c400dcbc4b feat(портал-мобилка): «Биллинг» — карточки транзакций на телефоне
История транзакций обёрнута в ResponsiveTable: на десктопе/планшете —
v-data-table-server как прежде, на телефоне — карточки (операция, сумма
цветом, дата, #ID) + компактный пейджер по 20. Серверная пагинация сохранена.

Тесты биллинга 40/40 зелёные. Проверено на 390 и 1440px.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 19:17:17 +03:00
Дмитрий 73a5096f6f feat(портал-мобилка): ResponsiveTable + карточки «Сделок» на телефоне
Обёртка ResponsiveTable (таблица на десктопе/планшете, карточки на телефоне
по ярусу useLayoutTier). Применена к реестру лидов «Сделки»: на телефоне —
карточки лида (чекбокс выбора, телефон, статус-плашка, источник·город,
комментарий, дата), тап открывает карточку сделки; на десктопе прежняя
v-data-table без изменений.

Тесты: ResponsiveTable.spec (2), «Сделки» 58/58 зелёные. Проверено на 390 и 1440px.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 19:17:01 +03:00
Дмитрий 1140fd0c09 feat(портал-мобилка): каркас — сайдбар прячется на телефоне, снизу панель-вкладки и «Ещё»
AppLayout: ярус-отступ (десктоп/планшет 232px, телефон 0 + низ под панель), рендер
AppBottomNav/AppMoreDrawer на телефоне, гамбургер открывает «Ещё». AppSidebar:
проп tier + скрытие на телефоне. Десктоп/планшет без изменений.
2026-07-07 17:59:04 +03:00
Дмитрий bc77c84e4c feat(портал-мобилка): AppMoreDrawer — выезжающее «Ещё» на телефоне
Разделы вне 5 нижних вкладок: Дашборд, Отчёты, Настройки (реквизиты), Импорт, Помощь.
Ни один экран не выкидываем.
2026-07-07 17:54:00 +03:00
Дмитрий 5e39c50fa0 feat(портал-мобилка): AppBottomNav — нижнее меню-вкладки на телефоне 2026-07-07 17:50:36 +03:00
Дмитрий dc8a3c5f4f feat(портал-мобилка): composable useLayoutTier — ярус телефон/планшет/десктоп 2026-07-07 17:45:37 +03:00
Дмитрий b0bd110f8f fix(projects): регионы в 4 выпадашках раздела «Проекты» — сортировка по сути названия
Те же выпадашки региона (новый проект, фильтр списка, массовое
add/remove регионов, карточка проекта) переведены на REGIONS_ALPHA —
единый порядок с автоподбором, республики по своему имени, а не кучей.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 16:30:42 +03:00
Дмитрий 33acb436e9 fix(autopodbor): регионы в выпадашках — сортировка по сути названия
Регионы выводились в конституционном порядке (республики → края →
области), из-за чего список выглядел кашей (Дагестан → Донецкая
Народная → Ингушетия → Кабардино-Балкарская). Добавлен REGIONS_ALPHA:
сортировка по «настоящему» имени, слова-типы (Республика/область/край/
автономный округ) отбрасываются — Татарстан на «Т», Адыгея на «А».
Подставлен во все 7 выпадашек автоподбора. Тест regionsAlpha.spec.ts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 16:27:44 +03:00
Дмитрий fa7b2000e8 chore(autopodbor): кнопка «Отказаться» (было «Удалить») + автоподбор в CSV списаний + canon-sync schema.sql v8.63
- Кнопка на актуализации переименована «Удалить»→«Отказаться» (чтобы клиент не путал с удалением конкурента).
- CSV-выгрузка «Списаний» теперь включает автоподбор-строки (отдельным блоком, «Автоподбор конкурентов»);
  тест на export. charges 11/11.
- schema.sql canon-sync v8.63: +колонка dismissed_actualize_keys у autopodbor_competitors + CHANGELOG
  (заодно в цепочку шапки вписана пропущенная v8.62 CHECK autopodbor_charge).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 16:03:43 +03:00
Дмитрий a3fd8a6e9a feat(autopodbor): «Удалить» на актуализации — мягкое отклонение находки
Кнопка «Удалить» на карточках «На актуализацию» рядом с Добавить/Заменить.
Отклоняет ТОЛЬКО находку (новый сайт/адрес): фирма поля остаётся, находка → архив,
её новые ключи запоминаются у фирмы поля (новая колонка dismissed_actualize_keys jsonb).
Классификатор вычитает отклонённые ключи → та же находка больше не всплывает; реально
другой новый сайт даст новый ключ → покажется. Не глушим по имени, конкурента не убираем.

Бэк: миграция + модель-каст + ProposalClassifier (вычитание) + эндпоинт dismissActualize
+ роут. Фронт: api + store + кнопка «Удалить». Тесты: классификатор 8/8, ветка 185/185,
фронт 30/30. Canon-sync schema.sql (v8.62) — follow-up (миграция idempotent-guarded).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 15:50:59 +03:00
Дмитрий aa24273355 fix(billing+autopodbor): автоподбор-списания в табе «Списания» + фикс вёрстки плашек «Предложений»
- «Списания» (TenantChargesController.index) теперь union lead_charges + autopodbor_charge
  (balance_transactions) — клиент видит списания за прогоны, не только в «Истории транзакций».
  Автоподбор-строки: kind=autopodbor, метка вместо сделки, «—» для tier. Фильтр charge_source
  автоподбор не подмешивает. 2 теста, всего charges 10/10.
- Плашки «Предложений» разъезжались за экран на длинных URL (utm/рекламные хвосты): grid-элементы
  min-width:auto не сжимались. Фикс: .ld-grid>* min-width:0 + перенос длинных ссылок.
- Фронт 16/16.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 14:21:30 +03:00
Дмитрий 2d145bc07d test(autopodbor): актуализировать 4 устаревших фронт-теста создания проектов
Групповое и одиночное создание теперь ТРЕБУЮТ регион (vsyaRf=false по умолчанию;
«Вся РФ» — явная галочка, дефолта больше нет — подтверждено владельцем). Тесты
были под старый дефолт «Вся РФ» → doCreate бэйлился на гейте региона. Добавлен
явный выбор «Вся РФ» перед doCreate. Плюс requisites_required теперь открывает
форму реквизитов (reqGate), а не тост — тест переведён на новое поведение,
reqGate добавлен в defineExpose для наблюдаемости. Спек 6/6 зелёный.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 15:51:45 +03:00
Дмитрий 0f30edb2b6 Merge remote-tracking branch 'gitea/main' into worktree-avtopodbor
# Conflicts:
#	app/config/services.php
#	app/tests/Pest.php
2026-07-06 14:50:58 +03:00
Дмитрий 7dc84256b9 feat(autopodbor): удаление предложения показывает пул связанных строк
Клик «Удалить» у предложения открывает окно со всеми предложениями,
найденными в том же месте (совпал url карточки/сайта в «где нашли»), с
галочками. По умолчанию отмечена только нажатая строка; клиент выбирает,
какие связанные строки удалить. «В работе» — прежнее окно. Массовое
удаление предложений — подтверждение со списком выбранных.

Только показ и порядок «сначала выбери, потом удали»; БД/бэкенд не тронуты.
Тесты: пул по url, строгое совпадение, дефолт-галочка, удаление отмеченных.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 10:54:50 +03:00
Дмитрий dda18d7cd6 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
Дмитрий 2aedb54dc5 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
Дмитрий f7bd3e39af fix(autopodbor): окно слияния показывает выживающую карточку и её имя по умолчанию
Баг «САПС/Метрополис»: клиент переименовал свежую карточку и слил — а выжила
ДРУГАЯ (с проектами/в поле), имя переименованной затёрлось вслепую, карточка
пропала. Теперь окно «Найти дубли» помечает карточку, которая ОСТАНЕТСЯ
(«· останется»), и берёт ЕЁ имя как имя объединённого по умолчанию — клиент
видит исход до подтверждения и не теряет карточку случайно.

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

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 13:32:36 +03:00
Дмитрий 1258b9bbed 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
Дмитрий 70ca25762a 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
Дмитрий 064c4c72c8 feat(autopodbor): заметная ошибка в окне создания и кнопка «Проверить дубли»
Ошибка создания проекта показывается заметно прямо в окне (красный блок), а не тихим
тостом внизу. При дубле источника — подсказка «проверьте на дубли» и кнопка, которая
перекидывает в «Конкурентное поле» и сразу открывает окно объединения дублей.

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

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 09:02:40 +03:00
Дмитрий 8fef74f25e 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
Дмитрий 0333dd6902 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
Дмитрий cee985bf36 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
Дмитрий 002e2c91c4 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
Дмитрий ac27a59baa 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
Дмитрий e46d1354fd 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
Дмитрий 1cdaf9cbbb feat(autopodbor): при слиянии выбор имени объединённого из найденных
Диалог дублей: селект имени среди выбранных к слиянию, по умолчанию первое.
Merger и ручка принимают опциональное имя. Обе экрана.

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

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 18:45:46 +03:00
Дмитрий b5e5e8ae83 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
Дмитрий 1435e168c4 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
Дмитрий 8c29910d6a 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
Дмитрий 01e8733801 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
Дмитрий f295351504 feat(автоподбор): Конкурентное поле — финальный проход склейки, вскрыть всё, группы дублей, телефоны, отсев рекламных номеров 2ГИС
Шаг 1 «Конкурентное поле» — чекпоинт:
- Финальный проход «Найти и объединить дубли» на поле и предложениях; клиент решает по каждой группе, ничего не склеиваем молча.
- Тихая склейка только по сайту и коду справочника; телефон и людный номер у более чем 4 фирм — на решение клиента.
- Колонка phones jsonb; телефон-дубли видны уже на «Предложениях».
- Sonar даёт только имя и тип, сайт всегда через EXA; вскрываем все карточки без гейта «есть сайт».
- Яндекс-карточки через локальный Playwright параллельно; рубрика из заголовка идёт в описание.
- Фикс рекламных номеров: 2ГИС-парсер разбирает телефоны пообъектно и выкидывает рекламные кнопки с platforms/caption чужих фирм.

Тесты: автоподбор 224/224 unit, 105/105 feature; фронт-спеки зелёные. Времянки app/scripts/diag-*/probe-* в гит не входят.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 17:34:03 +03:00
Дмитрий b2699f0d84 feat(y360): баланс почты Яндекс 360 — ручной ввод + кнопка Пополнить
email — денежный сервис; сумма вписывается в админке «Система» (Yandex360BalanceStore),
светофор по порогам, кнопка «Открыть оплату»/«Пополнить» → admin.yandex.ru/products.
Робот-скрейпер отклонён (SPA Яндекса враждебен ботам + автопополнение защищает баланс).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 13:34:13 +03:00
Дмитрий 8cc9ea122b deploy(prod): launch-gate ЯДРО на liderra.ru — баланс блокирует запуск, не создание
Ядро фичи для обычных проектов (без автоподбора): единый LaunchBalanceGate под
lockForUpdate(Tenant), ProjectService::create($launch)+setActive, bulk resume
«сколько влезло», ProjectController store/update/toggle, config/billing.php,
ProjectResource.preflight_blocked_at + фронт экранов проектов (сообщения в рублях,
метка «не запущен», группы). Схема БД не менялась (preflight_blocked_at уже был).
Cherry-pick ТОЛЬКО ядра поверх main 73b56042; автоподбор НЕ выкатывается.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 13:09:38 +03:00
Дмитрий d15a7cfd93 feat(биллинг-фронт): баланс на запуске — сообщения в рублях, метка «не запущен», группы
Фронт для правила «баланс блокирует запуск, а не создание»:
- ProjectLimitOverloadDialog переформулирован в «Проект не запущен — пополните
  ~X ₽ или уменьшите объём» (сумма в рублях topup_rub).
- NewProjectDialog: создание всегда успешно; при launch.deferred показывает
  сообщение (не блок). Update-лимита 409 → тот же диалог.
- Возобновление (toggle-active) ловит 409 balance_insufficient (стор не
  переключает is_active), показывает диалог; постоянная метка «Не запущен —
  не хватает баланса» на карточке/в панели по preflight_blocked_at/balance_blocked.
- BulkActionsBar: сводка «Запущено N, отложено M — не хватает баланса» на resume.
- Автоподбор: CreateScreen показывает сводку запуска (рубли); FieldCompetitor
  массовые pause/resume через общий POST /api/projects/bulk (наследует BULK_MAX,
  слепок-защиту, балансовый гейт).
- ProjectResource отдаёт preflight_blocked_at.

Новые/обновлённые фронт-тесты зелёные. Пред-существующий красный baseline
фронт-набора (ErrorView/Settings/Legal/… + ProjectsView v-show) не трогался.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 12:04:16 +03:00
Дмитрий 73b56042a9 feat(external): на плитке внешних сервисов — и баланс, и статус
Мини-плашка теперь показывает деньги (или —) И слово статуса (жив/выключено/ok)
рядом, как в детализации. Убрана мёртвая serviceValue.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 10:36:31 +03:00
Дмитрий 64785a9357 fix(external): Баланс = только деньги; живость — в колонку Статус
Баланс/статус различаем по типу сервиса (LIVENESS_ONLY_KEYS), не по null-балансу
(денежный Поставщик с сорванным автологином больше не показывается «выключено»).
Мини-плитка переименована «Балансы сервисов»→«Внешние сервисы».

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 10:26:06 +03:00