Commit Graph

370 Commits

Author SHA1 Message Date
Дмитрий fbca7e13f9 @
feat(sudya): оркестратор, карточка звонка и приёмка на подсадных ошибках

Оркестратор сам ничего не проверяет — собирает слои и выносит итог: любой СТОП →
СТОП, иначе ТРЕВОГА, иначе НОРМА. Сломанный якорь перекрывает всё. В бою полная
коллегия не зовётся — только приборы, деньги владельца берегутся.

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

Проверено сквозняком на живом журнале, а не только на выдуманных примерах:
судья честно поймал, что она говорит 57% времени при норме 35–45%.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@
2026-07-18 18:59:29 +03:00
Дмитрий e2e054365c @
feat(sudya): приборы техники и характера + сторож покрытия рубрики

Техника: задержки до звука и до ответа, потеря реплики клиента (СТОП — мост однажды
глох во время думания и сказанное исчезало), выдумки ушей на тишине, доля её речи.

Характер v9: женский род, «вы», повторное приветствие, своё имя вместо обращения,
длина реплики, латиница. Женский род правится ТОЛЬКО про себя — тест стережёт
живую ловлю 18.07, когда сторож сделал пациента-мужчину «готова».

🔴 Сверка вскрыла дыру в собственном плане: признаки 8 и 9 стояли в рубрике как
измеряемые, а кода не было — судья молча делал вид, что проверяет. Признак 8
реализован (перебивания были, а обрезки нет — тот самый утренний дефект моста).
Признак 9 честно записан как неизмеряемый: журнал пишет, что мост ЖДАЛ думающего,
но не пишет случаи, когда оборвал. Добавлен тест покрытия: каждый приборный признак
либо имеет код, либо стоит в списке с причиной. Дыра больше не спрячется.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@
2026-07-18 18:55:03 +03:00
Дмитрий bf30a83ed2 @
feat(sudya): прибор правды о числах и коллегия судей со слепым протоколом

Прибор ловит два дефекта, пойманных владельцем живьём: числа вне замка фактов
и цену наизнанку («от пятидесяти пяти до двадцати пяти» вместо «от двадцати пяти
до пятидесяти пяти»).

🔴 Адверсарный прогон поймал ПОВТОР истории: прибор резал правду «минимальный
заказ — одна заявка». Ровно на этой форме сторож чат-бота однажды уже съел верный
ответ и оставил клиенту обрубок. Добавлены формы один/одна/одну/штука, случай
закреплён отдельным тестом — тестов из плана было мало, они этого не видели.

Коллегия: четыре узкие роли вместо одной большой рубрики, вопрос НЕЙТРАЛЬНЫЙ
(наводящий однажды заставил судью объявить роботом живого диктора), находка без
цитаты понижается до сигнала, якорь-контроль, автостоп и кеш по деньгам.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@
2026-07-18 18:47:52 +03:00
Дмитрий 7ee40fcde5 docs(разведка): реклама по своим номерам (4 площадки) + аналоги поставщика в СНГ и мире
Две находки одной сессии.

1. Реклама по своим номерам — берём все 4 площадки:
   Яндекс Аудитории (порог 100, полный API, максимум площадок), VK Реклама
   (порог 100 — поправка, 2000 относится к старому myTarget), myTarget (2000,
   ради Одноклассников), МТС Маркетолог → Telegram Ads (0,9 руб/показ, без API).
   Главный сценарий — недозвоны, которые сейчас списываются в ноль.
   Look-alike выключен намеренно: согласие давали конкретные люди.
   Грабли автовыгрузки: формат 79995551111, SHA-256 без соли, статус
   «Обновляется» на несколько часов после заливки.

2. Аналогов нашего поставщика (ГЦК/BG) нет нигде — проверено 9 стран СНГ
   и 12 мировых рынков. Операторы монетизируют данные, но контакт наружу
   не выдают: закрытый двор от Казахстана до США. Законы всех девяти стран
   СНГ требуют отдельного согласия на передачу номера третьему лицу.
   Российская модель — аномалия, моат сильнее, чем считали.
   Казахстан — единственный перспективный (Kcell Target Call, DMP.one уже там).
   Беларусь закрыта законом 99-З дословно. Узбекистан — вторым, разведать глубже.

Дыры выписаны честным списком: локализация данных в КЗ/УЗ, реальные цены,
льёт ли BG по Казахстану (проверяется тестовым проектом за час).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-18 18:45:16 +03:00
Дмитрий ec8cd1ddb2 @
feat(sudya): разбор журнала моста и надзор за судьями

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

Надзор: промах = судья сказал НОРМА, а владелец нашёл брак ушами. Сказал СТОП —
поймал, не промах. Доля выше 20% — судья негоден. Без этого слоя коллегия
со временем халтурит незаметно: она же сама себя и оценивает.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@
2026-07-18 18:43:12 +03:00
Дмитрий 17cf679652 @
feat(sudya): план судьи + рубрика на 36 признаков

Рубрика — единственный источник правды по критериям: спектры I звук, II техника
разговора, III правда и обязательства, IV характер, V продажа (новое — этого не
судил ни один прежний судья), VI проверка самого судьи.

Каждый признак несёт тяжесть: СТОП двигает вердикт в брак, ТРЕВОГА зовёт смотреть
глазами, СИГНАЛ идёт только в статистику. Из 36 признаков 16 — СТОП.

Тесты закрепляют целостность: ровно 36, номера без дыр, поля из допустимых множеств,
спектр V судит только продавец.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@
2026-07-18 18:39:18 +03:00
Дмитрий d2b74c8b04 docs(finder): спека и план проверки телефонов (ДаДата + HLR)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 18:22:40 +03:00
Дмитрий f386a2e27b fix(finder): мусорные номера подписаны «номер не распознан» (по спеке)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 18:21:48 +03:00
Дмитрий f8bd812807 test(finder): отрисовка размеченных номеров закреплена тестами (HTML + Excel)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 18:13:33 +03:00
Дмитрий d9e82f6e3c @
docs(sudya): проект сводного судьи диалогов Александры

Собран из трёх существующих семейств судей: голосовые (NISQA/дуэли/glitch),
чатовые (AnswerGuard + слепые судьи-агенты), нормативные (llm-judge/reviewer-agent/
judge-evaluator). Ни одно из них не судило ГЛАВНОЕ — продала ли она; для номера
менеджера по продажам на лендинге это ключевой спектр.

Устройство: приборы (приговор) → коллегия узких судей-ролей (находки) →
судья над судьями (доля промахов). 36 признаков в шести спектрах.

Протокол честности, каждое правило оплачено ошибкой: слепота, нейтральный вопрос,
живой якорь в партии (забраковал якорь → партия недействительна), роли вместо
одной большой рубрики, находка без цитаты источника не считается.

Границы названы явно: звук живых клиентов не пишем (ПДн — отдельная работа),
судья не правит Александру сам, владелец остаётся высшей инстанцией.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@
2026-07-18 18:09:39 +03:00
Дмитрий f2221101c6 feat(finder): метки номеров в списке и Excel — живые мобильные первыми, мёртвые зачёркнуты
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 18:04:24 +03:00
Дмитрий ba62359337 fix(finder): нераспознанные номера в warning (не теряем), guard эндпоинта, секреты читаем раз
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 17:58:37 +03:00
Дмитрий 3db5115e6e feat(finder): проверка номеров встроена в сбор контактов (+2 поля Firm)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 17:46:52 +03:00
Дмитрий 40fa829738 fix(finder): оркестратор — сбой на одном номере не роняет остальные; junk-путь закреплён тестами
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 17:41:49 +03:00
Дмитрий c3eff704a3 feat(finder): оркестратор проверки номеров + сортировка для показа
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 17:34:49 +03:00
Дмитрий 74f3048e91 fix(finder): HLR — id=0 не терять, строковые статусы коерсить, опрос короче (8×0.5с)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 17:30:32 +03:00
Дмитрий 7255a4c1b6 feat(finder): HLR СМС-центра — живой/отключён/не существует, кэш вердиктов
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 17:23:29 +03:00
Дмитрий 7d57c8277d fix(finder): кэшировать любой оплаченный ответ ДаДаты — незнакомый тип не даёт платить дважды
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 17:19:58 +03:00
Дмитрий d358ddb6f3 feat(finder): ДаДата clean/phone — мобильный/городской, оператор с MNP, кэш
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 17:14:38 +03:00
Дмитрий 4ddcc6abae feat(finder): нормализация телефонов досье — дубли и хвосты-обрезки долой
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 17:00:45 +03:00
Дмитрий 1514991ceb @
style(sales): Pint — порядок импортов в SalesClientsController

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@
2026-07-18 14:40:02 +03:00
Дмитрий b0750dce53 @
feat(sales): сайт кандидата ссылкой прямо на плитке доски

Менеджеру удобно глянуть на клиента перед звонком, не открывая карточку.

- На плитке колонки сайт выводится ссылкой (target=_blank, rel=noopener),
  click.stop — иначе клик по ссылке заодно открывал бы диалог карточки.
- Расчёт ссылки вынесен в utils/prospectSite.ts и переиспользован в карточке:
  домен получает https, готовый адрес не трогаем, пусто → строки нет.

Гейты: Vitest 55/55 по воронке (4 новых теста доски), vue-tsc чисто.
TDD RED→GREEN.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@
2026-07-18 12:36:14 +03:00
Дмитрий 48dd6c44af @
fix(sales): «Зарегистрировался» подаёт ЗАЯВКУ начальнику, а не привязывает клиента сразу

Владелец заметил: в отделе есть штатный порядок «через начальника» (экран «Заявки
на привязку»), а кнопка в карточке кандидата создавала SalesClientAssignment напрямую
и в истории заявок ничего не появлялось.

- registerProspect() теперь зовёт SalesAttachmentService::submit() от имени ВЛАДЕЛЬЦА
  карточки. Свободен → заявка pending + письма менеджеру и начальникам; занят другим →
  заявка с пометкой конфликта, чужая привязка не трогается; уже свой → заявки нет.
  Привязка со снимком тарифа создаётся только при одобрении (handleApprove).
- Стадия карточки едет в «Зарегистрировался» СРАЗУ (решение владельца): регистрация —
  факт, воронка показывает правду; «чей клиент и кому деньги» решает начальник.
  Автожизнь не зависит от одобрения — джоб смотрит linked_tenant_id.
- Отменён прежний 422 «клиент уже закреплён за другим менеджером» — теперь это заявка.
- Подсказка под полем e-mail говорит про одобрение начальником.

Спека §17 (отменяет правило §6 «привязываем сразу»). Гейты: Pest 218/218 sales,
Vitest 38/38, Larastan 0 в своих файлах. TDD RED→GREEN.

LEFTHOOK_EXCLUDE: larastan/cspell падают на файлах параллельной сессии
tests/Feature/Admin/*Balances*, свои файлы проверены отдельно и чисты.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@
2026-07-18 12:09:24 +03:00
Дмитрий b3d758c81b @
style(sales): Pint — импорты ДаData в тесте кандидатов

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@
2026-07-18 11:40:27 +03:00
Дмитрий 1c3da4a25e docs(golos): прогресс телефонии Mango (бот REGISTERED) + рестарт-промт под компакт
Телефония: бот регистрируется в Mango (pyVoIP 1.6.8, PhoneStatus.REGISTERED, NAT-aware rport).
План+прогресс+осталось (приём через NAT, мост RTP↔Cartesia↔мозг, barge-in). Рестарт-промт под
оба трека. Секреты и ПДн (SIP-пароль, номера, ключи) — вне git, замаскированы.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-17 05:25:52 +03:00
Дмитрий ec903c6d19 docs(golos): чистка голоса (бренд-IPA/нервность/угу) + план телефонии Mango
Голос: fix_pron() лечит бренд «Лидерра» через IPA-блок Cartesia (подтверждено на ухо);
нервничание с затуханием (speed+calm/content, т.к. emotion anxious на этом голосе — пустышка);
угуканье подрезано. Всё принято владельцем на слух.
Телефония: план стройки под ключ (Mango SIP vpbx400046720.mangosip.ru → медиа-мост на GPU →
уши/голос Cartesia + barge-in). Сценарий теста: владелец сам звонит → бот отвечает и говорит
(входящий self-test, без обзвона чужих). Креды/скрины — вне git.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-17 00:33:06 +03:00
Дмитрий 57f1ca3900 docs(golos): движок Александры — наука телефонных продаж + плавающий темп + лестница финала (снимок движка + журнал)
Вшита наука телефонных продаж (Gong/Chorus, Восс/SPIN/Sandler): слушать>говорить,
SPIN-лесенка, зеркало/называние чувства, стоп-слова, дисциплина цены. Плавающий темп
Cartesia (0.86/0.90/0.95, только версия 2025-04-16). Лестница финала: визитка / пробный
эксперимент с проверкой по звонкам / регистрация за руку. Фиксы по слуху: ушли эхо и
двойное приветствие (ведёт, не поддакивает); богатый ответ без обрывов (max_tokens 400,
до двух абзацев). Снимок движка aleksandra_engine.py — durable, без ключей.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 23:23:26 +03:00
Дмитрий 87b7f4117f docs(golos): рестарт-промт под движок Александры (полный контекст для новой сессии)
Переписан paste-блок восстановления контекста под текущее состояние: движок
собран под ключ (живость + продающая база + отраслевая призма + живой Sonar +
жёсткий разворот), новый порядок чтения (журнал → паспорт → база), боевые
розетки, ключи/квирки, следующие шаги, стиль владельца.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 22:12:04 +03:00
Дмитрий 9317974670 docs(golos): движок Александры под ключ + живой Perplexity(Sonar) + жёсткий разворот ниши
- жёсткий разворот ниши (стоматология → займы под залог): бот ловит смену,
  тормозит разведочным вопросом (= покупка времени), свапает справку,
  додавливает через призму новой ниши; гарантий не даёт (флажок держит).
- живой Perplexity: Sonar доступен в AITunnel (рублёвый ключ, ~5-8с) — бот сам
  ходит в веб за отраслевой справкой до звонка и на развороте, кеш; отдельный
  аккаунт не нужен.
- движок собран в один файл scratchpad/aleksandra_engine.py (мозг+характер+
  живость+отрасль), прогнан end-to-end с живым Sonar. Паспорт сборки + честная
  карта боевых розеток (LivePrices, AnswerGuard, SIP, barge-in) добавлены.
- журнал и рестарт-файл обновлены.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 22:07:34 +03:00
Дмитрий 1a4218e1ee docs(golos): продающая база вплетена в живой круг (Александра продаёт из базы)
zhivoy_krug_prodazhnik.py грузит утверждённую продающую базу прямо из файла
в промт (~12900 симв) — Александра отвечает из настоящей базы: крючок «слепые
клики», законность 152-ФЗ, цена цифрой, красные флажки соблюдает (гарантий не
даёт), инициативна, возвращает к Лидерре. Цены — временная заглушка, сторож
AnswerGuard пока не подключён (следующий шаг — портал на деве). Журнал и
рестарт-файл обновлены.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 20:04:50 +03:00
Дмитрий 27644d6adc docs(external): план реализации чистки доп-каналов поставщика (TDD, 5 задач)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 19:15:37 +03:00
Дмитрий 907bd2f231 docs(external): спека модуля чистки доп-каналов поставщика (B6/B8 → удаление в 20:00, KEEP=B1/B2/B3)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 19:15:37 +03:00
Дмитрий b1814bea34 feat(external): POST /balances/refresh принимает services[] (групповое обновление) 2026-07-16 17:05:38 +03:00
Дмитрий d4b466cf75 feat(external): keyso — проба живости (зависимость поиска клиентов, 13-й ключ) 2026-07-16 17:03:47 +03:00
Дмитрий c1f46c0cc5 refactor(external): xfetch — проба живости (ключ у sales-finder, не у портала) 2026-07-16 17:00:14 +03:00
Дмитрий c1f015d17d feat(external): ExternalBalanceRefresher — обновление набора сервисов + окно свежести + BalanceReading::alive()
Фаза A плана 2026-07-16-external-services-online-monitoring:
- BalanceReading::alive() — состояние «жив, денежного баланса нет».
- ExternalBalanceRefresher: реестр 6 сервисов, refresh(keys, force, sendAlerts),
  окно свежести 60с, edge-trigger алерта по колонке light (фон/кнопка sendAlerts=false молчат).
- RefreshExternalBalancesJob делегирует рефрешеру (поведение суточного сбора сохранено).
Тесты: 35 External зелёные, Larastan 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 14:50:01 +03:00
Дмитрий a29f10a25f fix(sales): «Мой доход» падал у менеджера (permission denied на sales_client_assignments)
Аутентифицированный sales-user грузится под pgsql (crm_app_user) до admin-db
(приоритет middleware Authenticate > кастомного UseAdminConnection), и модель
запоминает это подключение. SalesEarningsService лениво читал $u->assignments/
->currentTariff → запрос уходил в crm_app_user (нет прав на sales_*) → 42501.
Фикс: assignmentsOf()/tariffOf() — свежие запросы на текущем (admin) подключении,
как уже делает SalesMetricsService. Регресс-тест: bogus-подключение на модели.
Гейты: 18/18, Larastan 0. Тесты грант НЕ ловят (общий admin-PDO) — ловится живьём.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 09:37:47 +03:00
Дмитрий b571445731 style(sales): Pint — импорт Connection в SalesProspectsAdvanceJob
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 19:10:27 +03:00
Дмитрий a2fa9ceb15 fix(sales): сервис-канал поиск→портал — исключить из CSRF (POST давал 419)
Интеграционные роуты в web.php → web-группа применяла VerifyCsrfToken; у
Python-поиска нет сессии/куки, POST /integration/prospects падал 419 (в бою).
Pest это не ловил (Laravel гасит CSRF под тестами). Защита канала — сервис-токен.

Найдено живым смоуком после выката Этапа 2.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 18:28:49 +03:00
Дмитрий fa0f79b69e feat(sales-finder): Этап 2 — кнопка «Отдать менеджеру», колонка Менеджер, клиент портала
В поиске: выпадашка менеджеров (из портала) + кнопка «Отдать менеджеру» рядом
с «Собрать контакты», колонка «Менеджер» перед «Оценкой», таблица с отступом.
Новый salesfinder/portal.py (get_managers/send_prospects, полный payload фирмы),
поля Firm.assigned_manager_id/name. Портал недоступен → кнопка disabled, ошибка
не помечает строки. Гейты: 244/244 pytest.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 18:22:15 +03:00
Дмитрий 16aa00a0e4 feat(sales): Этап 2 — сервис-канал поиск→портал (managers + ingest)
Портал публикует /api/sales/integration/{managers,prospects} под сервис-токеном
(X-Sales-Token, config sales.integration_token). ingest создаёт карточки stage=new
с полным payload, дедуп по (sales_user_id, inn|phone), assigned_by=начальник.
Гейты: 8/8 Pest, Larastan 0. Финдер-сторона — следующим коммитом.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 18:13:59 +03:00
Дмитрий ad2c61bab5 docs(sales): замечания владельца после демо Этапа 1 (карточка=все поля, сорт по созвону)
3 правки в §15: карточка показывает ВСЕ данные поиска (payload), фильтр —
конкретный выбор менеджера, сортировка «Переговоры» по ближайшему созвону.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 17:16:38 +03:00
Дмитрий 5fb20a1318 docs(sales): миграция — добавил testing в список стадий в шапке (RLS-review)
Этап 1 Task 15. Комментарий отставал от CHECK (8 стадий). Консистентность.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 16:50:57 +03:00
Дмитрий 869590a1b2 feat(sales): маршруты + пункты меню воронки (менеджер/начальник)
Этап 1 Task 14. /sales/prospects (менеджер), /sales/prospects/board
(начальник, salesBossOnly). Пункты «Потенциальные клиенты» и «Воронка отдела».

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 16:46:54 +03:00
Дмитрий 4b5afacfb7 feat(sales): экраны воронки — менеджер (свои) + начальник (все + фильтр)
Этап 1 Task 12–13. SalesProspectsView (менеджер, listProspects свои),
SalesProspectsBoardView (начальник, listSalesManagers фильтр, все карточки).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 16:44:29 +03:00
Дмитрий 4212380d6c feat(sales): доска-канбан прогнозов (8 колонок, клик→диалог, просрочка)
Этап 1 Task 11. Без drag: карточки раскладываются по стадиям, клик эмитит
open, просроченный next_call_at подсвечивается.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 16:42:08 +03:00
Дмитрий bb2fe2f34d feat(sales): диалог карточки прогноза — результат разговора + валидация
Этап 1 Task 10. Селектор результата, поля по стадии, отказ скрыт при user,
обязательные причина/время. Тесты через vm (v-dialog телепортит контент).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 16:40:46 +03:00
Дмитрий ead1335242 feat(sales): фронт — API прогнозов + утилита стадий/просрочки
Этап 1 Task 9. PROSPECT_STAGES (8 колонок), stageMeta, isOverdue;
listProspects/updateProspect в api/sales.ts.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 16:38:07 +03:00
Дмитрий d6cddf73a6 feat(sales): artisan sales:prospects-demo — демо-карточки воронки
Этап 1 Task 8. По 2 карточки на каждую из 8 стадий у указанного менеджера
(для показа досок). Baseline под artisan() Pest-паттерн.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 16:35:52 +03:00
Дмитрий 9d8fd8d48c feat(sales): API воронки — список (свои/все+фильтр) + результаты разговора
Этап 1 Task 3–7. GET /api/sales/prospects (менеджер видит свои; начальник —
все + ?manager_id). PATCH /prospects/{id} — переговоры (next_call_at),
недозвон (причина), отказ (причина; запрещён из stage=user). ownership 403.
8 тестов зелёные. Baseline Larastan под Pest-паттерны нового файла.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 16:33:29 +03:00