Найдено проверкой глазами в 19:27 МСК (после 18:00):
1. Баннер правок количества/региона/дней говорил «вступят со следующего дня» — врал
после 18:00 (правка не попадает в сегодняшний слепок → реально послезавтра). Теперь
показывает АКТУАЛЬНУЮ дату через firstLeadDate (до 18:00 → завтра, после → послезавтра):
«…вступят в силу с 27 июня». Дроуэр + окно «Редактировать».
2. Сообщение блокировки удаления/смены источника в SupplierSnapshotGuard было захардкожено
«мы увидим это сегодня в 18:00 … можно будет послезавтра» — после 18:00 «сегодня в 18:00»
уже прошло. Теперь time-aware через computeGraceUntil: «…лиды придут до 26 июня … можно
будет после 26 июня».
Проверено глазами: баннер лимита (27 июня), подтверждение источника (до 26 июня),
блок удаления (после 26 июня) — все согласованы и меняются по времени суток. Тесты:
guard 30/30, фронт 38/38, leadDate (18:00 порог) зелёные.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ProjectResource.source_change_message = ProjectRuleMessages.sourceChanged (тот же текст,
что in-app уведомление 6.2). Диалоги подтверждения (дроуэр + окно Редактировать) тянут его
из API с fallback на локальный текст. Бэкенд — единственный источник строк правил, экран и
колокольчик не расходятся. Проверено глазами (epic6-unified-rule-text-confirm.png). Тесты:
ProjectResource 5/5, дроуэр 27/27, EditProjectDialog 7/7.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Редизайн UX (design-gate 2026-06-25): раздача доводит хвост по старому источнику
через слепок, поэтому замок не нужен.
- 3.1: поля источника больше НЕ disabled; при правке количества/региона/дней на
залоченном проекте — информ-баннер pdd-applies-from-banner (вступит со след. дня).
- 3.2: смена источника на залоченном проекте → диалог подтверждения
pdd-source-change-confirm; PATCH только после подтверждения.
Старые тесты замка (disabled-поля) переписаны под новое поведение. 26/26 зелёных.
⚠️ Не выкатывать раньше включения флага routing_match_by_snapshot.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
U1 из прогона тупой пользователь 24.06: site/call поля формы проекта
получили человеческие подписи и подсказки вместо жаргона донор/конкурент.
Затронуты NewProjectDialog.vue и ProjectDetailsDrawer.vue.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Косяк 02: поле телефона проекта типа call отвергало +7.., 8.., пробелы и скобки.
prepareForValidation в StoreProjectRequest и UpdateProjectRequest приводит номер
через PhoneNormalizer к канону 7XXXXXXXXXX без ведущего плюса, чтобы раздача
LeadRouter матчила без плюса. Финальная regex оставлена страховкой.
Кастомные messages по signal_type: ошибка с примером формата, без имени Источник.
Фронт: постоянная подсказка под полем в NewProjectDialog и ProjectDetailsDrawer.
TDD: ProjectPhoneNormalizationTest 8 кейсов, GREEN. Проверено глазами на 8000.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Боковая панель ProjectDetailsDrawer ловила в onSave только 422; при 409
balance_insufficient (лимит превышает баланс) ничего не показывала — клиент
не понимал, почему правка лимита не сохранилась. Теперь под полем лимита
выводится причина с ёмкостью и запрошенным объёмом + призыв пополнить баланс.
TDD: ProjectDetailsDrawer.spec — 409 balance_insufficient показывает сообщение,
saved не эмитится. Глаза: лимит 100 при ёмкости 60 → PATCH 409 → видимое
«Лимит превышает баланс: хватает на 60 лид(ов), запрошено 105…».
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ProjectDetailsDrawer: при source_locked поля источника disabled + подсказка
с датой; красный баннер прочих ошибок не тронут. NewProjectDialog: баннер
«первые лиды с DD» (правило слепка 18:00). Тексты согласованы с владельцем.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Раньше чтобы убрать один регион из выбора, приходилось сбрасывать все
и выбирать заново. Добавлен closable-chips на v-autocomplete регионов в
трёх местах: карточка создания проекта (NewProjectDialog), панель
редактирования (ProjectDetailsDrawer) и массовое изменение регионов
(RegionsBulkDialog). Теперь у каждого чипа есть крестик.
Покрыто Vitest: closableChips=true на каждом селекторе.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
UX-request 18.05.2026 (п.9):
- ProjectDetailsDrawer (правая панель на /projects) теперь редактирует
signal_identifier для site (домен) и call (телефон 7\d{10}); для sms —
sms_senders+sms_keyword (как раньше).
- Поле «Источник» отображается **только** в карточке проекта (read-only
в drawer сделки на /deals — Task 2 закрыл).
Backend:
- UpdateProjectRequest: condition-based валидация по signal_type из БД
(site domain regex, call 11-digit 7\d{10}; sms — без новых правил)
- ProjectService::update: убран signal_identifier из silent-drop;
$needsResync расширен на signal_identifier → SyncSupplierProjectJob
signal_type остаётся immutable (менять тип проекта — отдельная задача).
Larastan baseline bumped (ProjectsUpdateTest: actingAs 8→12 для 4 новых тестов).
Pest tests/Feature/Plan5/Projects/ProjectsUpdateTest 12/12.
Vitest 33 passes на Project-spec'ах. Build 2.03s.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- projectsStore: Project.regions?: number[] interface field
- NewProjectDialog: replace interim placeholder с v-autocomplete (89
subjects + federal district subtitle); form drops region_mask/region_mode
(backend dual-writes)
- ProjectDetailsDrawer: replace maskToCodes/encode-watch с direct
form.regions binding; same v-autocomplete component
- Vitest: +2 NewProjectDialog tests (count=89, POST payload includes regions[]);
refactor 3 existing PDD region tests на regions[] model
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>