Что сделано стек на проде 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>
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>
Раздел 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>
- NewProjectDialog.submit(): обязательны название и источник (домен/номер/отправители по типу сигнала); ошибка показывается сразу, без обращения к серверу. +2 TDD-теста, два существующих теста обновлены под новый гейт. Полный фронт-сьют — без новых падений; проверено глазами в браузере на локалке.
- docs: пометки находок приёмки/UI/impersonation/ADR-018 приведены к фактическому прод-статусу (M-1, M-2 капча Yandex, FN-RESET/2/3/ENC, F-CSV, apiv1-rate, N-4, F-T1, F-P1 — на проде; failed_jobs очищены 494191->0; tenant 24 удалён soft-delete).
- решение владельца 22.06: admin-area доделки (saas-admin SSO, two-person approval, role-guard супер-админа, supplier fallback, обезличенный admin_user_id) сняты как отдельные задачи — доделать единым пакетом вместе с подключением Yandex SSO после ООО.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Один невалидный UTF-8-байт в выгрузке лидов crm.bp-gr.ru ронял весь импорт на
INSERT (PG: invalid byte sequence for encoding UTF8, SQLSTATE 22021). str_getcsv
пропускает любые байты, и невалидная последовательность доходила до БД.
CsvLeadsParser::parse теперь чистит невалидный UTF-8 через mb_convert_encoding
до парсинга — битый байт заменяется, строка импортируется, очередь не падает.
TDD CsvLeadsParserUtf8Test, проверено руками на PG.
Также зафиксирован вывод по FN-RLS-CTX: no-action — путь projects уже под
tenant-middleware, старый no-auth endpoint заменён, не воспроизводится.
Прод не трогался. Накат — позже вместе с остальным.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
FN-3: онбординг-confirm не ставил users.email_verified_at — поле вне fillable,
mass-assign его гасил. RegistrationService::confirm теперь forceFill is_active +
email_verified_at. TDD ConfirmSetsEmailVerifiedAtTest.
FN-2: миграция 2026_06_19_130000 дропнула таблицу reminders, но забыла
ALTER COLUMN notification_preferences SET DEFAULT — реальный DB-дефолт оставался
с мёртвым ключом reminder, расходясь с каноном schema.sql v8.45. Новая миграция
2026_06_22_120000 метаданные-only выравнивает дефолт под канон. squawk 0 issues,
применено dev+testing, проверено psql. CHANGELOG v8.50 + шапка schema.sql.
TDD NotifPrefsDefaultNoReminderTest.
FN-1 переоценён как не-баг кода: resolvePlatforms даёт B2+B3 корректно, B3-miss —
supplier-side Doubles, джоба сама ретраит. Зафиксировано в отчёте приёмки.
Прод не трогался. Накат — позже вместе с остальным.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
FN-RESET: письмо сброса строило именованный роут password.reset которого нет в SPA.
ResetPassword::createUrlUsing → /reset/{token}?email= в AppServiceProvider boot.
FN-LOGIN-ROUTE: гость без Accept json на auth:sanctum уводил в именованный роут
login которого нет → 500. redirectGuestsTo /login + render AuthenticationException
→ 401 JSON для api/*.
FN-SESSION: chromium.launch стоял вне try/catch — отказ запуска браузера маскировался
unhandled-rejection в opaque exit 1 двойник login-rejected. launch в try + top-level
catch → чистый exit 4 + JSON stderr в refresh-session.js и manage-project.js.
Тесты: PasswordResetUrlTest, UnauthenticatedApiResponseTest, node:test launch-failure
в обоих playwright-скриптах. Разбор FN-SESSION + ops-долг playwright install под
www-data + поправки отчёта приёмки + новая находка FN-INN-LOOKUP.
Прод не трогался. Накат — позже вместе с остальным.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Read-only разбор логов 22.06: FN-SESSION (заход к поставщику Playwright валится
121×/день → CsvReconcile down, зацепка к «лиды не идут»), FN-LOGIN-ROUTE
(route login не определён, класс FN-RESET), FN-FAILEDJOBS-PILE (490k мёртвых
B1+SMS, майский шторм, корень починен). Основной шум — исторический.
Добавлен промт новой сессии для сведения находок и старта правок.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Полный приёмочный прогон R1–R5 на боевом liderra.ru: ядро PASS, омега цела
1835400/1013, teardown+F3 зелёный. FN-RESET: сброс пароля сломан для всех
(route password.reset не определён) — чинить до передачи продажникам.
Новый тариф T1=70₽ с 22.06. tenant 24 онбординг оставлен.
+cspell: онбординг, DOUBLEPROJ, INSUFF в словарь.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Найдено владельцем post-run: forgotPassword → дефолтное Laravel-уведомление
строит URL через route('password.reset'), которого нет (SPA-роут /reset/:token).
Клиент видит «ошибка», письмо не уходит; побочно ломает анти-перебор.
Клиент-видимо, чинить до передачи продажникам. Вердикт GO формально не меняет.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Полный прогон R1–R5 на боевом liderra.ru: деньги сходятся до копейки,
изоляция 0 утечек, аудит-цепочки зелёные после teardown, нагрузка ~37x
запас, живой онбординг через реальную капчу + дайджест-email доставлен.
Омега не тронута: 1835400.00 / 1013 сделок. Критдефектов нет.
Находки FN-AUDIT / FN-1 / FN-2 / FN-3 — разработчику, на продажу не влияют.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
R3b + launch-промт: 6-значный код приходит письмом на ящик владельца (в ответе
API на проде его нет, в чужую почту исполнитель не зайдёт) → владелец читает код
и передаёт исполнителю для шага ONB-CODE. На живом онбординге владелец даёт две
вещи: решение капчи + код.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
§4.5: efir.html как телевизор владельца, формат карточки было→ожидали→стало
+ 📸 живой скриншот, пульт ▶/⏸, автопродолжение, два параллельных выхода
(техкарточка + эфир). Добавлен в список чтения и Шаг 0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Пуленепробиваемый вход: железные запреты (омега/секреты/21:00/критдефект),
состояние прода (только омега, реальная капча, playwright ок, бэкап), что взять
у владельца, порядок R0-R5 с поправками (Татарстан=19, vid-диапазон, teardown
без name/auth_log, онбординг через ручную капчу), анти-ошибка ритуал, вердикт.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
R3b §A: капча на проде реальная (Yandex, test=false) — два способа пройти
онбординг (владелец сам регистрируется ИЛИ решает капчу в видимом Playwright);
массовый провижининг — SQL (R1). Удалённые ящики kdv1@/stels_info@ убраны из текста.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
N-4: пометка digest_sent ПОСЛЕ отправки (mark-after-send) — повтор не
дублирует И сбой джоба до отправки не теряет дайджест. TDD-тест GREEN 6/6.
N-2: инъекции R2 с TEST-диапазоном vid 9e12..1e13 → R5 чистит 4 orphan-таблицы
детерминированно по vid/lead_id, без ручного манифеста.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
UI-аудит раунд 2: APP_LOCALE=ru, но директории lang/ не было → Laravel отдавал
сырой ключ «validation.required» во все формы без кастомных messages() (профиль,
создание проекта, реквизиты для оплаты и т.д.). Auth-формы свой messages() имеют.
Добавлен каноничный ru-перевод (laravel-lang) + секция attributes с русскими
именами полей продукта (Имя/Телефон/Лимит лидов в день/ИНН/…).
Верификация: trans(validation.required)→«Поле … обязательно для заполнения.»;
форма профиля в Playwright показывает «Поле Имя обязательно для заполнения.»
вместо «validation.required».
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>