Commit Graph

2910 Commits

Author SHA1 Message Date
Дмитрий 9362cda148 feat(autopodbor): startStudyBatch + перевод одиночных сборов на распорядителя 2026-07-09 09:45:10 +03:00
Дмитрий e2663f90b1 feat(autopodbor): AutopodborStudyScheduler — одна дорожка + round-robin 2026-07-09 09:45:09 +03:00
Дмитрий 9d3df153a5 feat(autopodbor): AutopodborBudgetGate — деньги пакета с резервом проектов
Переиспользует BalancePreflightService.evaluate() для проверки, что после
списания за пакет ещё хватает баланса на дневной лимит активных проектов.
Бинарный поиск максимально доступного количества единиц пакета (maxAffordable)
и расчёт недостающей суммы (topupRub) при отказе.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 09:45:08 +03:00
Дмитрий d36f449d2a feat(autopodbor): миграция batch_id + индексы очереди шага 2 2026-07-09 09:45:08 +03:00
Дмитрий e70bb9eafe fix(supplier): пауза доходит до поставщика в batch — ночной джоб 18:00 гасит осиротевшие заказы
Боевой в batch-режиме: пауза проекта не доходила до поставщика — заказ висел активным
(галочка вкл, лимит>0), поставщик мог лить лиды и списывать за остановленный проект
(подтв. живой базой: omega, 57 заказов, 0 команд после паузы 08.07).

Поставщик фиксирует завтрашнюю заливку снимком в 21:00, поэтому гасить надо в 18:00-прогоне
ДО снимка (мгновенно бессмысленно — сегодня уже зафиксировано). Добавлен проход
deactivateOrphanedOrders в SyncSupplierProjectsJob: заказам источников, которых нет в
активных группах слепка за завтра, шлётся updateProject(status=paused) с ненулевым лимитом,
локально помечается inactive_since. online-режим не тронут (там пауза уже мгновенна).
Активность берётся из слепка (слепок-инвариант), не из live is_active.

Тесты (TDD RED->GREEN): batch pause + стык с delete-хвостом. 19/19 supplier+delete,
238/238 supplier+projects, pint чисто, PHPStan без новых замечаний.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 09:44:52 +03:00
Дмитрий 2248feafa8 feat(supplier): аварийный spike-детектор ручной очереди в incidents:watch-failures
Блок 6: если за окно (10 мин) в supplier_manual_sync_queue упала пачка
(>= threshold-manual-queue, дефолт 10) — вероятное падение кабинета поставщика.
Инцидент дедупится 60 мин, письмо шлётся каждый прогон на kdv1@bk.ru + ops@liderra.ru
(громко при реальной аварии, но одним сводным письмом). Флаг sendMail в createIncident.
phpstan-baseline: +4 TestCall::artisan() (5→9) от новых тестов.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
(cherry picked from commit 9f0f5cfc59)
2026-07-09 09:44:52 +03:00
Дмитрий 9a1666ad3a fix(supplier): FailoverProjectChannel не шлёт per-project CRITICAL письма
Убраны письма manual_required и failover_to_form (по проекту, без троттла) —
источник потопа ~116 писем на ops@ 07.07. Строка в ручной очереди остаётся
(запись видна в админке). Зависимость Mailer удалена из канала и DI-привязки.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
(cherry picked from commit 46607d702a)
2026-07-09 09:44:51 +03:00
Дмитрий 8052be899f chore(deploy): защищённый выкат сборки портала — не даёт затереть чужие фичи
Портал выкатывается полной заменой public/build; сборка из устаревшей ветки
молча сносила чужую работу (инцидент 08.07: Метрика снесла колонки «Сделок»).
deploy-build.sh перед подменой сверяет маркеры критичных фич (по активным
чанкам manifest.json, не по orphan-осколкам) — теряет живую фичу → ОТКАЗ.
Осознанный откат — FORCE=1, только проверка — DRY_RUN=1. Установлен на боевом.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 19:19:17 +03:00
Дмитрий dc64226ec3 fix(portal): карточки вместо таблицы на планшете-портрете (Сделки/Списания)
Широкая таблица (7 колонок) не влезала в узкую колонку планшета рядом с
rail-меню — правые колонки «Комментарий»/«Поставлен» обрезались на 600–1279px.
ResponsiveTable теперь показывает карточки на телефоне И планшете, таблицу —
только на десктопе (>=1280). Тесты табличного слоя зафиксированы на десктоп-ширину.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 18:57:07 +03:00
Дмитрий 987cd0ac58 fix(deals): колонка «Конкурент» показывает только бренд до первой запятой
Имя конкурента хранится как «Бренд, описание» — в колонке «Конкурент»
показываем часть до первой запятой, полное имя — в title при наведении.
Применено к десктопной таблице и мобильной карточке. +тест на обрезку.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 18:37:30 +03:00
Дмитрий 2bbe2a7612 feat(metrika): Метрика+Вебвизор в линию портала (чтобы выкаты не теряли)
Метрика была потеряна, т.к. клалась мимо конвейера: выкат = git archive HEAD ветки
+ пересборка, а Метрика жила отдельно → перезатёрлась. Кладём в feat/portal-mobile-adaptive
(линию, из которой режутся deploy/*-ветки) → любой будущий выкат несёт её сам.

Загрузчик metrika.ts (только кабинет layout=app), маскировка ПДн лидов
(ym-hide-content/ym-disable-keys) — десктоп-таблица + МОБИЛЬНЫЕ карточки (телефон+
комментарий+aria-label) + канбан + карточка сделки + диалог. Сборка проходит.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 17:00:37 +03:00
Дмитрий 77050dbefb fix(admin): клиентский диапазон ступеней в тарифной сетке + предпросмотр в редакторе
Cherry-pick a7a4e735 поверх боевой ветки feat/portal-mobile-adaptive для
выката ТОЛЬКО правки тарифов на прод. Логика денег не менялась.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 15:29:40 +03:00
Дмитрий 027071b40f feat(billing): приветственный подарок при регистрации 300 ₽ → 1000 ₽
START_BALANCE_RUB в RegistrationService: '300.00' → '1000.00' — новый тенант
получает 1000 ₽ на баланс при подтверждении почты. Обновлён докблок
RegistrationController и тест RegistrationTest (баланс 1000, 13 тестов зелёные).
Автоподборные 300 ₽ (цена «Собрать конкурентов») НЕ тронуты — это другая сумма.
Миграций нет (константа применяется при регистрации). В UI/лендинге сумма
подарка не отображается — фронт не менялся.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 09:35:22 +03:00
Дмитрий de46ae3314 fix(autopodbor): защита route.query в deep-link — чистый прогон тестов
Влитый из автоподбора deep-link «Сделки → Автоподбор» читал route.query
в onMounted без защиты. В приложении роутер всегда есть, но при монтировании
в юнит-тесте без роутера route === undefined → unhandled error (2 ошибки,
vitest exit 1). Добавил route?.query ?? {} — поведение в бою не меняется,
полный прогон снова зелёный (1184 , exit 0). Правка нужна для чистого
CI-гейта выката мобильной ветки.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 08:44:48 +03:00
Дмитрий 7799f13c79 feat(portal-mobile): новые колонки «Конкурент» и «Источник» в карточке сделки на телефоне
После вливания переделки сделок (колонки Конкурент/Источник со ссылками
в автоподбор) эти поля были только в таблице на компьютере — в карточке
телефона их не было. Добавил в мобильную карточку:
- «Конкурент» — имя конкурента зелёной ссылкой, ведёт в автоподбор
  (/autopodbor?competitor=ID), рядом город;
- «Источник» — отдельной строкой домен/идентификатор ссылкой в автоподбор
  (+ «· +N» если источников несколько) и канал (Сайт/Звонки/СМС).
Для сделок без источника автоподбора карточка выглядит как раньше
(проект · канал · город). @click.stop — ссылки не открывают деталь сделки.

Проверено на 390px: конкурент+источник видны, вбок не едет, переход
по ссылке в автоподбор работает; тесты DealsTable/mapper/ResponsiveTable
зелёные (23).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 08:26:29 +03:00
Дмитрий e47bd5b894 Merge branch 'worktree-avtopodbor' into feat/portal-mobile-adaptive 2026-07-08 08:16:51 +03:00
Дмитрий 7cf36153b4 docs(сделки): спека + план «Конкурент/Источник» в реестре сделок
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 07:56:45 +03:00
Дмитрий 98614604af feat(сделки): колонки «Конкурент» и «Источник» со ссылками в автоподбор
Раздел «Сделки»: колонка «Источник» разбита на две — «Конкурент» (ссылка на
экран конкурента) и «Источник» (ссылка на «Настройки проекта»). В модалку
настроек добавлена кнопка пуск/стоп (срабатывает не закрывая окно).

- бэк DealController::index: батч-резолв конкурента+источника по
  deal.project_id → autopodbor_sources.created_project_id → competitor (без N+1)
- контракт ApiDeal/MockDeal + маппер: competitor_*/source_* поля
- DealsTable: 1 колонка → 2 (Конкурент/Источник), router-link, fallback без автоподбора
- AutopodborView: deep-link ?competitor=&project= открывает экран конкурента + модалку
- FieldCompetitorScreen: кнопка ⏸/▶ в модалке настроек + авто-открытие по ссылке

Тесты: бэк DealIndexTest +4 (31 ), фронт +новые (66 ). Дизайн не менялся.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 07:56:30 +03:00
Дмитрий af2c4cbd15 fix(portal-mobile): 4 фикса вёрстки на телефоне (обход всех экранов)
Прошёл все экраны портала на 390px, нашёл и починил переполнения:

1. NewProjectDialog: кнопки дней недели (ПН…ВС) в окне редактирования
   проекта не влезали — СБ и ВС уезжали за правый край и были не видны.
   На телефоне делим ряд поровну между 7 кнопками.

2. DaysBulkDialog (массовое «Дни сбора»): та же беда с двумя рядами дней —
   тот же приём (flex 1/1/0 на телефоне).

3. ApiTab: пары кнопок «Копировать+Перегенерировать» и
   «Сохранить+Тестовый webhook» не помещались в строку — длинная вторая
   кнопка обрезалась. Разрешаем перенос на телефоне (flex-wrap).

4. NotificationsTab: таблица «События × каналы» была шире экрана —
   колонка Email уезжала, а названия событий крошились по одному слову.
   На телефоне ужимаем колонки-галочки и уменьшаем отступы, событию
   достаётся почти вся ширина; заголовки каналов мельче.

Все правки — только в phone-media (<600px), десктоп не затронут.
Проверено замерами DOM + скриншотами на 390px; тесты затронутых
компонентов зелёные.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 05:14:15 +03:00
Дмитрий 8c6ba9f07d fix(portal-mobile): кнопка «Создать проект» не жмётся к заголовку на телефоне
На узком экране заголовок «Проекты» и кнопка «Создать проект» стояли
вплотную в одну строку. На телефоне (<600px) кнопка теперь под заголовком
во всю ширину-строку, слева, с воздухом между ними; заголовок прижат влево
через align-self (перебивает utility .align-center с !important). Десктоп
не затронут — правка только в phone-media.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 04:27:15 +03:00
Дмитрий ae7a855325 fix(портал-мобилка): «Поле» карточки источников — кнопки не уезжают за край
Карточка источника (.ld-srccard) — flex-ряд: иконка | данные | блок кнопок
(.ld-srcctl, flex-shrink:0, max-width:320) справа. На телефоне кнопки
(Создать проект/Приостановить/Настройки проекта/В источники/Возобновить)
уезжали за край карточки. На телефоне (media <600px) карточка переносит
блок кнопок на строку ниже во всю ширину. Затрагивает обе под-вкладки
(Источники в работе + Предложения). Проверено сканом: 0 заездов. Тесты 71/71.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 04:04:11 +03:00
Дмитрий 65f4f1ecbe fix(портал-мобилка): Счета — строка счёта не уезжает за экран на телефоне
Строка счёта была гридом из 4 колонок (дата | номер | сумма | кнопки).
На телефоне при двух кнопках («Счёт» + «Акт» после оплаты) номер крошился,
а кнопки уезжали за край. На телефоне (media <600px) строка в 3 яруса:
номер+сумма, дата+статус, ниже кнопки «Счёт»/«Акт» во всю ширину. Проверено
на засеянном оплаченном счёте с актом. Десктоп (грид 4 колонки) без изменений.
Тесты 39/39 зелёные.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 03:51:14 +03:00
Дмитрий 27fd4f00b3 fix(портал-мобилка): Канбан — этапы переносятся на строки, все видны
Лента этапов на телефоне скроллилась вбок (overflow-x), из-за чего после
«Просмотрено» остальные этапы (В работе/Сделка/Не реализовано) уходили за
экран и были не видны, третий чип обрезался. Заменил горизонтальную прокрутку
на flex-wrap — все 5 чипсов-этапов переносятся на строки и видны сразу.
Тесты Канбана 23/23 зелёные.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 03:38:56 +03:00
Дмитрий fcbd52676c fix(портал-мобилка): Биллинг — плитки Кошелёк/Лиды/Запас не схлопываются на телефоне
Предсуществующий баг BalanceCard: на узких экранах (<960px) ряд трёх плиток
становится столбцом, но flex:1 1 0 (flex-basis:0) схлопывал высоту плиток до
~35px, а overflow:hidden обрезал содержимое — цифры (49 050 ₽, 98 лидов, 4 дн.)
и кнопки «Пополнить» пропадали, оставались пустые заголовки. В столбце плитки
теперь flex:0 0 auto (по высоте контента). Затрагивает телефон и планшет;
десктоп-ряд (>=960px) без изменений. Тесты 52/52 зелёные.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 03:27:41 +03:00
Дмитрий 2d97db83ee fix(портал-мобилка): Биллинг «Дополнительные услуги» — плашки не крошатся на телефоне
Строка услуги (название+описание | «при успешном…» 140px | цена) на телефоне
сдавливала название до одной колонки — текст ломался по слову («Сбор конкуре
нтов»). На телефоне (media <600px) раскладываем: название на всю ширину сверху,
ниже строкой «когда списываем» + цена справа. Десктоп/планшет без изменений.
Тесты 113/113 зелёные.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 03:12:58 +03:00
Дмитрий 0e74daa161 fix(портал-мобилка): «Лимит оптом» — на весь экран на телефоне
Диалог массовой правки лимита теперь на телефоне открывается на весь экран
(:fullscreen), единообразно с «Дни оптом»/«Регионы оптом» из той же панели
множественного выбора. Десктоп/планшет без изменений.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 20:59:20 +03:00
Дмитрий 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
Дмитрий a32f64cf5c fix(автоподбор): гейт «та же фирма» на разворот 2ГИС — режет иногородних чужаков
Баг AutoMoney: разворот по общему/партнёрскому/иногороднему номеру тащил чужие МФО
из Москвы/Питера (moneyman, finombudsman — фин.омбудсмен!, npmir, razvitie…) в источники
красноярского конкурента. crowdedCap ловил только массовые 8-800.

Гейт (100%-надёжный, проверен на реальных данных прода): карточку 2ГИС из разворота
выкидываем, ТОЛЬКО если город из URL карточки (2gis.ru/<city>/firm) ≠ город конкурента
И домен не наш бренд (с учётом поддоменов-филиалов). Свой город ИЛИ свой бренд — оставляем.
Яндекс НЕ трогаем (город в URL не виден, там же законные филиалы — риск срезать своих).

Проверка на проде: #16 AutoMoney/#64 Ваш Инвестор — все 2ГИС moscow/spb уходят;
#22 (автоломбард krasnoyarsk), #48 Кредит-финанс (Екб/Томск, Яндекс) — остаются.
11/11 тестов expander, вся ветка 220 green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 19:50:38 +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
Дмитрий e9600fb3b1 feat(автоподбор): текстовые номера с сайта → «на сайте, проверьте» (unverified)
Второй пробел после фикса таймаута рендера: номера, написанные на сайте простым
текстом (не кликабельные tel:/schema, без коллтрекинга), терялись. Пример Центрофинанс:
8 800 200-00-10 («Телефон:» у юр. адреса), +7 931 106-54-50 (подвал) — движок брал
только tel:-ссылки.

- HtmlPhoneScanner: тело сканируем БЕЗ <script>/<style> (меньше шума из конфигов)
- CandidateBuilder: без трекера body-номера (не в code/visible) → kind 'text' «проверьте»
- SourceAggregator + DeepStudyCollector: text-only → phone_kind 'unverified' (не теряем,
  но и за 100% настоящий не выдаём); code/справочник перебивают → 'real'
- фронт: бейдж «⚠ на сайте — проверьте» (amber), сортировка ниже настоящих, легенда
- 7 тестов (scanner/builder/aggregator/DeepStudy); вся ветка 493/493, build ок

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 19:23:37 +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
Дмитрий 4dc897d61c fix(автоподбор): рендер сайта больше не теряет номера при таймауте Playwright
Шаг 2: CurlPlaywrightFetcher.site() curl'ом успешно тянул страницу с tel:-номерами,
но render() (node render-page.cjs) висел на waitUntil networkidle и падал по таймауту.
Symfony Process::run() при таймауте бросает ProcessTimedOutException — оно вылетало из
site(), SiteOpener обнулял весь сбор. Итог: 0 номеров с сайта (боевой кейс Центрофинанс,
tenant info@lkomega.ru, прогон 07.07 14:07, только сайт+карточка, ни одного code-номера).

- render()/renderFirm() ловят \Throwable -> null: падение/вис рендера НЕ фатально,
  curl-HTML с номерами 'в коде сайта' сохраняется
- render-page.cjs: networkidle -> domcontentloaded + пауза; рендер 30с+вис -> 3.7с (боевая проверка)
- сиды curlRunner/nodeRunner для офлайн-теста; регресс-тест воспроизводит потерю номеров

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 18:16:42 +03:00
Дмитрий 1140fd0c09 feat(портал-мобилка): каркас — сайдбар прячется на телефоне, снизу панель-вкладки и «Ещё»
AppLayout: ярус-отступ (десктоп/планшет 232px, телефон 0 + низ под панель), рендер
AppBottomNav/AppMoreDrawer на телефоне, гамбургер открывает «Ещё». AppSidebar:
проп tier + скрытие на телефоне. Десктоп/планшет без изменений.
2026-07-07 17:59:04 +03:00
Дмитрий 019b70d416 chore(autopodbor): AITUNNEL_AGGREGATOR_MODEL=gpt-4o в .env.example — слабая mini резала живые федеральные МФО как агрегаторы
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 17:54:31 +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
Дмитрий 66376b3814 docs(handoff): исправлен устаревший статус — deep-study/render-cache/EXA уже на проде
Хендоф называл три фичи «невыкаченными, за тумблерами» — по факту (проверено
командой на боевом) все три на проде и флаги ON: AUTOPODBOR_DEEP_STUDY,
AUTOPODBOR_RENDER_CACHE, EXA_PROXY (тоннель отдаёт зарубежный IP). Уехали 06.07.
Следствие: баг «шаг 2 AutoMoney» — в уже-живом deep-study. Добавлена сегодняшняя
сортировка регионов (REGIONS_ALPHA), gitea-ссылка обновлена на b0bd110f.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 17:15:20 +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