# ЭТАЛОН проекта Лидерра

Единый снимок **истинного состояния проекта** — чтобы не путаться между сессиями.

**Правило использования:**

- В начале работы — свериться с этим файлом.
- Волатильную часть (§1–§4: git, что запущено, временное) перед рискованными действиями
  **перепроверять реальной командой**, не доверять снимку вслепую.
- Обновляется по команде заказчика **«обнови эталон»**.

**Снимок снят:** 21.05.2026 (день, после фичи «удаление проектов вместо архива + дедуп источника + человеческие ошибки» — 10 коммитов FF в main; volatile §1–§4 пересверены). **(Частичное обновление 16.06.2026 — см. блок ниже; §2–§6 не пересверены.)**

## ⚠️ Обновление 16.06.2026 (сессия под стеной «роутер-наставник»)

- **Git:** ветка `main`, HEAD **`1e524022`**. origin `CoralMinister/lidpotok` — **SUSPEND** (push 403);
  main ahead 357 / behind 57 от origin/main. **Gitea-бэкап жив**, main доставлен
  (`cc82665→1e524022`, `https://111.88.252.149.nip.io/liderra/portal`). **Не закоммичено:** доки
  этой сессии (GUIDE-правка, баг-файл наставника, F-1 runbook, хэндофф, спеки/планы).
- **Сделано:** F-4 larastan baseline закоммичен `317125e3`; push в Gitea; урок «пуш через стену»
  в GUIDE + баг-файл наставника (для claude-brain); F-1 deploy-runbook.
- **Lead-region:** код **уже в main** (снимок прод↔локалка 15.06 устарел) — merge не нужен/вреден.
  Единственное, чего нет в main — 500 МБ сырых CSV Россвязи (tails); коммитить их не нужно.
- **F-1 (CVE):** запатчен локально (`composer.lock`: laravel v13.15.0, guzzle/psr7 2.11.0 и др.);
  прод на уязвимых версиях — ждёт деплоя по `docs/superpowers/plans/2026-06-16-f1-cve-deploy-runbook.md`.
- **Полный итог + промт следующей сессии:** `docs/superpowers/plans/2026-06-16-session-close-handoff.md`.
- ⚠️ **§2–§4 (env/demo) и §6 (рабочие нити) ниже — от 21.05.2026, в сессии 16.06 НЕ пересверены.**

---

## 1. Git — состояние (волатильно)

- Git-корень репозитория — папка `Документация/` (**не** `app/`).
- Remote: `CoralMinister/lidpotok` (приватный).
- Текущая локальная ветка: **`feat/project-migration-redesign`**.
- Локальный HEAD = origin/main HEAD = **`22e81cc`** (chore(gitleaks): allowlist Nuclei docs false-positive — tail коммит моего эпика «удаление проектов»; сверять `git log -1 origin/main`).
- Push паттерн: `git push origin <ветка>:main`. Мой push 21.05 (день): `3b6992d..22e81cc` (10 коммитов FF — спека+план+7 имплементаций+gitleaks-allowlist); pre-push gitleaks-full 1155/0, lychee 64/0.
- Pre-push lefthook прошёл чисто после добавления `.gitleaksignore` (Nuclei docs `-u http://...` ловился rule `curl-auth-user` — false-positive из параллельной ветки `worktree-a8-infosec-tooling`, добавлен fingerprint).
- **Незакоммиченного нет** (фикс + тест запушены).
- Прочее незакоммиченное: `docs/observer/STATUS.md` + `episodes-2026-05.jsonl` (hook-артефакты brain governance, не мои); untracked artifacts (см. §4).
- Остатки от rebase (безопасно): `stash@{0}` с не-моими hook/parallel-артефактами (+5 других parallel-стэшей); `/tmp/plan4-rebase-bak/` — устаревшие untracked-копии 2 observer-файлов (committed-версии origin/main авторитетнее).

> ⚠️ Снимок git в начале сессии бывает **устаревшим** (параллельные сессии скачут по веткам).
> Истина — `git branch --show-current` + `git log -1 origin/main`.

## 2. Dev-окружение (native Windows, без Docker)

| Компонент | Состояние |
|---|---|
| PostgreSQL 16 | служба `postgresql-x64-16` Running; БД `liderra` (данные ВОССТАНОВЛЕНЫ: `db:seed` + 5 учёток; 5 pending-миграций эпика докатаны → факт. **v8.26**); `liderra_testing` (CI test DB); dev-юзер `postgres` (superuser → RLS обходится) |
| Redis | Memurai (служба `Memurai`) Running, порт 6379 |
| PHP | 8.3, `C:\tools\php83\php.exe` |
| Портал | **ЗАПУЩЕН** (`php artisan serve` на 127.0.0.1:8000) |
| Очередь | **ЗАПУЩЕНА** (`php artisan queue:work redis`) |
| Шедулер | **НЕ запущен** → CSV reconcile авто-крон (каждые 30 мин) не идёт; проверялся вручную |
| Cloudflare-туннель | **ЗАПУЩЕН** (`tools/cloudflared.exe` → `https://graph-directory-ana-realize.trycloudflare.com` → :8000; quick-tunnel, random URL) |
| Фронтенд | **PROD-сборка** (`app/public/hot` отсутствует → `app/public/build/`) |
| MCP-серверы node | Redis MCP (×5+ дублей), Playwright MCP, 21st-dev/magic, @upstash/context7-mcp — все висят как dev-tooling |

> ⚠️ После правок фронтенда (`app/resources/js/`) — **`npm --prefix app run build`**.
> PID процессов меняются — `Get-CimInstance Win32_Process -Filter "Name='php.exe'"` для свежих.

## 3. Что запущено временно

- На момент снимка 20.05.2026 (день) **подняты для приёма лидов**:
  - portal `serve` :8000 — ДА
  - queue worker (`queue:work redis`) — ДА
  - scheduler (`schedule:work`) — НЕТ (CSV reconcile авто-крон не идёт; запускать вручную при необходимости)
  - cloudflared tunnel — ДА (`https://graph-directory-ana-realize.trycloudflare.com`)
- Supplier `/admin/user/api` настроен на текущий туннель + secret, статус Активный; supplier-сессия в Redis (`supplier:session`, TTL 6h).
- При рестарте машины/туннеля URL меняется → заново: `tools/cloudflared.exe tunnel --url http://localhost:8000` + обновить URL у поставщика (поле `#user-us_api_url`), + при необходимости `php artisan supplier:session:refresh`.

## 4. Временное / демо — НЕ постоянное, под финальную очистку

- **Демо-данные dev-БД `liderra` (актуальный статус 20.05.2026 вечер):** 5 тенантов + 5 учёток, каждая в своей компании. Разбивка выполнена скриптом `app/storage/_demo_split_tenants.php`. Tenant 1 (demo, Demo Admin) = 4 проекта; tenants 2-5 (ivan/anna/petr/mariya-demo) = пустые. Пароль у всех: **password**. Для восстановления с нуля: `php artisan db:seed` → `php artisan tinker storage/_demo_5users.php` → `php artisan tinker storage/_demo_split_tenants.php`.
- **Каналы миграции проверены вживую 20.05.2026 (все 3 ✅):** webhook (лид→Deal+списание), CSV reconcile (скачано 169 строк с crm.bp-gr.ru), экспорт (проект create+delete у поставщика, без следов). После проверки тест-данные вычищены до чистого демо; `supplier_webhook_secret` = рабочий 48-симв. Прочие untracked `_demo_*.php` (`_demo_reroute`/`_demo_day_setup`/`_demo_user`/`_demo_create_projects`/`_demo_migrate_b1site`) — временные, под Task 9 cleanup.
- Webhook-тест артефакты: `.env` `SUPPLIER_LOGIN`/`SUPPLIER_PASSWORD`, `app/bootstrap/app.php` trustProxies, `system_settings.supplier_webhook_secret`, `tools/cloudflared.exe`, DNS-правки (`tools/.dns-backup.json`).
- Untracked снимки и YAML в корне (`*.png`, `rt-*.yml`, `user-api-page.yml`, `supplier-api-configured*.png`) — артефакты recon/тестов разных сессий.
- Untracked plans/notes/снимки от параллельных сессий:
  - `docs/superpowers/plans/2026-05-18-webhook-real-supplier-integration.md`
  - `docs/superpowers/plans/2026-05-19-quirk-fixes-epic.md`
  - `docs/superpowers/{plans,specs}/2026-05-20-a1-backend-tooling*.md`
  - `docs/superpowers/{plans,specs}/2026-05-20-observer-chain-attribution*.md`
  - `docs/observer/notes/2026-05-20-brain-retro-v2.md`
  - `brain-dashboard-*.png` (4 снимка) + stray `app/app/resources/` (вложенный артефакт)
- Orphan worktree-директория `.claude/worktrees/supplier-session-fix/` (gitignored).
- Процедура очистки демо-артефактов webhook-теста: Task 9 плана `docs/superpowers/plans/2026-05-18-webhook-real-supplier-integration.md`.

## 5. Ключевые факты (стабильно)

- Структура: git-корень `Документация/` · Laravel-приложение `app/` · фронтенд `app/resources/js/`
  · сборка фронтенда → `app/public/build/` · схема БД `db/schema.sql` (**фактическая v8.27** —
  21.05.2026 дропнута колонка `projects.archived_at` (фича архива заменена настоящим удалением);
  v8.26 наследие — Plans 1+3 эпика project-migration-redesign: `supplier_projects.subject_code` +
  `project_supplier_links` pivot + `deals.subject_code` + seed `supplier_export_mode` + CHECK chk_deals_subject_code.
  Header v8.27 в commit `07d7387`; CHANGELOG_schema.md содержит v8.27 + v8.26 entries).
- Стек: Laravel 13 + PHP 8.3 · Vue 3 + Vuetify 3 (не Tailwind/Inertia) · PostgreSQL 16 · Redis.
- **Демо-доступ к порталу:** 5 изолированных компаний — `admin@demo.local` (Demo Tenant, 4 проекта) + `manager1@demo.local` (Компания Ивана) + `manager2@demo.local` (Компания Анны) + `manager3@demo.local` (Компания Петра) + `manager4@demo.local` (Компания Марии). Пароль у всех **`password`**. Каждый логин видит только своё. Админка `/admin/*` в local открыта любому залогиненному (`EnsureSaasAdmin` — стаб local/testing).
- Поставщик лидов: `crm.bp-gr.ru` (учётка в `.env` `SUPPLIER_*`); портал — Vue 2 + Element UI;
  `/admin/visit/rt` «Мои проекты» (форма add-project — Element UI внутри Vuetify v-dialog).
- Оперативная карта проекта: `CLAUDE.md` (правится только плагином `claude-md-management`).
- Память Claude: индекс `MEMORY.md` — подгружается каждую сессию.

## 6. Текущие рабочие нити (детали — в памяти Claude)

- **Удаление проектов вместо архива + дедуп источника + человеческие ошибки — DONE+ЗАПУШЕНО** (21.05.2026 день,
  `3b6992d..22e81cc`, 10 коммитов FF в main). По заказу: (1) кнопка «архивировать» заменена на настоящее удаление
  (если по проекту есть сделки — блок с понятным сообщением, иначе hard delete + удаление донора у поставщика
  с учётом шеринга — пере-синк остатка, если другие клиенты ещё пользуются источником); (2) подтверждена возможность
  шеринга одинаковых источников между разными клиентами (модель не меняется); (3) добавлен запрет дубля источника
  внутри одного клиента (раньше не было); (4) сырой `SQLSTATE` больше не уходит в UI — глобальный handler
  `QueryException` + app-level pre-checks (имя/источник) с понятными сообщениями. Колонка `projects.archived_at`
  и все `scopeActive/scopeArchived/->archived()` снесены, миграция `2026_05_21_000000`, schema bump v8.26→**v8.27**.
  Новый job `App\Jobs\Supplier\DeleteSupplierProjectJob` — удаление/пере-синк донора при шеринге.
  Регрессия: Pest filter=Project **229/228+1sk/0**, Vitest **896/3sk/0**, vue-tsc 0, Vite build OK, Pint/Larastan 0.
  Живая проверка 5 сценариев (имя/источник дубль / sharing / удаление пустого / блок при сделках) — все ✓ с чисткой.
  Спека: `docs/superpowers/specs/2026-05-21-project-delete-dedup-errors-design.md`, план:
  `docs/superpowers/plans/2026-05-21-project-delete-dedup-errors.md`. Память: `project_delete_dedup_errors.md`.
- **Сквозной чек-лист всего портала + 6 фиксов — ЗАПУШЕНО** (21.05.2026, `a0e18a1..b7466eb`). Прогон всех ~30 экранов
  (Playwright) + полная регрессия (Pest 1010/0, Vitest 895/0, pint/larastan/vue-tsc/build чисто). Портал здоров: все
  экраны рендерятся, консоль чистая. Найдено и исправлено 3 UI-бага: (1) дашборд здоровался захардкоженным «Доброе утро,
  Иван» → реальное имя из auth-store + по времени суток (`ba49805`); (2) топбар на `/reminders` и `/import` показывал
  «Страница» вместо названия → fallback на `route.meta.title` (`17e3c04`); (3) админ-меню показывало mock-счётчики
  «Тенанты 142 / Инциденты 3» вместо реальных (5 / 0) → убраны (`b7466eb`). Плюс 3 stale эпик-теста (см. ниже). Все
  фиксы по TDD (RED→GREEN) + проверены вживую в браузере. **Не баги (на решение заказчика):** мета-цифры дашборда
  («+3 лида», «2 248 ₽») — демо-заглушки, не подключены к API; тарифная сетка датируется «с 1970-01-01» (косметика);
  колонка «Город» пустая у webhook-лидов (старый открытый вопрос); 5 pre-existing eslint-придирок в чужих spec-файлах
  (известный долг, вне glob lefthook). Чек-лист портала — в истории чата.
- **`saveProjectMultiFlag` matching — ИСПРАВЛЕНО И ЗАПУШЕНО** (`a0e18a1`). Реальный crm.bp-gr.ru возвращает `rt-projects-load` с `name='B[123]_<id>'` и идентификатором в поле `content`, а старое сравнение `$p['name'] === $dto->uniqueKey` никогда не совпадало с реальным ответом → `idMap=[]` → `SyncSupplierProjectJob` молча выходил, а на портале копились orphan-группы. Фикс: matching по `$p['content'] ?? $p['name']` (fallback на name для мок-тестов). Объясняет прошлую ремарку «проект 5 вылечен вручную — усыновлены 3 портальные записи»: тот же баг, заказчик обходил руками. Verified: 16/16 Pest supplier-suite + E2E live на crm.bp-gr.ru + multi-tenant прогон формулы `computeOrder` (max(max, ceil(Σ/3))) и cap=3 distribution. Память: `project_supplier_integration.md`.
- **Сквозной прогон чек-листов экспорта + multi-tenant формулы (20.05 вечер-5)** — отдельный отчёт в чате. Все случаи (Create/UPDATE regions/limit/workdays/archive/identifier-swap/BATCH + F1-F6 формула + L1-L6 cap=3+eligibility + C3 archive) прошли с ожидаемым результатом или подтверждённой trade-off. Открытые вопросы зафиксированы: identifier-swap оставляет orphan-группу (ProjectService::update не дёргает delete старой); archive не делает resync; batch mode в dev падает в tier-3 manual queue (Playwright bridge не настроен на этой машине); workdays union только по eligible, regions union по всем (тонкость).
- **Workdays-hardcode + resync-gate в supplier sync — ИСПРАВЛЕНО И ЗАПУШЕНО** (`80275c6`). Два бага: (1) `SyncSupplierProjectJob` хардкодил workdays=[1..7] в 7 местах — поставщик всегда получал все 7 дней независимо от `delivery_days_mask` проекта; (2) `ProjectService::update()` ресинкал только при смене sms_*/signal_identifier/regions — изменение лимита и дней оставалось локальным до ночного батча 18:00 МСК. Плюс sub-баг forceFill в update-path не обновлял локальный `current_workdays`. Все три точки залатаны; +3 Pest specs (создание из маски, update-path refresh, resync-gate на limit/days); Pest 146/146, Pint+Larastan 0. Ресинк проекта id=5 «мой номер» выполнен вручную — на portal ушли реальные дни Пн-Пт. Память: `project_supplier_integration.md`, `feedback_environment.md` квирк #104.
- **Multi-region supplier sync — ИСПРАВЛЕНО И ЗАПУШЕНО** (`36c71ec`). Портал отвергал второй регион (`status=Doubles` на дубль идентификатора), что молча проглатывалось. Теперь оба джоба (`SyncSupplierProjectJob` + `SyncSupplierProjectsJob`) формируют одну группу на идентификатор со всеми регионами merged; `subject_code=null` везде. `ProjectService::update()` триггерит resync при изменении `regions`. Проект 6 (телефон `7913XXXXXXX`) вылечен вручную: усыновлены 3 портальные записи в локальную БД → re-sync через UPDATE → теперь тег=РФ, регионы=[29, 28]. Тесты 21 GREEN.
- **Off-screen logout-меню топбара — ИСПРАВЛЕНО И ЗАПУШЕНО** (`9331465`). Баг Vuetify: `v-menu` внутри `position:fixed v-app-bar` уезжал за экран под `prefers-reduced-motion:reduce` (умолчание Windows Server). Фикс: `repositionMenuAfterOpen` подключён к обоим меню (`@update:model-value`) в `AppTopbar.vue`. Память: `feedback_environment.md` квирк #103.
- **Эпик `project-migration-redesign` ПОЛНОСТЬЮ ЗАВЕРШЁН** (Plans 1+2+3 запушены 20.05 `9729909`;
  Plan 4 запушен 20.05 день `e35fc6c`): per-субъект supplier_projects + pivot project_supplier_links
  (Plan 1), eligibility через pivot + cap=3 + deal.subject_code от тега (Plan 2), online/batch toggle +
  computeOrder + saveProjectMultiFlag + sync rewrite (Plan 3), админка-тумблер + экран «Проекты у
  поставщика» bulk-delete + ЛК require-region «Вся РФ» (Plan 4). Память: `project_migration_redesign.md`.
- **Plan 4 (админка + ЛК) — DONE+ЗАПУШЕН** (`b0ce510..e35fc6c`, 4 коммита): T1 тумблер export-mode
  `01d292f`, T2 backend «Проекты у поставщика» `d0eecbb`, T3 frontend `f1a3e9f`, T4 ЛК require-region
  `e35fc6c`. Vitest full 890/0, Pest backend targeted GREEN, pint+stan 0.
- **Online-mode НЕ flip'нут** — Plan 4 был UI-гейтом, UI готов; flip toggle в online — отдельное решение заказчика.
- **3 pre-existing эпик-теста RED — ИСПРАВЛЕНЫ И ЗАПУШЕНЫ** (`95ee664`, 21.05.2026): `Plan4/Schema/SchemaDeltaTest`
  (64→65 таблиц, 121→123 индекса + schema header v8.25→v8.26), `Integration/SupplierProjectsAccessTest`
  (unique-constraint → per-subject `(platform, unique_key, subject_code)`), `Integration/SupplierLeadFlowTest`
  (eligibility через pivot `project_supplier_links`, не legacy `supplier_b1_project_id` — добавлены
  `linkProjectToSupplier()`). Production-код не менялся — тесты отставали от смердженных Plans 1-3. Pest full 1010/0.
- **Каналы миграции — все 3 проверены вживую 20.05.2026 (✅):** webhook (#3, вход), CSV reconcile (#2, вход), экспорт проектов (выход). Приём настроен: cloudflared-туннель + supplier `/admin/user/api` Активный. Реальные лиды станут Сделками только после привязки реальных проектов через pivot (на чистом демо не сделано). Память: `project_supplier_channels_2026-05-18.md`.
- **Экспорт проектов (Лидерра → crm.bp-gr.ru)** — `FailoverProjectChannel` 3 яруса предыдущего
  эпика supplier-migration-followup (`ad09db6`); НОВЫЙ per-субъект online-mode + SyncSupplierProjectsJob
  rewrite поверх — в `9729909`. Память: `project_supplier_project_failover.md` + `project_migration_redesign.md`.
- **brain governance dashboard** — параллельная сессия, ветка `feat/brain-dashboard`; продолжает
  observer-фиксы. Память: `project_brain_governance_design.md`.

---

*Обновлять командой «обнови эталон». §1–§4 волатильны — перед действиями перепроверять реальными командами.*
