Разбивка на 10 задач по TDD: LivenessProbe/DTO, 4 пробы живости
(SMTP/ЮKassa/Jivo/капча), джоба пишет строки живости, email-алерт по
edge-trigger, фронт со статус-текстом. Схема БД не меняется.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Дизайн (брейншторм 02.07): расширяем плитку балансов до наблюдения за всеми
внешними сервисами — деньги И живость. Добавляем Почту (Yandex 360 SMTP,
только живость), ЮKassa, JivoSite, SmartCaptcha. Красная плитка + письмо
на ops@liderra.ru по edge-trigger. Конкурентное поле — вне объёма.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Обоснование (spec) + детальный пошаговый план с полным откатом:
- факты живой базы (7 тест-клиентов, деньги синтетические), keep/delete
- разведка crm.lead.store: визуал новый, начинка (эндпоинты/API/формат лида) та же
- порядок: свап ЛК -> проверка проектов по алгоритму -> чистка кабинета -> чистка базы
- маркировка БОЕВОЙ ПРОД во всех доках + стартовый хук
Секреты/ПДн не включены (почты замаскированы, секрет вебхука как <секрет>).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Task 0.3: guard 'sales' (driver sanctum, provider sales_users). Тест SalesGuardTest 3/3 (valid Bearer→200, без токена→401, мусор→401). Миграция personal_access_tokens (Sanctum Bearer; раньше не было — основной кабинет SPA cookie), DDL через pgsql_supplier, гранты crm_admin_user, CHANGELOG v8.60. Larastan baseline: +SalesGuardTest (Pest TestCall false-pos), SetTenantContext int→mixed (второй provider расширил тип $request->user()). План: admin-db ДО auth:sales. Один эскейп на сессию.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Task 0.1: миграция sales_tariffs/sales_users/sales_client_assignments/sales_attachment_requests/sales_payouts (SaaS-level, без RLS, фильтр по владению в коде). Append-only триггер. Гранты crm_admin_user. DDL через pgsql_supplier. CHANGELOG_schema v8.59. Разрешение хозяина: один эскейп на сессию.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Демо-прототип портала менеджеров по продажам в дизайне Лидерры (Forest),
приведён к реальной модели данных + расширен. Без бэкенда.
- Роли менеджер/начальник, простой демо-вход, переключение роли
- Менеджер: Сводка, Мои клиенты, карточка клиента, Привязать, Мой доход
- Начальник: Сводка отдела, Результативность, Тарифы менеджеров,
Счета (оплата по счёту), Заявки на привязку, Выплаты, Менеджеры
- Тарифы = формула дохода (В1): 3 семейства, конструктор, переход «тариф
прилипает к клиенту» (В12 решён)
- Выбор периода везде (этот/прошлый/позапрошлый/произвольный)
- UX-проход Playwright: ?-подсказки, починена вёрстка подписей
- Спека: docs/superpowers/specs/2026-06-28-sales-manager-portal-brainstorm.md
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Разбор 13 false-positive ru-phone-unmasked: фейк-номера в заглушке агента
(Fake*CompetitorAgent), кликабельных прототипах фичи и демо-экране DetailScreen —
не реальные ПДн, та же категория, что factories/doubles/specs. Добавлены пути
и плейсхолдер-паттерн в .gitleaks.toml. full-history скан: no leaks found.
эскейп: фиксируй (авторизовано владельцем)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Прогон фичи глазами «самого тупого клиента» на изолированной тест-БД (прод не тронут):
все формы, групповые действия, биллинг с реальным списанием, эмуляция поставки Агента, визуал.
Деньги в порядке (300/50 списываются ровно при успехе, без двойных/ложных списаний).
Найдено и ПОЧИНЕНО 6 находок (код — коммит worktree-avtopodbor 1b3683c6).
Независимая перепроверка по коду; одна самокоррекция (общий тост, не «полная тишина»).
эскейп: фиксируй (авторизовано владельцем)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Находки эталон↔реализация и их закрытие (F1 «Предложения», F2 админ-тарифы,
F3 биллинг, M2 чистка; M1 — не баг; N1/M3 — хвосты). Код фичи — отдельным
коммитом в ветке worktree-avtopodbor (793b20a3).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Прод приведён к gitea-main 84dfbc85 один-в-один (rsync-checksum, потерь нет);
бэкап цел; экран Тенанты на серверную пагинацию выкачен; 992 фронт-теста зелёные;
деньги t2=1 839 405₽ целы. Остатки не-git на проде объяснены (.bak-precutover до 03.07).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Свод за заход «закрывай хвосты»: разбор и фикс preflight-sweep/reminder (no-op с 26.06
из-за RLS-роли очереди), self-heal 4 проектов на проде, деньги t2 целы, playwright в deps.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Корень: после переезда на Managed PG очередь ходит под ролью crm_app_user (RLS),
и Tenant::query() в BalancePreflightSweepJob/BalanceFrozenReminderJob отдавал 0 строк
без app.current_tenant_id — биллинг-преflight молча стал no-op с 26.06 (ни заморозок,
ни снятия проектных блоков). Перечень тенантов теперь берётся через pgsql_supplier
(BYPASSRLS), модель грузится внутри per-tenant SET LOCAL контекста. Логика проверена
на боевых данных: t25/t26 снимутся, t27/t30 заморозятся.
Playwright рантайма supplier-портала объявлен в dependencies ровно 1.59.0 под
chromium-1217 + package-lock синхронизирован; деплой ставит его npm ci --omit=dev,
durable к чистке node_modules.
Тесты Billing 18/18, pint/phpstan чисто.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Фундамент под сквозную вложенность: periodRange() читает date_from/date_to
(приоритет) либо preset; Финансы и Клиенты считаются по выбранному периоду через
whereBetween. FE: «Свой период» + два date-поля + «Применить» → date_from/date_to.
Спека дизайна A+B+C+масштаб сохранена. Baseline перегенерирован (getJson тестов).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Дашборд не было видно в сайдбаре — уйдя с него, нельзя было быстро вернуться.
Добавлен первый nav-пункт «Командный центр» → /admin/dashboard (иконка dashboard).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
6-я плитка «👥 Клиенты» со светофором (amber если есть спящие) + drill:
KPI за период (всего активных / новых / заходили / получали лиды / платили),
список новых клиентов (с датой входа/лидами/балансом) и «спящих» (активные
без входа 14+ дней или ни разу = не активировались). Клик по строке → карточка
клиента. Backend: clients() endpoint + clientsTile в summary (cross-tenant через
pgsql_admin); сигналы — users.last_login_at, deals, balance_transactions.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Переиспользование одного DB-билдера в цикле накапливало where-клаузы →
updateOrInsert уходил в INSERT существующей строки → SQLSTATE 23505 на проде
при повторном сборе. Билдер теперь создаётся внутри цикла. + тест на 2 прогона.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- DadataBalanceProvider: эндпоинт profile/balance требует X-Secret вместе с Token
(был HTTP 401 на проде при первом сборе); добавлен заголовок при наличии secret.
- BalanceHealth: отрицательный баланс больше не даёт «−1 дн.» (кламп max(0, days)).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Требование владельца 28.06: прямая ссылка оплаты у каждого сервиса в дашборде
(на планшете). topup_url — статика из конфига; YC строится из billing_account_id.
3 read-only эндпоинта под группой [saas-admin,admin-db] (cross-tenant через
pgsql_admin): L1 сводка (Финансы+Здоровье), L2 Финансы (KPI+внимание+топ),
L2 Здоровье (6 подсистем+светофор). TDD, 83 admin-теста зелёные. baseline:
+3 Pest getJson false-positive. Без маржи, без новых таблиц.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
10 задач по TDD: 3 backend-эндпоинта (summary/finance/health) под admin-db
группой, Vue-экран AdminDashboardView + роут /admin/dashboard, тесты, выкат.
Без новых таблиц; переиспуют существующие detail-экраны как Уровень 3.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Правило продукта: ограничений по количеству проектов нет, лимит только
по балансу и заказанным лидам. Убран гейт tenants.limits.max_projects
в ProjectService::create и показ лимита проектов на дашборде. Поле limits
оставлено как резерв; max_users и api_rps в коде не используются.
Заодно фикс типа в EditProjectDialog.spec: sampleProject типизирован
настоящим Project, source_locked больше не краснит vue-tsc.
Тесты: ProjectsStore 13/13, DashboardSummary 11/11, DashboardView 8/8,
EditProjectDialog 7/7; vue-tsc чисто; pint чисто; vite build ок.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Иерархический дашборд (3 уровня, drill-down). Этап 1: Командный центр +
Финансы + Здоровье (переиспользуют существующие экраны как L3). Этап 2: Лиды +
Заказ у поставщика. Механизм заказа задокументирован по коду (формула
SupplierQuotaAllocator: max(max_спрос, ceil(Σ/3))), без маржи (по решению владельца).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Старый per-instance экспорт больше не используется (заменён глобальным
installMenuRepositionFix). Старый тест-файл удалён - механизм покрыт
installMenuRepositionFix.spec.ts.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Корень дефекта живого клиента 27.06: список Тип лица в окне создания
проекта уезжал за экран, реквизиты не сохранялись 422. Обход вешался
вручную на каждый список и забыт в 3 окнах. Решение - включать обход
автоматически глобально через MutationObserver, убрать ручные пометки.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
AdminTenantsController/AdminBillingController ходят под default-подключением;
новое pgsql_admin (crm_admin_user, srv_bypass) даст им cross-tenant доступ
через middleware-переключатель (следующий коммит). На dev fallback на
DB_USERNAME. Test: pgsql_admin делит базовый pgsql-конфиг, роль из DB_ADMIN_*.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Поправка по факту кода: реально сломаны только AdminTenantsController и
AdminBillingController (ходят под default crm_app_user); Incidents/Pd/
SupplierIntegration/Impersonation уже используют pgsql_supplier и работают.
План: connection pgsql_admin + middleware UseAdminConnection (admin-db).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Корень: после переезда на Managed PG админка ходит под crm_app_user без
cross-tenant доступа; штатная роль crm_admin_user готова, но не подключена.
Способ A: pgsql_admin connection + middleware-переключатель на админ-группе.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Повод: 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>
Магазин Ю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>
Договор Ю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>