При входе с email_verified_at=null (новый клиент не ввёл код из письма)
AuthController возвращает дружелюбное «Подтвердите почту — мы отправили код
на ...» с флагом email_not_confirmed, а не пугающее «Аккаунт заблокирован».
Реальная блокировка админом (verified + is_active=false) по-прежнему даёт
«Аккаунт заблокирован». Фронт по флагу уводит на /confirm-email с переносом
email в store (там кнопка «Отправить код повторно»).
TDD: Pest 2 кейса (неподтверждённый vs заблокирован), vitest redirect-кейс,
все GREEN. Проверено глазами на 8000.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Новый клиент без реквизитов заполняет короткие реквизиты прямо в окне
создания проекта (шаг 1: тип лица, имя, телефон, ИНН для юр/ИП), затем
переходит к форме проекта (шаг 2) — без ухода на /settings и без потери
черновика. Решение по шагу — по light-complete реквизитов (fail-open при
ошибке чтения; бэкенд-гейт 422 остаётся запасным путём, тоже инлайн).
Убран старый алерт с уходом на /settings. Vitest 20 passed, оба пути
проверены глазами на 8000 (есть реквизиты сразу проект; нет шаг 1 затем 2).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Галочка Вся РФ теперь подтверждает выбор одним кликом и сразу очищает
зависшую ошибку regions, убрана отдельная кнопка Подтверждаю и предупреждение.
Защита от случайной всей РФ сохранена осознанным кликом галочки.
Drawer пусто=вся РФ не трогал. Vitest RED→GREEN на старом коде доказан,
NewProjectDialog specs 16 passed. Проверено глазами на 8000.
Co-Authored-By: Claude Opus 4.8 <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>
Косяк 01: расчёт capacity садился на устаревшую цену через
PricingTier::where is_active true при двух активных версиях тарифа.
Переведено на PricingTierRepository activeAt now во всех путях расчёта:
release-сервис, контроллер runPreflight, bulk-лимит, sweep-джоб, reminder-джоб.
Реальное списание было корректным — деньги клиентов не затронуты.
TDD: PreflightUsesCurrentTariffVersionTest 5 кейсов, GREEN.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Что сделано стек на проде b808a24f деньги клиента целы фикс redeploy.sh
пред-деплойный аудит омега разобрана до конца. Что осталось омега-решение
владельца плюс Б-1 ООО плюс мелкая уборка. Грабли прода и промт для новой
сессии внутри. Телефоны омеги замаскированы.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Сверка боевого read-only перед накатом: прод-код == git побайтово 0 правок
мимо git, вся работа всех сессий включая оплату в main+gitea, прод-БД == канон.
Единственная нечистота — счётчик RLS-политик в шапке schema.sql отставал
42 реально 44 == прод pg_policies. Поправлено структурно БД не менялась плюс
запись в CHANGELOG_schema. Полный аудит дрейф+потери — отдельной запиской.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
deptrac закрыт через design-механизм самого конфига заведён
app/deptrac.baseline.yaml подключён через imports фиксирует
ProjectResource SupplierSnapshotGuard read-only расчёт замка для UI
прогон 0 violations 1 skipped гейт ловит только новый дрейф.
larastan принят env-факт ide-helper L13 Windows на CI зелено не код-дефект.
Диагностируемость молчаливого дропа won't-fix warning спамил бы на каждый
лид намеренно-выключенного проекта.
Прод-ops отмечены сделанными failed_jobs очищены 494к до 7 tenant 24
удалён soft-delete 22.06 проверено живьём 23.06.
Отметки в хэндоффах FJ и сводном чтобы перестало таскаться.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Лиды не идут с 3 июня = намеренное решение владельца он сам выключил
проекты подтверждено 23.06 не дефект. Развёрнута вчерашняя поправка
ушедшая в крайность реальный инцидент. Новый файл-разбор
2026-06-23-LEADS-STOPPED-correction.md с доказательствами прода
read-only SSH плюс баннеры во всех связанных доках. Телефон-источник
замаскирован.
Приёмка раунд-2 сверена живьём все 5 закрыты M-1 M-2 apiv1-rate на проде
hash 21 schema v8.51 Раздел B тесты.
Долги докалки проверены 23.06 всё ещё открыты deptrac 1 живое нарушение
ProjectResource SupplierSnapshotGuard larastan env-квирк диагностируемость
молчаливого дропа no_snapshot_skipped всё ещё Log info.
Только docs прод и код не тронуты.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- D2: requiredLeadsForTomorrow переведён на полный лимит, откат share-aware R-19 [решение владельца]
- B/D3: пополнение снимает клиентскую заморозку И блоки проектов вместе, политика всё-или-ничего
- F/J/D6: вечерний пересчёт 18:00 снимает блоки проектов у незаморожённых; общий ProjectBlockReleaseService; иерархия заморозка > блок
- fix: balance_freeze_log INSERT переведён на главное соединение — межсессионный self-lock с FOR UPDATE топапа [найден живым прогоном, pg_blocking подтвердил; в тестах маскировался SharesSupplierPdo]
- spec + plan в docs/superpowers
138/138 биллинг-тестов GREEN. Pint чисто. Живьём B+F подтверждены на докалке. На прод НЕ катилось.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Балансовый блок проектов закрыт 6 находками (N/G/E/H/M/O), по TDD+визуал,
gitea/main 2deaf207..de106a20, на прод НЕ катилось. E подтверждён живым
заказом в кабинете поставщика + уборка. L (омега tenant 25/проект 188)
остаётся открытым — сверка после деплоя + GO. Также зафиксирован долг
larastan(env-косяк ide-helper)/deptrac(ProjectResource->SupplierSnapshotGuard).
Co-Authored-By: Claude Opus 4.8 (1M context) <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>
Диалог «Редактировать» делал Object.assign(form, project) и слал весь объект,
включая sms_senders=null для site/call. UpdateProjectRequest валидирует
sms_senders как sometimes|array|min:1 → present-null проваливал array → 422.
Поле sms на форме site/call не отрисовано, поэтому errors.sms_senders некуда
показать — диалог «висел молча». Теперь persist() для не-sms проектов не шлёт
sms_senders/sms_keyword (заодно не триггерит зря snapshot-guard).
TDD: NewProjectDialog.spec — правка site не содержит sms-полей в PATCH body.
Глаза: правка site-проекта → PATCH 200, имя изменилось, диалог закрылся.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Заблокированный за нехваткой баланса проект выглядел как обычный «Ожидает
синхр.» — клиент не понимал, почему лиды не идут. Теперь карточка показывает
приоритетный красный статус «Приостановлен — не хватает баланса».
- ProjectResource: новое read-only поле balance_blocked (preflight_blocked_at !== null)
- ProjectCard: статус-бейдж приоритетно показывает блок над sync_status
- Project type: balance_blocked?: boolean
TDD: backend 2/2 (ProjectResource), frontend ProjectCard 6/6. ProjectResource
регрессия (applies_from/source_lock) 6/6 GREEN.
larastan/deptrac исключены точечно — пред-существующая краснота.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Пополнение баланса больше не оставляет проекты заблокированными навечно.
Новый ProjectBlockReleaseService: после зачисления (единая точка
BillingTopupService::topup — и ручное пополнение, и онлайн через
PaymentWebhookController) проверяет, хватает ли баланса на суммарный дневной
лимит ВСЕХ активных проектов тенанта, включая заблокированные. Хватает →
снимает preflight_blocked_at со всех + диспатчит SyncSupplierProjectJob;
не хватает → не трогает никого и возвращает дефицит (политика всё-или-ничего,
решение владельца). Зеркалит BalancePreflightService и фильтр sweep.
TDD: 4 теста (release при покрытии, удержание при нехватке, всё-или-ничего на
двух проектах, no-op без заблокированных). Регрессия billing 114/114.
larastan/deptrac исключены точечно — пред-существующая краснота.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Заблокированный за нехваткой баланса проект не должен уезжать заказом к
поставщику ни через одиночную правку, ни через ручную «Синхронизировать»,
ни через возобновление — раньше эти три пути диспатчили SyncSupplierProjectJob
безусловно. Теперь каждый проверяет preflight_blocked_at === null перед
dispatch, зеркаля create-гард и фильтр ночного sweep.
- ProjectService::update — needsResync && preflight_blocked_at === null
- ProjectService::triggerSync — early return для заблокированного
- ProjectController::toggleActive — гард перед dispatch
TDD: 6 тестов (3 пути × blocked/unblocked) — assertNotPushed для заблок.,
assertPushed для обычного. Регрессия preflight/project actions 26/26.
Живой контраст на докалке: blocked → очередь 0, unblocked → очередь 1.
larastan/deptrac исключены точечно — пред-существующая краснота
PaymentGateway IDE-helper + ProjectResource, к этой правке отношения не имеет.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
bulkUpdateLimit обходил преfflight баланса: клиент мог выставить дневной
лимит выше ёмкости и заказать у поставщика больше оплаченного. Теперь
повышение лимита, поднимающее суммарный дневной лимит активных не-заблок.
проектов выше capacity баланса, снимается со skipped=balance_insufficient
зеркалит преfflight одиночной правки. Понижения и правки paused/blocked —
всегда проходят. Без активных pricing_tiers проверка пропускается.
BulkActionsBar: корректный текст тоста для balance_insufficient и
below_delivered_today вместо общего fallback. ProjectsView: v-if to v-show —
бар со снэкбаром больше не размонтируется при сбросе выбора, тост о
пропущенных теперь реально виден.
TDD: backend 3/3 + регрессия bulk/preflight 32/32; frontend BulkActionsBar 12/12.
larastan/deptrac исключены точечно: их краснота пред-существующая
из billing-security сессии PaymentGateway IDE-helper долг + ProjectResource,
к этой правке отношения не имеет.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
KanbanView: удалён тест клика по убранной кнопке «Новая сделка».
BalanceCapacityIndicator: Vuetify-плагин в mount (v-icon) + формат «1 000 ₽».
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Закрыт хвост из billing-audit: webhook при зачислении пишет id строки ledger
в saas_transactions.balance_transaction_id (жёсткая прослеживаемость). Колонка
BIGINT nullable без FK (balance_transactions партиционирована). schema.sql v8.52
+ миграция 2026_06_22_170000 (guarded) + CHANGELOG. Тест проверяет связку. 115/115.
TopupResult допускает confirmation_url; TopupDialog при нём редиректит на
страницу ЮKassa (через тестируемый redirectTo), иначе прежнее мгновенное
зачисление. BillingView показывает баннер «платёж обрабатывается» при
возврате ?topup=return. Пресеты сумм уже были.
Публичный роут /api/webhook/payment (CSRF-exempt). Cross-tenant поиск через
pgsql_supplier (BYPASSRLS), зачисление под SET LOCAL app.current_tenant_id,
атомарный claim pending->success (идемпотентность), защита от несовпадения
суммы, делегирование зачисления BillingTopupService.
Флаг ВКЛ → создание платежа через OnlineTopupService + confirmation_url;
ВЫКЛ → прежнее мгновенное зачисление. Биндинг PaymentGatewayDriver в
AppServiceProvider. Также мелкая гигиена SystemSettingsHelperTest
(DatabaseTransactions для отката).
ProjectDetailsDrawer: при source_locked поля источника disabled + подсказка
с датой; красный баннер прочих ошибок не тронут. NewProjectDialog: баннер
«первые лиды с DD» (правило слепка 18:00). Тексты согласованы с владельцем.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
SupplierSnapshotGuard::lockState (pure, без DB) + ProjectResource отдаёт source_locked/source_unlock_at/source_unlock_projected; ProjectController withCount(supplierProjects). Логика гарда не изменена.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Фундамент legal_entities/payment_gateways/saas_transactions + драйвер
ЮKassa, поток create->redirect->webhook->автозачисление, рубильник-флаг
billing_yookassa_enabled в админке, чек 54-ФЗ заложен и выключен. Часть 3
счёт на безнал - следующим циклом. Прод на заглушке до ООО Б-1.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Новый сводный документ: что сделано (на проде / в gitea ждёт наката), какие
ключи нужны от владельца (Sentry DSN, Jivo widget ID, Slack webhook, ЮKassa,
Yandex SSO), решения владельца, ООО-блокеры, снятое. JivoSite-виджет отмечен
встроенным; Slack-ошибки — готовы в коде.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- JivoWidget.vue: подгружает скрипт Jivo при заданном VITE_JIVO_WIDGET_ID
(по образцу SmartCaptchaWidget); ключ пуст → ничего не грузит, виджет спит.
- Смонтирован в AppLayout (клиентский портал). +VITE_JIVO_WIDGET_ID в vite-env.d.ts.
- TDD: JivoWidget.spec (грузит при ключе / спит без) GREEN; AppLayout.spec 16/16; eslint 0.
- Активируется вставкой VITE_JIVO_WIDGET_ID (твой ID канала Jivo). На прод не выкачено.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Раздел B (~25 «непокрытых» тест-путей) — переоценка: большинство уже покрыто,
реальные гапы закрыты +9 целевыми TDD-тестами (b9184a6a, d7b5f2c1). Помечено
закрытым в owner-decisions и round2-DONE-handoff, чтобы не всплывало в остатках.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- ReportsView.onCancel снимает submitSuccess — success-баннер больше не висит после отмены отчёта. TDD: тест «отмена задачи сбрасывает зелёный» (RED→GREEN), весь ReportsView.spec 22/22, eslint 0.
- docs: ui-audit-round2 — минор тоста помечен исправленным (открытых пунктов не осталось); stage5-checklist — supplier:rekey-orphans dry-run проверен на проде 22.06 («No orphan»), разовая миграция не нужна.
- На прод не выкачено.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>