Три группы накопившихся auto-правок (НЕ ручные): 1. markdownlint --fix auto-format (~25 .md в docs/superpowers/, docs/security/marketing-vet.md, docs/adr/015, docs/deploy/lkomega-runbook): MD031/MD032 (blank lines around fence/list) + MD004 (bullet markers `+`→`-`). Содержательных текстовых правок 3: ADR-015 bullet, sprint5d-cleanup bullet, router-discipline trailing space. 2. lefthook 2.1.6 → 2.1.8 (package.json + lock): patch-bump, авто-резолвил npm. 3. Observer runtime (docs/observer/): episodes-2026-05.jsonl +420 строк (текущая активность мозга), STATUS.md regen, .pii-counters / .read-counter тики, +2026-05-24-brain-retro.md note. Цель — разблокировать merge feat/llm-first-router → main (этап 0 плана постановки в боевой). Содержание ветки не трогает.
5.7 KiB
Runbook: импорт проектов lkomega → info@lkomega.ru
Разовая операция на боевом liderra.ru (111.88.246.137). Усыновляет активные
проекты поставщика crm.bp-gr.ru (аккаунт lkomega) как проекты Лидерры под
тенантом info@lkomega.ru. Портал не трогается (никаких save/update/delete).
Plan: docs/superpowers/plans/2026-05-22-supplier-projects-import-lkomega.md
Spec: docs/superpowers/specs/2026-05-22-supplier-projects-import-lkomega-design.md
Деплой команды
Скопировать на сервер в /var/www/liderra/app (бэкап заменяемого SupplierRegions.php):
app/Support/SupplierRegions.php(изменён — добавленmapFromSupplier)app/Services/Supplier/Import/SupplierImportMapper.php(новый)app/Services/Supplier/Import/SupplierProjectImporter.php(новый)app/Console/Commands/ImportSupplierProjectsCommand.php(новый)
cp /var/www/liderra/app/app/Support/SupplierRegions.php /var/www/liderra/app/app/Support/SupplierRegions.php.bak-$(date +%Y%m%d-%H%M%S)
# scp 4 файла...
cd /var/www/liderra/app && php artisan optimize:clear # сброс кэша команд/конфига
Команда — не очередь/воркер, queue:restart не нужен.
Шаг 1 — dry-run (показать план, ничего не пишет)
cd /var/www/liderra/app && php artisan supplier:import-projects --tenant=info@lkomega.ru
Вывод: число проектов к созданию, таблица (тип / идентификатор[маскирован] /
тег / регионы / лимит / площадки B1:id …), список пропусков (unsupported_source
для dop2, regions_exclude, sms_unparseable, already_exists).
Показать заказчику → получить «ок».
Шаг 2 — реальный прогон
cd /var/www/liderra/app && php artisan supplier:import-projects --tenant=info@lkomega.ru --commit
Вывод: Создано: проектов=N, supplier_projects=M, связок=K.
Шаг 3 — пост-проверка
# Число проектов под тенантом (подставить tenant_id info@lkomega.ru):
php artisan tinker --execute="echo App\Models\Project::on('pgsql_supplier')->where('tenant_id', <ID>)->count();"
-
Выборочно сверить 2–3 проекта:
daily_limit_target= сумме площадок; регионы корректны (ГИБДД→Лидерра). -
Проверить целостность площадок каждого проекта (см. оговорку ниже): каждый проект должен иметь столько связок
project_supplier_links, сколько площадок было в группе (обычно 3).php artisan tinker --execute="App\Models\Project::on('pgsql_supplier')->where('tenant_id',<ID>)->get()->each(fn(\$p)=>print(\$p->id.': '.\$p->supplierProjects()->count().PHP_EOL));" -
Подтвердить, что на портале crm.bp-gr.ru НЕ появилось новых проектов (команда его не дёргает).
Атомарность
commit() оборачивает запись каждого проекта в отдельную транзакцию на проде
(DB::connection('pgsql_supplier')->transaction(...) — Project + все supplier_projects +
все pivot-связки группы атомарно). Сбой посреди группы → транзакция откатывается → ни
проекта, ни partial-связок не остаётся, БД консистентна. Уже созданные ДО сбоя проекты
сохраняются (per-group, не per-run).
В прод-команде это включается автоматически: гейт getPdo()->inTransaction() — false на
проде → BEGIN/COMMIT per item; true только под тестовым харнессом SharesSupplierPdo
(общий PDO уже в транзакции) → внутренний BEGIN пропускается, чтобы избежать
«already active transaction» в Pest.
При ошибке посреди прогона — просто запустить --commit повторно: идемпотентность
(already_exists по tenant+signal + firstOrCreate по (platform, unique_key, subject_code)) пропустит уже импортированные проекты и до-создаст оставшиеся.
Откат
Импортированные проекты под тенантом — soft-archive через ЛК или:
App\Models\Project::on('pgsql_supplier')->where('tenant_id', <ID>)
->update(['is_active' => false, 'archived_at' => now()]);
supplier_projects/pivot можно оставить (они указывают на реальные портальные проекты,
их используют и другие потоки).
NB про среду
- На worktree-сборке 2 теста
SupplierPortalClient*Testпадают из-за отсутствия node-модуляplaywright— это известный worktree-only квирк (не регрессия), на боевом/основном checkout сnode_modulesони зелёные. - Larastan: production-код чист; test-only
TestCall/Mockery (квирк #25) добавляются вphpstan-baseline.neonна чистом checkout при интеграции (не из worktree — там дрейф ide-helper искажает счётчики).