diff --git a/docs/observer/STATUS.md b/docs/observer/STATUS.md index 7862367f..9f5e4ae4 100644 --- a/docs/observer/STATUS.md +++ b/docs/observer/STATUS.md @@ -1,6 +1,6 @@ # Brain Status (auto-generated) -Last updated: 2026-08-01T08:41:49.271Z +Last updated: 2026-08-02T08:02:08.362Z | Контролёр | Состояние | Детали | |---|---|---| @@ -39,7 +39,7 @@ Last updated: 2026-08-01T08:41:49.271Z - Observer evidence: 0 episodes this month, 0 observer_error markers, 0 PII matches before filter - Legacy v1 episodes (not in factor analysis): 0 -- Last /brain-retro: 66 day(s) ago +- Last /brain-retro: 67 day(s) ago - Использование узлов: см. `/brain-retro` (раз в спринт). missed_activations: 0. **Неиспользованные узлы — не алерт, если профильной задачи не было** (Pravila §16.4 v1.36; capability-readiness; см. memory `feedback_brain_unused_tools_not_problem` — outside-repo memory store). ## Метрики дисциплины @@ -112,9 +112,9 @@ Episodes since last run: 542 / threshold: 10 | PID | Имя | CPU-время | Возраст | |---|---|---|---| -| 3544 | MsMpEng | 27.74ч | 0.0ч | -| 23936 | Code | 9.91ч | 221364.7ч | -| 4 | System | 4.07ч | NaNч | +| 3544 | MsMpEng | 43.25ч | 1328768.0ч | +| 23936 | Code | 16.25ч | NaNч | +| 5868 | Code | 7.14ч | NaNч | ⚠️ Проверь, не «осиротевшие» ли это процессы от завершённых Claude-сессий. diff --git a/ПИЛОТ.md b/ПИЛОТ.md index 1e09e8c0..6598df9a 100644 --- a/ПИЛОТ.md +++ b/ПИЛОТ.md @@ -16,6 +16,33 @@ --- +## 🆕 ОБНОВЛЕНИЕ 02.08.2026 (день) — «Заголовок объявления» доехал до экрана клиента + +**Выкачен фронтенд** телеграм-рекламы (ветка `fix/tg-zagolovok-obyavleniya`, `main` = `8712a3340`). +Бэкенд заголовок требовал с 29.07, база его хранила, робот заполнял — **а поля на экране не +было**. Клиент, рекламирующий сайт, получал отказ «заголовок обязателен» и не имел куда его +вписать. Кампаний в телеграме на бою было 0, песочница включена — до живого клиента не дошло. + +- **Что доставлено:** `resources/js/views/advertising/AdvertisingTelegramView.vue` + + `resources/js/api/telegram.ts` + пересобранный `public/build` (бандл `assets/app-Dp1fSF0n.js`, + метка в `public/build/DEPLOYED.json`). +- **Приёмка глазами** (под `info@lkomega.ru`, разрешение владельца): ссылка на сайт → поле + «Заголовок объявления» появляется с подсказкой «до 40 знаков»; ссылка `t.me/…` → поля нет. + Кампания не создавалась, данные клиента не менялись. +- **Откат:** прежняя сборка цела — каталог `public/build-old-zagolovok` рядом с рабочим + + архив `/tmp/front-backup-2026-08-02-zagolovok.tgz` (669 КБ, включает оба исходника). + Убрать после суток наблюдения. +- 🔴 **Полный overlay на боевой ЗАПРЕЩЁН** — прод и `main` расходятся штатно (47 файлов тестов, + `phpstan-baseline.neon`, миграции по рунбуку §6b). Катить только поимённым списком. + Сверять — **только `rsync --checksum`**: без него сравнение идёт по времени файла и свежий + клон даёт 2433 ложных «расхождения» вместо 55 настоящих. + +🪤 **Сборка фронтенда на боевом упала с первого раза:** `node_modules` там был огрызком +(48 пакетов, ни `vite`, ни `vue`). Вылечено `npm ci --legacy-peer-deps` — стало 563 пакета, +сборка 2.4 с. См. §2, строка про сборку фронтенда — она была устаревшей. + +--- + ## 🆕 ОБНОВЛЕНИЕ 29.07.2026 (вечер) — статус проекта врал клиенту «Готовим к запуску» при живом заказе **Выкачены ДВА backend-файла** — `app/Models/Project.php` и `Api/ProjectController.php` @@ -763,7 +790,10 @@ default-connection) → `rm bootstrap/cache/*` + `sudo -u www-data php artisan o - **Домен:** `liderra.ru` + `www.liderra.ru` → A-запись на `111.88.246.137` (резолвятся). `test.liderra.ru` — НЕ резолвится (легаси в старом конфиге). - **Сайт:** теперь по **HTTPS** (`https://liderra.ru`), http редиректит на https. - **«Дверь» (HTTP Basic Auth)** перед сайтом: логин `liderra`, пароль в `/home/ubuntu/liderra-secrets.txt` (ключ `basic_auth`). Эндпоинт `/api/webhook/` — без двери (для поставщика). -- **Демо-вход в портал:** `admin@demo.local` / `password` (tenant demo). +- ~~**Демо-вход в портал:** `admin@demo.local` / `password` (tenant demo).~~ ⚠️ **Не работает + с 01.07.2026** (база чищена «с нуля»): проверено 02.08.2026 — «Неверный email или пароль». + Тестовых учёток на бою НЕТ, все 10 тенантов — живые клиенты. Для проверки экрана глазами + нужен явный доступ от владельца. - **SSH:** `ssh -i ~/.ssh/liderra_deploy ubuntu@111.88.246.137` (ключ на dev-машине; вход по паролю отключён). sudo без пароля. ## 2. Сервер и стек @@ -772,7 +802,7 @@ default-connection) → `rm bootstrap/cache/*` + `sudo -u www-data php artisan o - **Стек одной VM:** nginx 1.24 + php8.3-fpm + PostgreSQL 16.14 + Redis. Приложение в `/var/www/liderra/app`. - **`APP_ENV=production`, `APP_DEBUG=false`** ✅ (стектрейсы наружу не светят). - ✅ **`APP_URL=https://liderra.ru`** (исправлено 22.05; было `http://111.88.246.137`) + `SANCTUM_STATEFUL_DOMAINS=liderra.ru,www.liderra.ru` (cookie-логин на apex+www). **Конфиг закэширован** (`php artisan config:cache`) → будущие правки `.env` применять `php artisan config:cache`. ✅ `SESSION_SECURE_COOKIE=true` (22.05 — куки сессии/CSRF только по HTTPS; verified `secure; httponly; samesite=lax`). -- **Деплой кода** — копированием (НЕ git-checkout; `/var/www/liderra/app` не под git). Соответствует test-deploy эпику (ветка `feat/test-deploy`). Точную версию кода сверять при деплое (`git hash-object` файла vs нужный коммит). Фронт собирается **локально** (`npm run build`) и `public/build` копируется — на VM `node_modules` нет, RAM мало. После правки PHP в очереди — `systemctl restart liderra-queue`; после правки `.env` или контроллеров — `php artisan config:cache` + `systemctl reload php8.3-fpm` (opcache). Часть файлов на сервере принадлежит `www-data` (правка через `sudo cp`). **⚠️ scp с Windows кладёт CRLF в `.env`** (инцидент 22.05 вечер: Laravel молча fallback на дефолтный sqlite-кэш, 500 на каждой странице) — после копирования любых текстовых файлов с Windows-машины обязательно `sudo sed -i 's/\r$//' /var/www/liderra/app/.env` (или копировать `git archive`/`tar`). **Pre-flight гейт** `sudo /usr/local/bin/liderra-precheck.sh` — 15 проверок (CRLF, длина APP_KEY, decrypt(encrypt) round-trip, PG/Redis ping, config-cache свежее .env, pending migrations, HTTP smoke), exit 1 при провале — **запускать после любой правки `.env` и до `systemctl restart`**. Источник скриптов: `tools/liderra-monitoring/` в репо (`365d1a0`). +- **Деплой кода** — копированием (НЕ git-checkout; `/var/www/liderra/app` не под git). Соответствует test-deploy эпику (ветка `feat/test-deploy`). Точную версию кода сверять при деплое (`git hash-object` файла vs нужный коммит). Фронт **с 02.08.2026 можно собирать прямо на VM** (`npm ci --legacy-peer-deps` → `npx vite build`): node 20.20.2 / npm 10.8.2 стоят, зависимости установлены (563 пакета), сборка занимает ~2.4 с, диска свободно 65 ГБ. Прежняя запись «на VM `node_modules` нет, собирать локально» **устарела** — до 02.08 там лежал огрызок в 48 пакетов без `vite`, из-за чего сборка падала с `Cannot find package 'vite'`. Безопасный порядок: собирать в `public/build-new` (`npx vite build --outDir public/build-new --emptyOutDir`), проверить результат, затем подменить `mv` — рабочий каталог не пустеет ни на секунду; после подмены `chown -R www-data:www-data public/build`. После правки PHP в очереди — `systemctl restart liderra-queue`; после правки `.env` или контроллеров — `php artisan config:cache` + `systemctl reload php8.3-fpm` (opcache). Часть файлов на сервере принадлежит `www-data` (правка через `sudo cp`). **⚠️ scp с Windows кладёт CRLF в `.env`** (инцидент 22.05 вечер: Laravel молча fallback на дефолтный sqlite-кэш, 500 на каждой странице) — после копирования любых текстовых файлов с Windows-машины обязательно `sudo sed -i 's/\r$//' /var/www/liderra/app/.env` (или копировать `git archive`/`tar`). **Pre-flight гейт** `sudo /usr/local/bin/liderra-precheck.sh` — 15 проверок (CRLF, длина APP_KEY, decrypt(encrypt) round-trip, PG/Redis ping, config-cache свежее .env, pending migrations, HTTP smoke), exit 1 при провале — **запускать после любой правки `.env` и до `systemctl restart`**. Источник скриптов: `tools/liderra-monitoring/` в репо (`365d1a0`). - **Очередь (`liderra-queue.service`):** ✅ `Restart=on-failure` + `StartLimitBurst=5/5min` + `OnFailure=liderra-queue-alert.service` (22.05 вечер). Раньше было `Restart=always` — крутилось бесконечно при crash'е, забивая `laravel.log` (26 МБ за сутки). Теперь после 5 крашей за 5 минут systemd останавливает + шлёт email на `kdv1@bk.ru`. Источник unit'ов: `tools/liderra-monitoring/liderra-queue*.service`. ✅ **`--timeout=300` в `ExecStart`** (22.05 утро, инцидент `signal=9/KILL` каждые 60с): Laravel queue worker дефолтным `--timeout=60` убивал сам себя через `pcntl_alarm`+`posix_kill` раньше, чем `RefreshSupplierSessionJob` успевал завершить PlaywrightBridge (cold-start Chromium на 2GB VM ~65с — HOTPATCH `PlaywrightBridge.php:TIMEOUT_SECONDS=180`, но воркера про это «забыли»). Поймано через `bpftrace tracepoint:signal:signal_generate` — sender pid == target pid, comm=php. На сервере также drop-in `/etc/systemd/system/liderra-queue.service.d/timeout.conf` как safety-net до синка из репо. Проверено вживую: `RefreshSupplierSessionJob 1 мин. 5 сек. DONE` (раньше `1 мин. FAIL → KILL`). - **Развёрнутый прикладной код (22.05):** ✅ регистрация по коду на email + обязательный телефон (E2E live: `POST /api/auth/register/start` → 200 + реальная отправка); ✅ деление лимита лидов B1/B2/B3 (денежный фикс `distributeForPlatform`, on main `e6beff6`; **re-split существующих проектов ВЫПОЛНЕН 22.05 форсом** — все активные поделены: 50→17/17/16, 30→10/10/10, 24→8/8/8, 18→6/6/6, 15→5/5/5; переплата ×N остановлена. NB: уже-`ok` проекты со старыми ×N батч сам не перечинивает → нужен force per-project online-синк); ✅ RLS-фикс admin-impersonation (`pgsql_supplier` BYPASSRLS, on main `b32dfbc`); ✅ **автолинковка субдомен→корень** (ветка `feat/root-domain-auto-link`, 22.05 вечер): `SyncSupplierProjectJob`/`SyncSupplierProjectsJob` при синке проекта-субдомена (`krasnoyarsk.carmoney.ru`) автоматически добавляют ещё один линк к корневому supplier_project (`carmoney.ru`), если он есть в `supplier_projects`. Закрывает класс «поставщик шлёт корень `carmoney.ru` — подписчики на субдомены не получают». Утилита `App\Support\SupplierIdentifier::extractRootDomain` + артизан-команда `supplier:backfill-root-links` (идемпотентна, --dry-run); ✅ **пагинация «Проектов»** (`` внизу страницы — клиент с >20 проектов теперь видит все, листая по страницам); ✅ **backfill 348 пред-проектных лидов выполнен 22.05 вечер**: они приходили от поставщика 21.05 (до создания проектов tenant 2) → молча сохранились в `supplier_leads` без сделок. После деплоя кода: balance Клиент 1 поднят 194→1 000 000 (страховка от исчерпания при массовой конверсии), `failed_webhook_jobs` 25 445→0 (исторический шторм зачищен, backup `/home/ubuntu/deploy-backups/failed_webhook_jobs_pre_truncate_*.csv.gz`), `supplier:backfill-root-links` добавил 9 root-связок к 32 site-проектам, потом `processed_at` 348 лидов сброшен в NULL и `RouteSupplierLeadJob` re-enqueue'нут — результат: **deals 6→412 у Клиента 1** (275 лидов сделали по 1 сделке, 90 silent-no-deal — поставщик шлёт на бренды без подписчиков; 73 разошлись cap=3 распределением), balance: 1 000 000→999 731 (269 lead-credits списано). Все проверены на проде. Бэкапы выкаток — `/home/ubuntu/deploy-backups/`. ✅ **Backend supplier group-sync fix (22.05 поздний вечер, on main `d3197095`):** online-синхронизация (`SyncSupplierProjectJob::handleOnline`) теперь считает агрегат по всей группе источника (active projects with same `buildUniqueKeyAgnostic`) — union regions/workdays, `computeOrder(eligible)` + `distributeForPlatform`, `status=paused` когда вся группа неактивна; `ProjectService::update` при смене `signal_identifier`/`sms_*` отвязывает старые `supplier_projects` (pivot + legacy FK) и dispatches `DeleteSupplierProjectJob` для чистки у поставщика; `ProjectController::toggleActive` + `ProjectService::bulkPauseResume` диспатчат `SyncSupplierProjectJob` (раньше пауза локальной была, до поставщика не доходила); fallback `order=computeOrder(groupProjects)` если eligible-tomorrow пуст (Mon-Fri проект синканный в пятницу вечером); pause-limit `max(1, sp.current_limit)` (portal не принимает `limit=0` даже при `status=false`). Перенесена автолинковка корня (`SupplierIdentifier::extractRootDomain`) — раньше была только в ветке `feat/root-domain-auto-link`. 5 файлов задеплоены копированием в `/var/www/liderra/app/` (бэкап `/home/ubuntu/deploy-backups/2026-05-22-supplier-group-fix.tar.gz`, hash-сверка ✓, pre-flight 15/15 ✓), `config:cache` + `route:cache` + `systemctl restart liderra-queue` + `reload php8.3-fpm`. Проверено вживую qa-проектами через `tinker sudo -u www-data`: создание `lim=20 → 7/7/6`, `Service::update lim=30 → 10/10/10` (#1 при изменении), убрать пятницу `wd=1-4`, убрать регион `reg=21`, пауза `status=false lim=10`, возобновление `status=true reg=21`, multi-client union `reg=21;72`. Чистка после ре-теста: `portal_total → 444+` (мои qa-проекты удалены, бэкапов нет). NB: ре-тест смены источника на проде упал на RLS (`Service::update` требует tenant-GUC, в tinker под www-data не ставится) — функционально покрыт локальным TDD-тестом (`Queue::assertPushed DeleteSupplierProjectJob` + pivot detach + FK null); первый реальный HTTP-запрос клиента даст полный flow. Не сделано (отложено): нет — последний пункт «чистка 5 qa-tenants» закрыт 23.05.2026. (Также закрыто 22.05 поздний вечер +1/+2: П12-П15 UI #4-#7 выкачены `0e5ab345`; 4 truly-orphan supplier_projects удалены — память про «16 осиротевших» была неверна, фактически было 4; спам `csv_reconcile: 79135XXXXXX` даунгрейднут warning→info `146501ba`.)