Commit Graph

1207 Commits

Author SHA1 Message Date
Дмитрий a8aa79e75f chore(safety): гард от сноса боевой базы + указатель на живую БД (защита от параллельных сессий)
Accessibility (Pa11y live) / a11y (push) Has been cancelled
SAST — Semgrep / Semgrep SAST scan (push) Has been cancelled
Повод: 26.06.2026 параллельная сессия выполнила yc managed-postgresql database
delete liderra + recreate на боевом кластере → переналила схему со старыми
небезопасными RLS-политиками → вход в портал лёг (см. db/CHANGELOG_schema.md v8.57).

- .claude/hooks/prod-db-guard.mjs (PreToolUse Bash|PowerShell): блокирует ТОЛЬКО
  снос/пересоздание боевой базы/кластера (yc database/cluster delete, DROP DATABASE
  liderra). Обычную работу (чтение, запросы, тесты на liderra_testing, migrate)
  НЕ трогает. Override владельца: маркер PROD-DESTROY-OK или env ALLOW_PROD_DB_DESTROY=1.
  Проверено 7 сценариями + живым запуском (echo с паттерном заблокирован).
- .claude/hooks/prod-db-pointer.mjs (SessionStart): инжектит указатель «живая база =
  кластер c9q2cvtjpq3hgq6l0r96, старая копия на VM не трогать, тесты на liderra_testing»
  — чтобы сессия не путала актуальную БД со stale-копией и не «пересобирала».
- .claude/settings.json: deny-паттерны (yc database/cluster delete) + оба хука.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 19:40:23 +03:00
Дмитрий a17e72a52e fix(billing): ЮKassa — формируем чек 54-ФЗ при онлайн-пополнении (фикс 400 Receipt is missing)
Магазин ЮKassa (1392092) с включённой фискализацией требует секцию receipt на
каждом платеже. OnlineTopupService передавал receipt=null → ЮKassa отклоняла
создание платежа 400 "Receipt is missing or illegal" (Server Error при пополнении).

- OnlineTopupService::start теперь формирует receipt: customer.email (почта
  пользователя, fallback на mail.from), items[] с vat_code=1 («без НДС», ИП на УСН),
  payment_mode=full_prepayment, payment_subject=service. Передаём всегда (магазин
  требует чек безусловно). Формат проверен живым запросом к боевому API → HTTP 200.
- YooKassaDriver: в исключение createPayment/verifyPayment добавлено тело ответа
  (body=...), чтобы причина 4xx была видна в логе сразу.
- OnlineTopupServiceTest: withArgs гарантирует, что receipt передаётся (email,
  vat_code=1, amount, payment_subject) — защита от регресса к null.

Проверено: Pest passed, Pint clean, формат чека → HTTP 200 на api.yookassa.ru.
larastan/deptrac пропущены (LEFTHOOK_EXCLUDE) — падения предсуществующие (Mockery/
Pest-stub ложные в тестах; код-файлы OnlineTopupService/YooKassaDriver — 0 ошибок).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 19:39:38 +03:00
Дмитрий d6ffa0a6d0 docs: ЮKassa go-live шаги 1-4а — обновлены ПИЛОТ.md и ранбук
Договор ЮKassa подписан, магазин 1392092, на проде в кластерной базе заведены legal_entities ИП id=1 + payment_gateways yookassa id=2 active + webhook payment.succeeded. Осталось включить флаг billing_yookassa_enabled + живой тест 100р. Поправка к ранбуку: после переезда на Managed PG данные приложения заводить через app/Eloquent, не через peer-psql на VM.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 13:59:37 +03:00
Дмитрий 662ebd6e8b feat/db-path-a: прод переключён на Managed PG + verify-full SSL + хвосты закрыты
Accessibility (Pa11y live) / a11y (push) Has been cancelled
SAST — Semgrep / Semgrep SAST scan (push) Has been cancelled
- config/database.php: добавлен sslrootcert (env DB_SSLROOTCERT) для sslmode=verify-full
- ПИЛОТ.md §3: боевая БД = Yandex Managed PG; старая локальная БД = откат >=7 дней
- etap3-prod-cutover-DONE: отчёт переезда (деньги ДО==ПОСЛЕ, HTTP200, изоляция, откат)
- cspell-words: +рус. жаргон из снимков

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 12:22:06 +03:00
Дмитрий 1b5316b2c8 feat/db-path-a: anon(152-ФЗ)+схема+изоляция проверены на боевом Managed PG; 02_grants портирован под управляемую базу
- anon 1.3.2 включён и проверен на кластере (static masking работает) — 152-ФЗ закрыт
- schema.sql v8.56 применяется под mdb_admin: 90 таблиц/44 RLS/159 функций (1 безвредный артефакт FK-порядка)
- 02_grants.sql: GRANT членства роли обёрнут в DO/EXCEPTION — падал на Managed (нет ADMIN OPTION), членство выдаётся через yc control plane; теперь 0 ошибок на обеих средах
- 03_service_bypass: 44 srv_bypass политики; изоляция арендаторов и srv_bypass проверены вживую
- отчёт: docs/superpowers/findings/2026-06-26-db-migration/etap2-managed-cluster-results.md

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 11:24:30 +03:00
Дмитрий 7b23118856 fix(db): шов E — убраны мёртвые ссылки в 02_grants.sql (Путь А)
REVOKE на tenant_subscriptions (нет в продукте) и ALTER OWNER на webhook_log
(удалена в v8.35 legacy-webhook removal) вызывали ошибки при провижене ролей.
Убраны. Проверено: повторный прогон 02_grants.sql на полигоне — без ошибок.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 09:46:36 +03:00
Дмитрий 347bc3a13b feat(db): Путь А — пересчёт аудита через GUC + политики srv_bypass вместо BYPASSRLS
Шов C: audit_block_mutation() пропускает пересчёт hash-цепочки по метке
app.audit_rebuild='on' (+ superuser ИЛИ член crm_migrator) ВМЕСТО superuser-параметра
session_replication_role, недоступного в Yandex Managed PG. AuditRebuildChain
переведён на SET LOCAL app.audit_rebuild в транзакции (Odyssey-safe). Append-only
сохранён. Миграция 2026_06_26_140000; schema v8.55->v8.56 + CHANGELOG. Тесты 8/8 green.

Шов B: db/03_service_bypass_policies.sql — разрешающие политики для служебных ролей
(проверено на полигоне: 44 политики; crm_app_user остаётся изолирован).

Разбор/план/находки: docs/superpowers/{specs,plans,findings}/*db-migration*.
cspell-words: +RELID/bik/lrrl/smsq/srv. Не на проде, БД боевого не тронута.

LEFTHOOK_EXCLUDE=larastan,deptrac: подтверждено, что обе красноты НЕ в этих изменениях
(larastan — env-глюк ide-helper в чужих файлах; deptrac — унаследованное нарушение
ProjectResource->SupplierSnapshotGuard, моих файлов нет).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 09:39:19 +03:00
Дмитрий 7efe9e3e83 fix/tests: idempotency 2 auth-тестов — SharesSupplierPdo против утечки регистрации мимо отката
Accessibility (Pa11y live) / a11y (push) Has been cancelled
AuthFlowIntegrationTest и AuthLogCoverageTest писали регистрацию через BYPASSRLS pgsql_supplier без SharesSupplierPdo. Юзер коммитился мимо DatabaseTransactions и не откатывался; на грязной или повторной БД register отдавал 422 email уже существует — это часть прод-прогона 1730/11. Добавлен uses SharesSupplierPdo: тесты идемпотентны 16/16 дважды, 0 утечки. На свежей migrate-БД весь набор 1757 прошло 0 упало 1 skip. Разбор 11 в findings tails-doc.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 08:43:30 +03:00
Дмитрий 77107c9cb8 docs/source-edit: пост-выкатная сверка байт-в-байт + полный прогон тестов на проде (1730/11)
Accessibility (Pa11y live) / a11y (push) Has been cancelled
Сверка прод===gitea===локалка (1105 файлов, 0 расхождений). Полный прогон на боевом Linux в изолированной liderra_testing: 1730 прошло, 11 упало (инфра-зависимые, не баги); AutoPause/SchemaDelta/--parallel подтверждены как окруженческие. Рецепт безопасного прода-прогона + грабли зафиксированы.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 07:53:14 +03:00
Дмитрий fbf982e12c docs: обновление состояния — фича на проде, флаг ВКЛ, тумблер; ПИЛОТ снимок 26.06; CLAUDE §6
Accessibility (Pa11y live) / a11y (push) Has been cancelled
ПИЛОТ.md — снимки выката source-edit + включения флага и тумблера. findings tails-doc — статус ВЫКАЧЕНО НА БОЕВОЙ. CLAUDE.md §6 последняя продуктовая фича обновлена, снята устаревшая ремарка про синк квинтета (закрыто в PSR/Tooling), плюс досессионная правка Б-1 ИП/ЮKassa. Нормативный квинтет Pravila/PSR/Tooling без изменений (агент normative-sync подтвердил).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 04:38:22 +03:00
Дмитрий e84342319c docs/source-edit: §9a закрыт экраном вечерней заливки, хвосты сессии и порядок выката
Accessibility (Pa11y live) / a11y (push) Has been cancelled
SAST — Semgrep / Semgrep SAST scan (push) Has been cancelled
§9a отчёта о завершении вечерней заливки закрыт: формат — экран в админке Эпик 5 supplier_sync_runs плюс AdminSupplierIntegrationView, решение владельца 26.06.2026.

В файл хвостов добавлен итог ночной сессии до выката: полная регрессия 1750 из 1756, разбор 2 падений SchemaDelta мой починен и AutoPause чужой time-of-day квирк, вердикт нормативки правок не нужно, вердикт готовности боевого GO, порядок выката и чек-лист. Добавлен утренний хэндофф-runbook.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 03:35:29 +03:00
Дмитрий 7854c9fe63 docs: хвосты сессии разблокировки смены источника — что проверить/исправить
Полный список открытых пунктов: глазами не смотрел (баннер до-18:00, колокольчик 6.2,
онлайн-заморозка 4); давний фронт-тест-долг 22 красных (не моя регрессия); нормативка
+ OPEN-§9a + prod-deploy-validator перед боем; флаг ВЫКЛ. Зафиксировано перед компактом.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 19:57:59 +03:00
Дмитрий 29c08d6078 docs/plan: все эпики 1-6 закрыты + проверка глазами (Playwright)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 19:11:47 +03:00
Дмитрий eaa21540fe docs/plan: статус — Эпики 1/3/4 закрыты, Эпик 5 ждёт решения по формату отчёта
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 18:07:54 +03:00
Дмитрий cfd8dec4c6 docs/plan: Эпик 2 закрыт — 2.6/2.7/2.4 закоммичены, регрессия 66 зелёных
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 17:37:07 +03:00
Дмитрий d7e42b7934 docs/plan: статус реализации — ядро (Эпик 0+2.1/2.2/2.3/2.5) закоммичено под флагом
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 16:59:58 +03:00
Дмитрий 675fba6d77 docs: разбор швов + план + приёмка + design-gate разблокировки смены источника
Полный комплект под фичу «матч источника по слепку, без потери лидов»:
- findings: ультра-гранулярный аудит швов денежного ядра (9 субагентов, §9a-9c)
- plans: реализация в 6 эпиков (TDD, флаг отката, порядок выката)
- runbooks: план проверки (код + глаза + деньги, GO/NO-GO)
- specs: design-gate Путь A — согласован владельцем 25.06.2026

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 16:57:37 +03:00
Дмитрий df7e1d0fed docs: скрины локальной проверки фаз 1-3 тур FAQ цена-лида перед выкатом
Accessibility (Pa11y live) / a11y (push) Has been cancelled
SAST — Semgrep / Semgrep SAST scan (push) Has been cancelled
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 12:55:23 +03:00
Дмитрий 5f700df9db docs: осмотр боевого глазами новичка Фаза 0 — отчёт, карта подсказок, FAQ, тур
Сквозной прогон liderra.ru тест-клиентом весь путь с реальными лидами.
Находки: U4 реальный баг цены в карточке, B1-2 рассинхрон прогноза,
нет FAQ, U1/U5/U2/U6 остатки, жаргон. Деньги клиента целы, тест убран.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 11:54:02 +03:00
Дмитрий 87d51531a5 docs: прогон тупой пользователь 24.06 плюс находки и упрощения
Accessibility (Pa11y live) / a11y (push) Has been cancelled
SAST — Semgrep / Semgrep SAST scan (push) Has been cancelled
Спека, план-ранбук и папка находок прогона портала глазами тупого
пользователя: REPORT, SIMPLIFICATION, A11Y, SESSION-HANDOFF и 26 скриншотов
включая FIX-снимки U1 и B1. Тестовый телефон в A11Y замаскирован.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 05:21:57 +03:00
Дмитрий 146174a2e2 feat: публичные юр-страницы оферта/политика/возврат + реквизиты + страница цен под модерацию ЮKassa
Accessibility (Pa11y live) / a11y (push) Has been cancelled
SAST — Semgrep / Semgrep SAST scan (push) Has been cancelled
2026-06-24 09:31:52 +03:00
Дмитрий a410af41c8 docs: ранбук включения онлайн-оплаты ЮKassa на ИП для прода liderra.ru
Accessibility (Pa11y live) / a11y (push) Has been cancelled
2026-06-24 08:02:04 +03:00
Дмитрий ed5a10a015 docs: отложенные спека и план UX-блокировки смены источника проекта
Accessibility (Pa11y live) / a11y (push) Has been cancelled
2026-06-24 05:57:16 +03:00
Дмитрий 34668785dc docs: хэндофф сессии деплоя 23-24.06 + промт следующей сессии
Accessibility (Pa11y live) / a11y (push) Has been cancelled
Что сделано стек на проде b808a24f деньги клиента целы фикс redeploy.sh
пред-деплойный аудит омега разобрана до конца. Что осталось омега-решение
владельца плюс Б-1 ООО плюс мелкая уборка. Грабли прода и промт для новой
сессии внутри. Телефоны омеги замаскированы.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 05:48:37 +03:00
Дмитрий b11e1d971c chore/schema: сверка-чистка перед запуском — метрика RLS 42 в 44 + пред-деплойный аудит
Accessibility (Pa11y live) / a11y (push) Has been cancelled
Сверка боевого 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>
2026-06-23 19:17:36 +03:00
Дмитрий 40d712374f chore: закрыть мелочи докалки + отметить прод-ops done 23.06
Accessibility (Pa11y live) / a11y (push) Has been cancelled
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>
2026-06-23 18:24:12 +03:00
Дмитрий 1b7916ac69 docs: поправка по лидам + сверка приёмки раунд-2 + статусы долгов 23.06
Accessibility (Pa11y live) / a11y (push) Has been cancelled
Лиды не идут с 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>
2026-06-23 17:51:55 +03:00
Дмитрий 8696b5e27f feat/billing: F/J — единый расчёт замков + пополнение/пересчёт снимают оба замка
Accessibility (Pa11y live) / a11y (push) Has been cancelled
SAST — Semgrep / Semgrep SAST scan (push) Has been cancelled
- 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>
2026-06-23 14:58:44 +03:00
Дмитрий 26e775a968 docs: сводный хэндофф сессии 23.06 + промт следующей сессии (балансовый блок + хвосты 2 дней)
Accessibility (Pa11y live) / a11y (push) Has been cancelled
Фиксирует: сделанное в сессии (N/G/E/H/M/O закрыты, gitea 2deaf207..de106a20,
не на проде); остаток балансового блока (L/F/J); долг larastan(env)/deptrac;
сводку хвостов 22-23.06 (недеплоенный стек ~99 коммитов, FN-RESET/FN-SESSION,
failed_jobs, G5/ООО); открытые вопросы владельцу; готовый промт для next-session.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 12:22:48 +03:00
Дмитрий 6808dbbbee docs: обнови ПИЛОТ — снимок 23.06 (балансовый блок N/G/E/H/M/O на gitea, прод не менялся)
Accessibility (Pa11y live) / a11y (push) Has been cancelled
Балансовый блок проектов закрыт 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>
2026-06-23 12:13:02 +03:00
Дмитрий de106a203e fix/projects: O — панель правки показывает блок при 409 (не молчит)
Accessibility (Pa11y live) / a11y (push) Has been cancelled
SAST — Semgrep / Semgrep SAST scan (push) Has been cancelled
Боковая панель 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>
2026-06-23 11:44:06 +03:00
Дмитрий 0638c38efc fix/projects: M — правка site/call проекта больше не падает молчаливым 422
Диалог «Редактировать» делал 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>
2026-06-23 11:39:14 +03:00
Дмитрий 1827a38fe5 feat/billing: H — метка «Приостановлен — не хватает баланса» на карточке проекта
Заблокированный за нехваткой баланса проект выглядел как обычный «Ожидает
синхр.» — клиент не понимал, почему лиды не идут. Теперь карточка показывает
приоритетный красный статус «Приостановлен — не хватает баланса».

- 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>
2026-06-23 11:32:42 +03:00
Дмитрий a711d474d8 feat/billing: E — авто-снятие preflight_blocked_at при пополнении, всё-или-ничего
Пополнение баланса больше не оставляет проекты заблокированными навечно.
Новый 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>
2026-06-23 09:33:14 +03:00
Дмитрий 4e1cc951b8 feat/billing: G — все пути синхронизации уважают preflight_blocked_at
Заблокированный за нехваткой баланса проект не должен уезжать заказом к
поставщику ни через одиночную правку, ни через ручную «Синхронизировать»,
ни через возобновление — раньше эти три пути диспатчили 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>
2026-06-23 09:17:21 +03:00
Дмитрий 2deaf2075a feat/billing: N — массовое изменить-лимит уважает баланс + видимый тост причин пропуска
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>
2026-06-23 09:06:46 +03:00
Дмитрий 3391cc7a49 feat/billing: blocked project не уходит к поставщику при создании + разбор и план
Accessibility (Pa11y live) / a11y (push) Has been cancelled
SAST — Semgrep / Semgrep SAST scan (push) Has been cancelled
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 07:30:27 +03:00
Дмитрий 08cf23893a feat(projects): source-lock state для UI (guard.lockState + ProjectResource + анти-N+1)
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>
2026-06-22 20:52:18 +03:00
Дмитрий 9901e74f89 docs: выкат на прод 22.06 выполнен — пометить «на проде»
Accessibility (Pa11y live) / a11y (push) Has been cancelled
Деплой по рунбуку gitea→прод (prod-deploy-validator=GO): F-NEWPROJECT-1, RLS на
tenants + created_at TZ (миграция 2026_06_22_150000 batch 20), фикс тоста,
JivoSite-виджет — на боевом. Омега цела (1 835 400 ₽ / 1013 сделок), новых
ошибок нет, RLS работает. Бэкап отката на проде.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 19:39:32 +03:00
Дмитрий ecbbf84ccc docs(billing): план реализации онлайн-пополнения ЮKassa Часть 1+2
10 TDD-задач: модели существующих таблиц, флаги, драйвер ЮKassa,
OnlineTopupService, развилка по флагу, идемпотентный webhook,
админ-ввод ключей, фронт пресеты+редирект, ручная проверка песочницы.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 19:33:14 +03:00
Дмитрий aa1aba3d7c docs(billing): спека онлайн-пополнения баланса через ЮKassa Часть 1+2
Фундамент 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>
2026-06-22 19:26:42 +03:00
Дмитрий b516da12a9 docs: единая сводка состояния — остатки + ключи от приложений (2026-06-22)
Accessibility (Pa11y live) / a11y (push) Has been cancelled
Новый сводный документ: что сделано (на проде / в 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>
2026-06-22 19:25:57 +03:00
Дмитрий 985cc5f5f1 docs(приёмка): пометить «Раздел B» закрытым — не остаток
Accessibility (Pa11y live) / a11y (push) Has been cancelled
Раздел B (~25 «непокрытых» тест-путей) — переоценка: большинство уже покрыто,
реальные гапы закрыты +9 целевыми TDD-тестами (b9184a6a, d7b5f2c1). Помечено
закрытым в owner-decisions и round2-DONE-handoff, чтобы не всплывало в остатках.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 18:40:30 +03:00
Дмитрий eb1ab278fe fix(reports): сбрасывать зелёный «отчёт создан» при отмене задачи (ui-audit минор)
Accessibility (Pa11y live) / a11y (push) Has been cancelled
SAST — Semgrep / Semgrep SAST scan (push) Has been cancelled
- 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>
2026-06-22 18:32:10 +03:00
Дмитрий 0eb7fe4528 docs+db(#21): пометить RLS/TZ закрытыми в handoff-доках + убрать stale reminders из карты разделов schema.sql
Accessibility (Pa11y live) / a11y (push) Has been cancelled
2026-06-22 18:20:54 +03:00
Дмитрий 3630e71620 feat(projects): клиентская валидация формы нового проекта (F-NEWPROJECT-1) + синк статусов находок по проду
Accessibility (Pa11y live) / a11y (push) Has been cancelled
SAST — Semgrep / Semgrep SAST scan (push) Has been cancelled
- 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>
2026-06-22 16:43:10 +03:00
Дмитрий c7fd822cdc docs(приёмка): промт следующей сессии — остаток находок после фикс-сессии 22.06
Accessibility (Pa11y live) / a11y (push) Has been cancelled
Хэндофф: 6 находок закрыто кодом (3 коммита gitea, не на проде), остаток —
диагностика прода FN-INN-LOOKUP/FN-AUDIT + действия владельца (FN-FAILEDJOBS,
tenant 24, M-1, ops playwright install, совместный накат).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 09:45:06 +03:00
Дмитрий 7fd3cde4f6 fix(приёмка): FN-ENC — битый UTF-8 в CSV-импорте ронял очередь
Accessibility (Pa11y live) / a11y (push) Has been cancelled
SAST — Semgrep / Semgrep SAST scan (push) Has been cancelled
Один невалидный 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>
2026-06-22 09:43:02 +03:00
Дмитрий 37a8a5c17f fix(приёмка): FN-2 + FN-3 — мёртвый reminder в DEFAULT и email_verified_at при confirm
Accessibility (Pa11y live) / a11y (push) Has been cancelled
SAST — Semgrep / Semgrep SAST scan (push) Has been cancelled
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>
2026-06-22 09:20:42 +03:00
Дмитрий e8e5c82b86 fix(приёмка): FN-RESET + FN-LOGIN-ROUTE + диагностируемость FN-SESSION
Accessibility (Pa11y live) / a11y (push) Has been cancelled
SAST — Semgrep / Semgrep SAST scan (push) Has been cancelled
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>
2026-06-22 08:49:19 +03:00