- pragmarx/google2fa@^9.0 для TOTP RFC 6238.
- AuthController::login изменён: при totp_enabled=true НЕ делает Auth::login,
сохраняет auth.pending_user_id+pending_remember в session, возвращает
requires_2fa=true. /me=401 пока 2FA не пройдена.
- AuthController::verifyTwoFactor: читает pending_user_id, верифицирует TOTP
через Google2FA::verifyKey($secret, $code, window: 1) (окно ±1 = 30s).
Success → Auth::login + regenerate + clear pending + last_login_at.
- VerifyTwoFactorRequest: regex /^\d{6}$/.
- /api/auth/2fa/verify публичный (нет session-auth до verify).
Frontend:
- auth-store::login: при requires_2fa=true user остаётся null (иначе
isAuthenticated=true и guard пустит на /dashboard минуя 2FA).
- auth-store::verifyTwoFactor action.
- api/auth.ts::verifyTwoFactor(code).
- TwoFactorView: onMounted redirect на /login если нет pending state;
submit → verify → /dashboard; на error - clear code + focus first cell.
userEmail из auth.user?.email.
Pest +6 (всего 67/67 за 6.97s, 194 assertions): login для 2FA НЕ создаёт
session + verify success/неверный код/без login/валидация формата +
после verify /me=200.
Vitest +3 (всего 142/142 за 10.75s): login pending vs success state +
verifyTwoFactor success/reject. TwoFactorView spec получил setActivePinia
+ requires2fa=true для bypass onMounted-redirect.
PHPStan baseline +26 Pest TestCall warnings (накопительно).
Регресс: pint+stan passed; vitest 142/142; vite build 908ms;
story:build 21/28 за 31.28s; Pest 67/67 за 6.97s.
CLAUDE.md v1.33->v1.34, реестр Открытых_вопросов v1.42->v1.43.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
После исчерпания всех 3 ретраев Laravel вызывает failed(\Throwable $e) —
упавший job сохраняется в failed_webhook_jobs для ручного разбора и
повторного запуска через админку.
Реализация:
- app/app/Models/FailedWebhookJob.php — Eloquent для failed_webhook_jobs
- ProcessWebhookJob::failed() через DB::table->insert (не Eloquent::create)
чтобы обойти RLS: failed-callback запускается вне транзакции воркера,
SET LOCAL app.current_tenant_id не выставлен, политика бы отвергла INSERT.
Запись должна попасть в БД даже в катастрофическом сценарии.
- payload через json_encode(JSON_UNESCAPED_UNICODE) — UTF-8 кириллица
сохраняется
Sentry::captureException оставлен как TODO для production (на dev-стеке
нет DSN).
3 новых Pest-теста:
- failed() пишет упавший job с webhookLogId (через DB::table('webhook_log')
для FK satisfaction)
- failed() работает БЕЗ webhookLogId (NULL ok — soft FK)
- failed() записывает payload с UTF-8 кириллицей корректно
Pest 48/48 зелёные за 4.7 сек. Pint + Larastan чисто.
Webhook-flow покрыт полностью на dev-стеке (за исключением Sentry и
SendNewLeadNotificationJob — Биз-20 Telegram, ждёт настоящего бота).
CLAUDE.md v1.15 → v1.16. Реестр Открытые_вопросы v1.24 → v1.25.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Закрыт пункт «pg_partman replacement» из project_phase1_strategy.md
(расширение pg_partman недоступно на native Windows-стеке без сборки
из исходников).
Реализация:
- app/app/Console/Commands/PartitionsCreateMonths.php
- signature: partitions:create-months {--ahead=2}
- создаёт партиции для deals + supplier_lead_costs (обе по received_at)
- идемпотентна (проверка через pg_class WHERE relkind='r' перед CREATE)
- запускать ежесуточно через Windows Task Scheduler / cron
Smoke-test на dev: --ahead=8 создал 6 партиций (Nov 2026 - Jan 2027) +
12 skipped. После migrate:fresh партиции возвращаются к initial 6.
4 новых Pest-теста в PartitionsCreateMonthsTest:
- создание партиций на 8 месяцев вперёд для обеих таблиц
- идемпотентность (повторный --ahead=5 → 0 created, 12 skipped)
- --ahead=0 создаёт только текущий месяц
- INSERT в deals с received_at в новой партиции корректно роутится
Тесты используют beforeEach/afterEach для cleanup'а через
DROP TABLE ... CASCADE (FK webhook_dedup_keys на партицию propagates).
Pest 45/45 зелёные за 4.9 сек. Pint + Larastan чисто (phpstan-baseline
регенерирован для динамических свойств $this в Pest closure'ах).
CLAUDE.md v1.14 → v1.15. Реестр Открытые_вопросы v1.23 → v1.24.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Закрыт Биз-19 (§10.8.1) на код-уровне. При создании НОВОЙ сделки сервис
DuplicateDetector ищет master по (tenant_id, phone) в окне 24 ч. Если
найден — новой сделке проставляется duplicate_of_id = master.id, баланс
НЕ списывается, SupplierLeadCost НЕ создаётся. ActivityLog пишется с
context.duplicate_of = master.id.
Реализация:
- app/app/Services/DuplicateDetector.php — отдельный сервис:
findMaster(tenantId, phone, ?Carbon $now): ?Deal. Ищет deals с
duplicate_of_id IS NULL и received_at >= now - 24h. Возвращает
первую по received_at ASC или null. WINDOW_HOURS = 24 — константа.
- App\Jobs\ProcessWebhookJob::handle() — после upsertDeal() для новой
сделки вызывает findMaster(). Если master !== создаваемая сделка —
markAsDuplicate(): UPDATE duplicate_of_id + ActivityLog с context.
- DI через app(DuplicateDetector::class) внутри handle() (не в
сигнатуре — для совместимости с прямыми вызовами из Pest без
Bus::dispatchSync).
4 новых Pest-теста:
- master в окне 24ч → дубль, баланс НЕ списывается
- master старше 24ч → НЕ дубль, баланс списан дважды
- дубли изолированы по tenant_id
- ActivityLog для дубля содержит context.duplicate_of
Pest 41/41 зелёные за 4.1 сек. Pint + Larastan чисто.
CLAUDE.md v1.13 → v1.14. Реестр Открытые_вопросы v1.22 → v1.23.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Закрыты 4 TODO в Webhook PoC. Job теперь полностью реализует §5.5
narrative ТЗ за исключением DuplicateDetector (Биз-19) и
SendNewLeadNotificationJob (Биз-20) — отдельные ветви.
5 новых Eloquent-моделей:
- app/app/Models/BalanceTransaction.php — списание lead_charge -1,
type-константы (TYPE_LEAD_CHARGE и т.д.)
- app/app/Models/ActivityLog.php — event=deal.created с
context.source=webhook, event-константы
- app/app/Models/RejectedDealsLog.php — zero_balance ветка вместо
Log::info (payload сохраняется для возможного восстановления)
- app/app/Models/SupplierLeadCost.php — composite PK (id, received_at),
snapshot cost_rub из suppliers, supplier_id resolves через
project_suppliers m2m (первый активный по sort_order)
- app/app/Models/Supplier.php — минимальная для FK target
Job-структура реструктурирована: handle() оркестрирует, делегирует в
logRejection() / chargeNewLead() / resolveSupplierId() / upsertDeal().
Все INSERT'ы в одной DB::transaction — атомарность Ю-2 (deal +
balance_transaction + supplier_lead_cost появляются вместе).
Graceful skip SupplierLeadCost если у проекта нет активного supplier
через project_suppliers + Log::warning. TODO для production: SystemSetting
fallback.
6 новых Pest-тестов в ProcessWebhookJobTest:
- BalanceTransaction lead_charge -1 для новой сделки
- Дубль vid НЕ создаёт BalanceTransaction
- ActivityLog event=deal.created с context.source=webhook
- RejectedDealsLog reason=zero_balance при balance_leads=0
- SupplierLeadCost snapshot cost_rub (helper seedSupplierForProject)
- SupplierLeadCost graceful skip без активного supplier
Pest 37/37 зелёные за 3.9 сек. Pint + Larastan чисто (ide-helper:models
регенерирован для 5 новых моделей).
CLAUDE.md v1.12 → v1.13. Реестр Открытые_вопросы v1.21 → v1.22.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Webhook PoC раскрыл архитектурный пробел в schema v8.6: §5.5-спецификация
делает INSERT в webhook_dedup_keys ДО INSERT в deals (атомарный захват
ключа), но FK был immediate. Решение в две стадии:
1. schema.sql v8.6 → v8.7 — DEFERRABLE INITIALLY DEFERRED на FK
(deal_id, deal_received_at) → deals. ON DELETE CASCADE остаётся
immediate. В bare-транзакции production worker'а решает проблему.
2. Pivot Job на pg_advisory_xact_lock — Pest-тесты с DatabaseTransactions
trait всё равно падали: PG проверяет deferred FK на RELEASE SAVEPOINT,
не на outer COMMIT. Воспроизведено standalone PHP-скриптом, это
PG-семантика subtransactions. Advisory lock работает identically
в любой вложенности транзакций. DEFERRABLE FK сохранён в schema
как defense-in-depth для batch-импортов без savepoint.
Backend стек:
- app/app/Models/Deal.php — composite PK через override
setKeysForSaveQuery (PG требует id+received_at для partition pruning)
- app/app/Models/WebhookDedupKey.php — мини-модель для тестов и debug
- app/database/factories/DealFactory.php — fake данные с received_at
в текущей партиции
- app/app/Jobs/ProcessWebhookJob.php — advisory-lock-based upsert
по §5.5 v8.7. PoC scope: dedup + balance check + project findOrCreate.
TODO для следующих ветвей: BalanceTransaction, SupplierLeadCost,
ActivityLog, RejectedDealsLog, DuplicateDetector (Биз-19).
- app/tests/Feature/DealModelTest.php — 6 тестов composite PK + связи
- app/tests/Feature/ProcessWebhookJobTest.php — 6 тестов: новая сделка,
дубль vid, balance=0, изоляция тенантов, findOrCreate проекта,
ON DELETE CASCADE.
Pest 31/31 за 2.7 сек. Pint + Larastan чисто (phpstan-baseline регенерирован,
scanFiles _ide_helper_models.php добавлен в phpstan.neon).
Документы:
- db/CHANGELOG_schema.md §W (две стадии решения)
- narrative §2.4/§5.5/§6.5/§11 синхронизированы под advisory lock
- Реестр Открытые_вопросы v1.20 → v1.21
- CLAUDE.md v1.11 → v1.12
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Точечная in-place синхронизация SQL/PHP-примеров webhook handler'а в narrative
ТЗ под двустадийную dedup-логику schema v8.6 (CTO-17). 8 разделов, без bump'а
версии файла (как для L13-гигиены 3a9ed71):
- §2.4 Поток данных от Webhook до сделки — описание воркера
- §5.5 ProcessWebhookJob (PHP-код) — Deal::updateOrCreate() заменён на
DB::selectOne с INSERT INTO webhook_dedup_keys ON CONFLICT RETURNING
is_new + раздельные ветки Deal::create() / Deal::where(...)->update()
- §5.6 Таблица крайних случаев (дубль vid)
- §6.5 Идемпотентность импорта (SQL-пример)
- §11 DDL deals — UNIQUE INDEX → INDEX, добавлен полный DDL
webhook_dedup_keys (PK, composite FK на deals(id, received_at)
ON DELETE CASCADE, RLS USING + WITH CHECK)
- §20.12.3 Связь с биллингом тенанта — поток в транзакции 4→5 шагов
- §21.1 Списание баланса при дублях
- §27.1 Итог по идемпотентности
Не трогалось намеренно:
- line 302 (глоссарий «Idempotency» — общая концепция UPSERT)
- line 1238 (диаграмма CSV-импорта — обобщённый текст)
- line 1180 (маппинг колонки id → deals.source_crm_id)
Реестр Открытые_вопросы v1.19 → v1.20 (новый блок «закрыт техдолг»).
Оперативная карта CLAUDE.md v1.10 → v1.11.
Линты: markdownlint 0 errors, cspell 0 issues на изменённых файлах,
lychee 115/115 OK на CLAUDE.md + 2 narrative.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Активны Прил. Н #15 squawk и #16 pgFormatter; фаза 1 по тулчейну
закрыта 13/17 (без #17 pg_partman — Windows native стек).
squawk:
- bin/squawk.exe (npm i -g squawk-cli + копия из ~/AppData/...
/squawk-cli/js/binaries/squawk → bin/squawk.exe; npm-wrapper
не находит spawn-target без .exe на Windows)
- .squawk.toml: 9 правил исключено (5 bootstrap-неприменимых +
4 дизайнных решения проекта). Smoke-test на db/schema.sql — 0 issues.
- lefthook.yml: pre-commit job на staged *.sql
- npm run lint:sql
pgFormatter:
- bin/pgFormatter/ (pg_format + lib/ из v5.9 release tarball,
запуск через Cygwin Perl 5.42.2 из Git for Windows — без
отдельной установки ActivePerl/Strawberry)
- Без авто-fix хука: diff vs db/schema.sql 3255 строк
(UPPERCASE→lowercase для типов, плотный одностроковый стиль,
перетасовка inline-комментариев) — стиль schema.sql ручной,
авто-fix недопустим
- Только ручной режим: npm run format:sql:check (dry-run + diff),
npm run format:sql (пишет в db/schema.sql.formatted для review)
Документы:
- Tooling Прил. Н v1.5 → v1.6 (§0 «Что нового», §3.3 таблица,
§10.1 п.8 ⏸→✅, §11.4 уточнение по Cygwin Perl)
- CLAUDE.md v1.8 → v1.9 (§0 ссылка, §6 текущая фаза 17/28,
колонтитул)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
При первом запуске pre-push hook'ов после установки lefthook (`4eee06f`)
обнаружились 3 проблемы — все легитимны, не в самом lefthook'е:
1. **gitleaks-full-history** ловил 42 хита `ru-phone-unmasked` в HTML-концептах
handoff Платона (liderra_v8_handoff/concepts/v8_*.html и web/v8/v8_*.html).
Это ДЕМО-данные для визуализации, не реальные ПДн. Добавлены в allowlist
.gitleaks.toml: `liderra_v8_handoff/concepts/.*\.html` + `web/v8/.*\.html`
+ `app/composer.lock`.
2. **lychee-links** ловил 21 ошибку «Cannot resolve root-relative link» на
ссылки `/login`, `/register`, `/legal/*` в HTML-концептах. Эти маршруты
появятся только в фазе 2+ (Vue+Vuetify реализация). Сужен glob
pre-push lychee — выкинут `web/**/*.html`. Дополнительно добавлены
`liderra_v8_handoff/concepts` и `web/v8` в .lychee.toml exclude_path
как защита для других вариантов запуска.
3. **2 РЕАЛЬНЫХ битых ссылки** в narrative — спасибо lychee, нашёл:
- `docs/CRM_bp-gr_Инструкция_v8_5.md:6128` ссылался на `brandbook.md`,
но этот файл удалён 08.05.2026 (заменён на `liderra_v8_handoff/docs/
BRANDBOOK_v2.md` v8 Forest). Исправлен относительный путь.
- `README.md:88` ссылался на `docs/README_АРХИВ_v8_4.md`, но переименован
в `_v8_5.md` коммитом `4ffc19a` от 07.05.2026. Поправлено + bump v8.4→v8.5
в подписи.
Финальный smoke-test после правок:
- gitleaks detect (full history): «no leaks found»
- lychee на narrative .md: 122 OK / 0 Errors / 5 Excluded
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Произошло так: при `composer require pestphp/pest pestphp/pest-plugin-laravel
--dev --with-all-dependencies` я не зафиксировал `^3` — composer подтянул
свежайшую Pest v4.7.0 + pest-plugin-laravel v4.1.0. Smoke-test
(`./vendor/bin/pest`) на default-тестах Laravel 11 прошёл 2/2 за 281 ms —
backward-compat с Pest 3 syntax подтверждён. Заказчик 08.05 (поздний вечер)
принял Pest 4 после live-проверки на стеке.
Бонус Pest 4: browser testing (без Dusk), stress testing, mutation
testing v2. Откат дёшев — `composer require pestphp/pest:^3`.
Что сделано:
- composer remove phpunit/phpunit (был direct dev-dep) — phpunit остался
как транзитивная зависимость Pest
- composer require pestphp/pest:^4.7 pestphp/pest-plugin-laravel:^4.1 --dev
- Pest.php создан через `vendor/bin/pest --init` (`tests/Pest.php`)
- `vendor/bin/pest` smoke-test: 2 passed (Unit/Feature ExampleTest), 281 ms
- `vendor/bin/pest --init` упал на интерактивном промпте «Wanna show Pest
some love?» в non-interactive PowerShell — Pest.php к этому моменту уже
создан, нефатально
Reopen(CTO-12): по правилу «явная фиксация переоткрытий» обновлены
3 источника:
- docs/Открытые_вопросы_v8_3.md v1.15→v1.16: блок «Что изменилось в v1.16»,
таблица §0 (CTO-12 переоткрыт+закрыт), запись §3 (Pest 4 + обоснование),
финальный список §X (Pest 4)
- docs/Tooling_v8_3.md v1.2→v1.3: блок «Что нового в v1.3», §3.1 п.4
(Pest 4 в boost:install), §3.4 строка 18 (Pest 4 + бонусы), §6 п.2
(конфликт Pest↔PHPUnit), §10.1 п.9 (процедура установки + warning про
--init на Windows non-interactive)
- CLAUDE.md v1.4→v1.5: §0 источники (Tooling v1.3, Реестр v1.16),
§3.2 строка 18 (Pest 4), §7 п.5 (Pest 4 в boost:install), футер с
историей версий
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Обнаружено 08.05.2026 (вечер): машина — VPS на OpenStack
(Manufacturer = OpenStack Foundation, HypervisorPresent = True).
Provider не пробрасывает nested virtualization в guest VM
(VirtualizationFirmwareEnabled = True на CPU, но KVM на хосте
блокирует VT-x для гостя). Docker Desktop показывает «Virtualization
support not detected, Engine stopped».
Следствие: ранее обсуждённые варианты A (полный WSL2) и B
(Sail на Windows FS) — физически невозможны на этой машине.
Переход на вариант D — native Chocolatey-стек.
Изменения:
- Tooling v1.1 → v1.2: §3.1 п.2/п.3 — Sail удалён из allow-list
Boost. Шапка обновлена под native-стек. Блок «Что нового в v1.2»
с обоснованием.
- CLAUDE.md v1.3 → v1.4: §0 (версия Tooling v1.2), §6 (стек dev =
native PG 16 + Memurai + PHP 8.3), §7 п.3 (Sail отключён в
boost:install). Футер.
Установлено 08.05 вечер:
- ❌ Docker Desktop — удалён (choco uninstall docker-desktop)
- ⏳ PostgreSQL 16.13 — устанавливается (choco install postgresql16)
- ⏳ Memurai Developer 4.1.8 — устанавливается (Redis 7-совместимый,
free до 1GB RAM)
pg_partman/pg_audit/pg_anonymizer на native Windows — ручная
замена. На MVP: партиции через php artisan cron-команду
(Биз-партиции уже в schema v8.5), audit-trigger'ы уже встроены.
Подробное обоснование и триггеры пересмотра — в personal memory
project_phase1_strategy.md (не коммитим).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CLAUDE.md §6 и Объединённый_конспект Часть X указывали
`composer create-project laravel/liderra app`. Такого Composer-
шаблона на Packagist нет. `liderra` — название нашего продукта,
а не пакета. Правильный official-стартер: `laravel/laravel`.
Замечено при smoke-test окружения 08.05 (готовка к фазе 1, вариант B —
Sail на Windows FS). Без этого фикса первая команда фазы 1 упала бы.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Выбран Pest 3 (не PHPUnit). Обоснование:
- datasets лаконично покрывают 14 статусов воронки и 34 RLS-политики
- architecture testing закрепляет правила Claude на код-уровне
(например, integration тесты не моки́руют БД — линт вместо памяти)
- родной для Laravel/Boost (Nuno Maduro в core team) — один guideline
вместо разрыва на boost:install
- Pest на PHPUnit под капотом — откат дёшев
Изменения:
- Открытые_вопросы_v8_3.md v1.13 → v1.14: запись о закрытии в §3,
сводка §0 (CTO 15→16 закрыто, итого 77→78 / 67→68 ✅)
- Tooling_v8_3.md v1.0 → v1.1: §3.1 п.4, §3.4, §6 п.2, §10.1 п.9
- CLAUDE.md v1.1 → v1.2: §0 (версии источников), §3.2 строка 18,
§7 п.5, футер
Импакт: при composer create-project (триггер фазы 1) — вместо
шага «решить Pest или PHPUnit» теперь composer require pestphp/pest
--dev --with-all-dependencies + vendor/bin/pest --init. Guideline
PHPUnit на boost:install отключить.
P0-блокер фазы 1 остаётся один — Б-1 (юр. лицо).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Получен handoff-пакет liderra_v8_handoff/ от дизайнера Платона
(kpd9363@gmail.com) от 07.05.2026 — v8 Forest. Заказчик 08.05 решил
применить только в части дизайна, имени, логотипа. Функционал, состав
страниц и правила (CTO-11, click-wrap, SSO break-glass, 14 статусов
воронки) — без изменений (источник — ТЗ v8.5/schema v8.5).
Что сделано:
- Массовая замена Лидпоток→Лидерра (с учётом падежей: Лидерры/Лидерре)
в 33 файлах (449 вхождений) — все .md/.sql/.json/.toml/.yml/.txt/.html,
кроме исторических упоминаний внутри liderra_v8_handoff/
- Удалён docs/brandbook.md v1.1 — заменён на BRANDBOOK_v2.md из handoff
- Скопированы 13 концептов liderra_v8_handoff/concepts/v8_*.html в
web/v8/. Удалены старые web/01-login.html, 02-dashboard.html,
03-deals.html, index.html (палитра v1.1 deprecated)
- CLAUDE.md v1.0→v1.1: §0 (BRANDBOOK_v2 + DEVELOPER_HANDOFF в источниках),
§2 (палитра Forest, Inter+JBM, Lucide), §5 п.6 (anti-pattern Inter
снят — в Forest Inter наш основной шрифт), §6 (13 концептов в web/v8/)
- Реестр Открытые_вопросы_v8_3.md v1.12→v1.13: добавлена запись о
ребрендинге + 4 точечных расхождений handoff vs ТЗ (статусы воронки,
click-wrap чекбоксы, SSO fallback, axe violations)
- package.json/package-lock.json: name lidpotok→liderra
4 расхождения handoff vs ТЗ (НЕ применены, источник истины — ТЗ/schema):
1. 14 «обобщённых» статусов в BRANDBOOK_v2 §3.6 ≠ 14 slug'ов в
schema.sql:2076 (совпадает 2 из 14: «Переговоры», «Оплачено»).
Источник — schema/ТЗ §6.4 (реселлерская модель из аудита crm.bp-gr.ru,
6 системных + 8 настраиваемых статусов).
2. 3-й click-wrap в v8_login.html («маркетинг-опционально») ≠ ТЗ §1.5/§4.1
(«согласие на ПДн», обязательное, OPEN-Ж-3).
3. SSO в v8_admin.html («локальный 2FA fallback») ≠ ТЗ OPEN-И-13
(break-glass super_admin, локальный 2FA выключен).
4. Заявление «axe-core 4.10.2 — 0 violations» в README handoff — локально
Pa11y 9.1.1 + axe нашёл 81 violation на 10/13 HTML (преимущественно
color-contrast на декоративных separator'ах с --ink-disabled).
Чисто: settings/errors/palette_options.
Что НЕ включено в коммит:
- лендинг/TZ_landing_v1_0.md — untracked, не моя работа в этой сессии
- .tmp/ — gitignored
Что осталось (для следующих сессий):
- Возможное переименование GitHub-репо CoralMinister/lidpotok → liderra
(отдельное решение заказчика)
- Опционально: обратная связь Платону по 4 расхождениям handoff vs ТЗ
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Доделка консистентности архива после реализации v8.5
(коммиты aabf827 / 038a884 / 4ffc19a).
Объединённый_конспект.md:
- Новая Часть IX «v8.3.3 + v8.4 ФИНАЛ + МИГРАЦИЯ + АУДИТ C → v8.5
(06–07.05.2026)» — хроника двух дней (8 подразделов: хронология,
v8.4 финал, миграция на Server 2022, аудит C, реализация v8.5
тремя коммитами, метрики, что осталось, 5 уроков).
Приложение_Б_В_БД_диаграммы_v8_3.md:
- Шапка обновлена: schema v8.5 (54/91/35/4 роли/12 триггеров/4 функции).
- Новая секция «Дельта v8.2 → v8.5» — компактная сводка изменений
schema, поскольку Mermaid-диаграммы фиксируют срез v8.1.
Перерисовка отложена до спринта 0/1 (следуем существующему
disclaimer'у файла).
- Перечислены: +1 таблица (project_user_assignments), +26 колонок
с разбивкой по таблицам и Биз/CTO/OPEN-И источникам, +5 индексов,
+2 WITH CHECK + 1 новая RLS, +6 REVOKE, +1 роль (crm_audit_writer),
+4 функции (audit_chain_hash/audit_block_mutation/
report_jobs_log_export/calc_lead_score), +12 триггеров, ALTER
api_keys.expires_at, закомментированный задел call_recordings.
cspell-words.txt: +KDV (старая машина), +коммита/коммитов.
Артефакт c--Users-KDV-Projects-lidpotok/ (~25 МБ JSONL старых сессий)
удалён из рабочей директории — был в .gitignore, в git не попадал,
коммит не затрагивает.
Lint+spell чистые.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
schema.sql v8.4 (hotfix Z.5.3-Z.5.6):
- outbound_webhook_subscriptions.events: убран DEFAULT '[]' (конфликт
с CHECK jsonb_array_length>0). NOT NULL остался — приложение должно
явно передать список событий ≥1.
- deal_tag_pivot: добавлены ENABLE RLS + CREATE POLICY tenant_isolation
через JOIN на deal_tags(tenant_id) — паттерн как у saas_invoice_items.
- Шапка schema.sql:107-108: «33 политики / 34 защищённых» → «34/34, 1:1»
(после правки выше). CHANGELOG_schema.md: расширена запись Z.5
(Z.5.3-Z.5.6) с финальными метриками.
narrative v8.4:
- §1.4, §3.2, §7.1, §22.6, §27 «33 политики на 34» (5 мест) → «34/34,
1:1». Шапка «Что нового в v8.4»: +3 RLS вместо +2 (с учётом hotfix).
Прил. Б+В:
- Шапка ссылалась на «schema.sql v8.3, 51 таблица» → актуально:
«schema.sql v8.4, 53/86/34/34, при расхождении приоритет за schema.sql».
Добавлены изменения v8.4 в перечень того, что не отражено в ER.
cspell-words.txt: добавлено «партиционированной» (склонение, нужно для
CHANGELOG Z.5.4).
Метрики schema.sql v8.4: 65 CREATE TABLE (53+12), 86 индексов,
34 RLS-политики, 34 ENABLE RLS, 3 роли БД.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- §1.4/§3.2/§22.6/§23.* «29 политик» (4 места) → «33 политики на
34 защищённых таблицах» (расхождение по `saas_invoice_items` —
намеренное, защита косвенно через FK на `saas_invoices`).
- §3.2: ссылка «schema.sql v8.1, раздел 12» → «db/schema.sql v8.4».
- §7.* «обновление updated_at через trigger» (стр. 1594) уточнено:
Eloquent `$timestamps = true` (application-уровень). Trigger в БД
не вводим на MVP, чтобы не дублировать ORM. В schema.sql triggers нет.
- §7.3 — добавлен явный disclaimer: источник истины = `db/schema.sql`,
inline-DDL ниже могут отставать (см. CHANGELOG_schema.md).
- §4.1 (стр. 660-666): добавлен 3-й чекбокс «Согласие с Политикой
конфиденциальности» — синхронизация с §1.5 (3 click-wrap, OPEN-Ж-3).
- §5.1 (стр. 5693): «Только webhook (без CSV в MVP)» → «webhook
основной + CSV-импорт опциональный модуль (раздел 6) + ручное
создание (раздел 10.7)» — синхронизация с §1.5 и §6.
- Заключение (стр. 5878): шапка v8.1 от 03.05.2026 → v8.4 от
06.05.2026, P0-блокеры 9→1 (Б-1), следующие шаги переписаны
с учётом фактического статуса.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Все 15 упоминаний placeholder-домена `crm-аналог.ru` заменены на
`lidpotok.ru` (имя проекта; DO-2 «купить домен» — отдельный P1).
Затронуты: webhook URL, register/verify-email links, wildcard
subdomains, *.lidpotok.ru SSL, staging.lidpotok.ru, status.lidpotok.ru,
admin@lidpotok.ru.
- Таблица §11.1 (стр. 363-364): «Yandex / VK Cloud (prod)» → только
«Yandex Object Storage (prod, по DO-1)». Email: «Mailgun / SendGrid /
собственный SMTP» → «Unisender Go (по Ю-7)».
- §17.7 Library (стр. 2845): «SMTP / Mailgun API» → «SMTP-relay
(Unisender Go, см. Ю-7)».
- §22.* (стр. 4497-4499): список РФ-провайдеров получил пометку
«✅ Yandex Cloud — выбран по DO-1, VK/Selectel — альтернативы Прил. К
не выбраны». Это точнее, чем простой перечень.
Историческая запись «Ю-7 — Mailgun → Unisender Go» в §1.* шапки
оставлена как есть (показывает решение Ю-7).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>