docs(конкурентное поле): отчёт теста «тупого клиента» + план/спека + 7 скринов
Прогон фичи глазами «самого тупого клиента» на изолированной тест-БД (прод не тронут):
все формы, групповые действия, биллинг с реальным списанием, эмуляция поставки Агента, визуал.
Деньги в порядке (300/50 списываются ровно при успехе, без двойных/ложных списаний).
Найдено и ПОЧИНЕНО 6 находок (код — коммит worktree-avtopodbor 1b3683c6).
Независимая перепроверка по коду; одна самокоррекция (общий тост, не «полная тишина»).
эскейп: фиксируй (авторизовано владельцем)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
After Width: | Height: | Size: 187 KiB |
|
After Width: | Height: | Size: 168 KiB |
|
After Width: | Height: | Size: 168 KiB |
|
After Width: | Height: | Size: 172 KiB |
|
After Width: | Height: | Size: 64 KiB |
|
After Width: | Height: | Size: 229 KiB |
|
After Width: | Height: | Size: 96 KiB |
@@ -0,0 +1,234 @@
|
||||
# Тест «Конкурентного поля» глазами тупого клиента — НАХОДКИ (30.06.2026)
|
||||
|
||||
Стенд: воркстри `worktree-avtopodbor`, свежая изолированная БД `liderra_dumbtest`
|
||||
(локальный dev-postgres 127.0.0.1, НЕ прод). Прод/gitea не тронуты. План —
|
||||
[RUN](../plans/2026-06-30-konkurentnoe-pole-dumb-client-test-RUN.md), спека —
|
||||
[design](../specs/2026-06-30-konkurentnoe-pole-dumb-client-test-design.md).
|
||||
|
||||
Приоритеты: 🔴 блокер · 🟠 спотыкание клиента · 🟡 косметика · 🟢 ок/плюс.
|
||||
|
||||
> ⚠️ **ОТКАТИТЬ В КОНЦЕ:** воркстри `app/.env` временно изменён для изоляции стенда —
|
||||
> `DB_DATABASE=liderra_dumbtest` (было `liderra`), `QUEUE_CONNECTION=database` (было `redis`).
|
||||
> Вернуть обратно: `DB_DATABASE=liderra`, `QUEUE_CONNECTION=redis`. Файл gitignored, не коммитится.
|
||||
>
|
||||
> **Методическая засада стенда (НЕ баг продукта):** на Windows `DB_DATABASE=… php artisan serve`
|
||||
> НЕ пробрасывает env в дочерний веб-процесс (`$_ENV` пуст, `variables_order` без `E`), поэтому
|
||||
> приложение читает БД из `.env`. Изоляцию тест-стенда задавать ТОЛЬКО через `.env`, не env-префиксом.
|
||||
> Из-за этого первые попытки «Собрать» давали ложный `run_in_flight` 409 — били в dev-`liderra`
|
||||
> (там омега=tenant 34 с зависшим queued-прогоном), а не в чистую `liderra_dumbtest`. Записей в
|
||||
> dev-`liderra` тест не сделал (всё блокировалось 409).
|
||||
|
||||
---
|
||||
|
||||
## ✅ ПОЧИНЕНО 30.06 (по TDD, в воркстри `worktree-avtopodbor`, dev)
|
||||
|
||||
Все находки закрыты. Тесты: Pest автоподбор **82/82**, Vitest автоподбор+админка **62/62**,
|
||||
`vite build` ✓, продакшен-код eslint-чист.
|
||||
|
||||
- **FIX-1 (GENERIC-ERROR)** — новый маппер `autopodborErrorMessage()` в `api/autopodbor.ts` (+5 тестов):
|
||||
окна «Собрать конкурентов/источники» теперь показывают адресный текст по коду ответа
|
||||
(`balance_insufficient` → «Не хватает денег — пополните», `run_in_flight` → «Подбор уже идёт»,
|
||||
валидация → по полю). Подключён в `catch` обоих экранов.
|
||||
- **FIX-2 (B-REGION)** — регион по умолчанию = пустой плейсхолдер «— выберите регион —»
|
||||
(обязателен), вместо «Республики Адыгея».
|
||||
- **FIX-3 (D-STUDIED)** — у изучённого конкурента кнопка «Собрать источники» заменена на
|
||||
«✓ Источники собраны» (disabled). +2 теста.
|
||||
- **FIX-4 (B-DUP)** — сквозной дедуп в `RunAutopodborSearchJob`: конкуренты, уже известные тенанту
|
||||
(чужие прогоны/ручные), не дублируются; если нового ничего нет — прогон «пусто», без списания.
|
||||
Идемпотентность ретрая своего прогона сохранена. +1 тест.
|
||||
- **FIX-5 (J-ADMIN-ID)** — убран захардкоженный `admin_user_id:1` с фронта (поле опционально, id
|
||||
админа проставит бэкенд из сессии). *Полный фикс ждёт saas-admin авторизацию (MVP-долг бэкенда).*
|
||||
- **FIX-6 (F-MIG)** — в 3 миграции автоподбора добавлен идемпотентный гард `to_regclass` (как в
|
||||
остальных миграциях проекта); `migrate:fresh` снова зелёный (проверено на свежей БД).
|
||||
|
||||
⚠️ **НЕ закоммичено** (жду «эскейп»). Перед прод-выкатом — отдельный предполётный хвост
|
||||
(canon-sync schema.sql, rls-reviewer, larastan, ребейз). I3-MOBILE (сайдбар на узком экране) НЕ
|
||||
трогал — это общий `AppLayout`, не экран фичи.
|
||||
|
||||
---
|
||||
|
||||
## ИТОГ ПО ПРИОРИТЕТУ (отранжировано по «больно клиенту»)
|
||||
|
||||
**Деньги — в порядке (проверено по базе).** Подбор списывает ровно 300₽ при успехе, изучение — 50₽;
|
||||
при пустом/нехватке/повторе НЕ списывает, в минус не уходит, двойного списания нет. Ни одного
|
||||
ложного/двойного списания за весь прогон.
|
||||
|
||||
**🟠 Что чинить (спотыкания тупого клиента):**
|
||||
1. **GENERIC-ERROR** — окна «Собрать конкурентов/источники» на любую ошибку показывают один общий
|
||||
краткий тост «Проверьте баланс» (или ничего на пустой форме). Для «уже идёт» и пустой формы —
|
||||
вводит в заблуждение. Сделать адресные сообщения + подсветку полей. *Главный UX-пробел.*
|
||||
2. **B-REGION** — регион по умолчанию «Республика Адыгея» (чужой). Поставить регион клиента/пустой
|
||||
плейсхолдер, иначе платный подбор уйдёт по чужому региону.
|
||||
3. **B1** — пустая форма: нет подсветки/подсказки, что заполнить.
|
||||
4. **B8** — нехватка денег: нет явного «пополните баланс».
|
||||
|
||||
**🟡 Мелочи:**
|
||||
5. **B-DUP** — повторные подборы плодят дубли карточек (нет сквозного дедупа предложений).
|
||||
6. **D-STUDIED** — кнопка «Собрать источники» активна у уже изучённого конкурента и молча ничего не
|
||||
делает.
|
||||
7. **J-ADMIN-ID** — админ-экран тарифов шлёт захардкоженный `admin_user_id:1`.
|
||||
8. **F-MIG-01** — 3 миграции автоподбора без идемпотентного гарда → ломается `migrate:fresh`
|
||||
(предполётный долг, в код фичи попал из canon-sync).
|
||||
9. **I3-MOBILE** — на узком экране сайдбар стопкой над контентом (общий AppLayout).
|
||||
|
||||
**🟢 Что хорошо:** экран «Поле»/«Карточка»/«Предложения»/«Админ-тарифы» — единый Forest-стиль и понятная
|
||||
иерархия; типы телефонов (городской/мобильный/8-800) + коллтрекинг ✓/🎭 рендерятся идеально; платный
|
||||
путь подбор→предложения работает с авто-переключением; админ-экран ошибку показывает правильно;
|
||||
пустые/загрузочные состояния и баннеры сроков (18:00/21:00 МСК) на месте.
|
||||
|
||||
**Движок «под капотом» — заглушка** (`FakeCompetitorAgent`), на звене 4 усилена до реалистичной
|
||||
поставки (конкуренты с разной похожестью + источники со всеми типами телефонов вкл. 8-800). Реальный
|
||||
ИИ-движок — отдельная работа (замена binding в `AutopodborServiceProvider`).
|
||||
|
||||
---
|
||||
|
||||
## Находки
|
||||
|
||||
### 🟠 F-MIG-01 — fresh-migrate / migrate:fresh сломан (3 автоподбор-миграции без идемпотентного гарда)
|
||||
**Где:** `database/migrations/2026_06_28_100000_create_autopodbor_runs.php` (и `100100_*_competitors`,
|
||||
`100200_*_sources`).
|
||||
**Симптом:** на свежей БД `php artisan migrate` падает: `SQLSTATE[42P07] отношение "autopodbor_runs"
|
||||
уже существует`.
|
||||
**Корень:** проектный паттерн — `db/schema.sql` это squashed-база (грузится `0001_..._load_initial_schema`),
|
||||
а каждая миграция, дублирующая таблицу из schema.sql, имеет гард
|
||||
`if (to_regclass('public.X') !== null) return;` (см. `2026_05_19_..._create_supplier_manual_sync_queue`).
|
||||
Canon-sync v8.58 добавил автоподбор-таблицы в schema.sql, но в 3 автоподбор-миграциях остался простой
|
||||
`Schema::create(...)` БЕЗ гарда → загрузчик создаёт таблицу, миграция падает на дубле.
|
||||
**Кого бьёт:** любой, кто поднимает чистый стенд или делает `migrate:fresh` (CI, новый разработчик,
|
||||
приёмочный прогон). На старой инкрементальной БД (`liderra_testing`) не воспроизводится — там таблицы
|
||||
миграций уже отмечены.
|
||||
**Не из этой сессии:** предсуществующий долг канон-синка, не код фичи и не UX. Уже в предполётном
|
||||
хвосте HANDOFF (canon-sync + rls-reviewer).
|
||||
**Рекомендация:** обернуть `up()` трёх автоподбор-миграций тем же гардом `to_regclass`, что и
|
||||
`supplier_manual_sync_queue` (3 строки на файл). Тогда `migrate:fresh` снова зелёный. Правка кода —
|
||||
под «эскейп»/в предполёт.
|
||||
**Обход для стенда (применён, кода не трогал):** после загрузчика зарегистрировал 3 миграции в таблице
|
||||
`migrations` как выполненные → `migrate --force` домигрировал box/phone_type/цены; схема корректна
|
||||
(box на обоих, phone_type на источниках, цены 300/50, pending=0).
|
||||
|
||||
---
|
||||
|
||||
### 🟢 A1/A3 — экран «Поле»: первый взгляд понятен
|
||||
Заголовок, подзаголовок «Ваши конкуренты: 5 · проектов в работе: 1. Поле ведёте вы — Лидерра
|
||||
подсказывает», две крупные кнопки, баннер-черновик «💡 Лидерра подготовила 5 в предложениях…
|
||||
Разобрать предложения →», ящики «В поле 5 / Предложения 5», карточки с типом/похожестью/Справочником/
|
||||
счётчиками, «✎ Изменить / ✕ Удалить / Открыть конкурента →». Forest-палитра. Клиенту ясно, что делать.
|
||||
Скрин `DUMB-A-field-first-look.png`.
|
||||
|
||||
### 🟠 B1 — пустая форма «Собрать конкурентов»: кнопка молчит, нет подсказки
|
||||
**Где:** окно «Собрать конкурентов для меня», кнопка «Запустить подбор (платно)».
|
||||
**Что делает тупой клиент:** открыл окно, ничего не заполнил, нажал «Запустить подбор».
|
||||
**Ожидал:** подсказку «заполните: чем вы занимаетесь, минимум 2 примера» / подсветку полей.
|
||||
**Увидел:** окно осталось, без подсветки полей и без понятного указания, ЧТО заполнить (в живом тесте
|
||||
сообщения на экране не увидел; возможен краткий общий тост «Проверьте баланс» — см. GENERIC-ERROR,
|
||||
который для пустой формы вводит в заблуждение). Клиент не понимает, почему «не работает».
|
||||
Скрин `DUMB-B1-empty-submit.png`.
|
||||
**Деньги:** ✅ безопасно — списания нет (tx=0), прогон не создан (баланс цел). Проблема — нет
|
||||
адресной валидации/подсветки полей.
|
||||
**Рекомендация:** при клике на невалидной форме — подсветить первое незаполненное поле + короткий
|
||||
текст «Заполните, чем вы занимаетесь» / «Нужно минимум 2 примера». Не оставлять клиента в тишине.
|
||||
|
||||
### 🟠 B-REGION — регион по умолчанию «Республика Адыгея» (чужой клиенту)
|
||||
**Где:** окно «Собрать конкурентов», поле «Регион поиска *».
|
||||
**Симптом:** по умолчанию выбрана **первая по алфавиту** «Республика Адыгея», а не регион клиента
|
||||
(у Омеги — Красноярский край) и не пустой плейсхолдер «Выберите регион».
|
||||
**Кого бьёт:** тупой клиент не заметит и запустит платный (300 ₽) подбор по чужому региону → деньги
|
||||
за бесполезный результат.
|
||||
**Рекомендация:** дефолт = регион тенанта (если известен) ИЛИ пустой плейсхолдер «— выберите регион —»,
|
||||
который заставляет выбрать осознанно. То же проверить в окне «Создать проект» (E1).
|
||||
|
||||
### 🟢 B-happy / H1 — платный подбор работает, списание корректно
|
||||
Заполнил форму (описание, регион Красноярский край, 2 примера) → «Запустить подбор (платно)» →
|
||||
окно «Идёт подбор… Можно закрыть вкладку, деньги спишутся только при успехе» → воркер обработал за
|
||||
83 мс → авто-переключение на «Предложения 13» с подзаголовком «Найдено в предложениях: 13. Это
|
||||
черновик — разберите и перенесите нужных в поле». **Деньги:** баланс 49700→49400, ровно ОДНА
|
||||
транзакция `autopodbor_charge −300.00` (H1 ✅). Карточки предложений — единый стиль с «Поле».
|
||||
|
||||
### 🟢 H3 — двойного списания нет (гвард run_in_flight)
|
||||
Пока прогон `queued/running`, повторный «Собрать» того же типа получает 409 `run_in_flight` —
|
||||
второй платёж не проходит. Подтверждено и кодом (`assertNoInFlight`), и живым 409 в ходе теста.
|
||||
|
||||
### 🟡 B-DUP — повторные подборы плодят дубли карточек в «Предложениях»
|
||||
После двух подборов в «Предложениях» висят пары-дубли («Окна Комфорт» ×2, «Пластика Окон» ×2,
|
||||
«Фабрика Окон» ×2, «Балкон-Сервис 16» ×2). Дедуп работает ВНУТРИ прогона (ключ
|
||||
`tenant+search_run_id+dedup_key`), но НЕ между прогонами → один и тот же конкурент из разных
|
||||
подборов = разные строки. Тупой клиент, кликнувший «Собрать» дважды (например, не увидев результат
|
||||
из-за async), получит задвоение. **Рекомендация:** дедуп предложений в пределах ящика «proposal»
|
||||
по конкуренту, а не по прогону; при повторной находке — обновлять существующую карточку.
|
||||
*Замечание:* усилено фикс-данными заглушки; реальный движок может отдавать иные наборы.
|
||||
|
||||
### 🟢 D3 / H2 — изучение конкурента: списание 50₽ + все типы телефонов
|
||||
Бэкенд+очередь+воркер: study run → done, **ровно 50₽** (баланс 49400→49350, одна транзакция).
|
||||
Источники из заглушки (после звена 4) включают полный набор: сайт ×2, телефоны
|
||||
city ✓(настоящий), city 🎭(подменный/коллтрекинг), mobile, **tollfree 8-800**. На карточке
|
||||
КрасЛомбарда вживую виден бейдж «✓ городской». Тип номера + метка коллтрекинга отображаются.
|
||||
|
||||
### 🟡 D-STUDIED — кнопка «Собрать источники» предлагается у уже изучённого конкурента и молчит
|
||||
Открыл уже изучённого КрасЛомбарда → «✨ Собрать источники для меня» доступна. Клик → бэкенд
|
||||
(`startStudy`: `studied_at != null → вернуть существующий прогон`) корректно НЕ списывает 50₽ и не
|
||||
изучает повторно, но клиент не видит ни нового результата, ни сообщения «конкурент уже изучен».
|
||||
**Деньги:** ✅ безопасно (повтор бесплатен). **Рекомендация:** для изучённого конкурента — менять
|
||||
кнопку на «Источники собраны» (disabled) или показывать «Уже изучали N.NN — повторный сбор не нужен».
|
||||
|
||||
### 🟠 B8 / H4 — нехватка баланса: списания нет, но клиент НЕ видит «не хватает денег»
|
||||
Поставил баланс 100 ₽, запустил подбор (300 ₽). **Деньги:** ✅ безопасно — баланс остался 100,
|
||||
прогон не создан, в минус не ушло (H4 ✅). **НО:** ни сообщения «недостаточно средств», ни
|
||||
«пополните баланс» в DOM на момент проверки не было (0 упоминаний скриптом). По коду срабатывает
|
||||
краткий общий тост «Проверьте баланс» (см. GENERIC-ERROR) — но он авто-исчезает и не говорит явно
|
||||
«пополните». Тупому клиенту неочевидно, что нужно пополнить. Скрин `DUMB-B8-insufficient.png`.
|
||||
|
||||
### 🟠 GENERIC-ERROR (сводная, УТОЧНЕНО верификацией) — общий тост «Проверьте баланс» на ВСЕ ошибки
|
||||
⚠️ *Самокоррекция:* сначала записал как «полная тишина» — **верификация по коду опровергла**. На
|
||||
самом деле `catch` в окнах есть и показывает тост (axios отклоняет 4xx → catch срабатывает):
|
||||
`FieldWorkspaceScreen.vue:134-137` → `flash('Не удалось запустить подбор. Проверьте баланс.')`;
|
||||
`FieldCompetitorScreen.vue:184-187` → `flash('Не удалось собрать источники. Проверьте баланс.')`.
|
||||
**Проблема (реальная):** тост **хардкоженный и общий** — один и тот же «Проверьте баланс» для ВСЕХ
|
||||
причин: нехватка денег (верно), `run_in_flight` «подбор уже идёт» (вводит в заблуждение), 422
|
||||
пустая форма (вводит в заблуждение). НЕ через `extractErrorMessage` (админ-экран — через него, делает
|
||||
правильно). Плюс тост краткий/авто-исчезает — в живом тесте B8 я его упустил по таймингу
|
||||
(в DOM на момент проверки сообщения уже не было). **Рекомендация:** в `catch` парсить код ответа
|
||||
через `extractErrorMessage`/по `error`: `balance_insufficient` → «Не хватает денег — пополните»;
|
||||
`run_in_flight` → «Подбор уже идёт, дождитесь результата»; 422 → «Заполните описание + минимум 2
|
||||
примера». Заодно — подсветка незаполненных полей при пустой форме (B1).
|
||||
|
||||
### Проверка находок (звено 9, независимый субагент-скептик по коду)
|
||||
- **GENERIC-ERROR** — ПОДТВЕРЖДЕНО с уточнением (выше): тост есть, но хардкоженный/общий, не
|
||||
error-specific; контраст с админкой (`extractErrorMessage`) подтверждён.
|
||||
- **B-DUP** — ПОДТВЕРЖДЕНО: `RunAutopodborSearchJob.php` ключ `updateOrCreate` включает
|
||||
`search_run_id` → конкурент из разных прогонов = разные строки.
|
||||
- **D-STUDIED** — ПОДТВЕРЖДЕНО (сервер: `startStudy` возвращает прогон без списания при
|
||||
`studied_at != null`) + фронт `FieldCompetitorScreen.vue` НЕ скрывает/не дизейблит кнопку «Собрать
|
||||
источники» при `studied_at` (нет проверки) — кнопка всегда активна.
|
||||
- **J-ADMIN-ID** / **F-MIG** — подтверждены прямым чтением кода (захардкожен `admin_user_id:1`;
|
||||
3 миграции `2026_06_28_*` без идемпотентного гарда).
|
||||
|
||||
### 🟢 J — админ-экран «Тарифы «Конкурентного поля»» грузится и валидирует корректно
|
||||
`/admin/autopodbor-pricing`: заголовок, поля «Сбор конкурентов 300» / «Сбор источников 50», поле
|
||||
«Причина (мин. 30)» предзаполнено, кнопка «Сохранить тарифы» **заблокирована без изменений** и
|
||||
**активируется** при правке. Справочная сетка лидов. Скрин `DUMB-J-admin-pricing.png`. В отличие от
|
||||
клиентских окон, при ошибке сохранения экран **показывает** дружелюбное «Не удалось сохранить.
|
||||
Проверьте данные…» (правильный паттерн — клиентским окнам не хватает именно этого).
|
||||
|
||||
### 🟠 J-ADMIN-ID — админ-экран шлёт захардкоженный `admin_user_id: 1`
|
||||
Сохранение цены (350) вернуло 422: тело запроса `{value, reason, admin_user_id: 1}` — id админа
|
||||
зашит константой `1`. В тест-БД saas-админа с id=1 нет → отказ. На проде сработает только если id=1
|
||||
случайно валиден. **Рекомендация:** подставлять id реально залогиненного админа (из auth-стора),
|
||||
а не константу. *NB:* сам отказ в тесте — частично из-за отсутствия админ-пользователя в свежей
|
||||
тест-БД, но захардкоженный id — реальный долг экрана F2.
|
||||
|
||||
---
|
||||
|
||||
## Визуал (звено 6)
|
||||
|
||||
### 🟢 Палитра/типографика/иерархия — соответствуют Forest и прототипу
|
||||
Все экраны (Поле, Карточка конкурента, Предложения, Админ-тарифы) — палитра Forest (teal #0F6E56,
|
||||
ivory фон, тёмный сайдбар), карточки с тенью, крупная «похожесть %», бейджи тип/предложение/телефон,
|
||||
понятная иерархия. Состояния проверены вживую: пустое («Предложений по источникам пока нет…»),
|
||||
спиннер («Идёт подбор…»), модалки, бейджи ✓/🎭 + городской/мобильный/8-800. Скрины `DUMB-*.png`.
|
||||
|
||||
### 🟡 I3-MOBILE — на узком экране (390px) сайдбар стопкой над контентом
|
||||
Карточки корректно перестраиваются в 1 колонку, всё читаемо. Но тёмный сайдбар на мобильном
|
||||
рендерится стопкой НАД контентом (полное меню), хотя в шапке есть «гамбургер» ☰ — drawer
|
||||
сворачивается не полностью. **Это общий `AppLayout`, не экран фичи** — на решение, но не блокер
|
||||
(продукт десктоп-первый). Мелочь: «✎ Изменить / ✕ Удалить» переносятся на 2 строки на узком экране.
|
||||
Скрин `DUMB-I3-mobile-field.png`.
|
||||
@@ -0,0 +1,93 @@
|
||||
# ТЕСТ «Конкурентного поля» глазами «самого тупого клиента» — хартия + промт
|
||||
|
||||
Документ-эстафета на случай /compact. Вверху — **готовый промт** для старта тестирования
|
||||
(скопировать целиком в новую сессию). Ниже — согласованный план, цепочка скилов, рамки.
|
||||
|
||||
Связано: [HANDOFF фичи](2026-06-29-konkurentnoe-pole-HANDOFF.md) ·
|
||||
[находки прототип↔реализация](../findings/2026-06-30-konkurentnoe-pole-proto-vs-impl-gap.md) ·
|
||||
эталон-прототип `docs/superpowers/prototypes/2026-06-29-konkurentnoe-pole-proto.html`
|
||||
(поднять: `node docs/superpowers/prototypes/serve.js` → http://localhost:8123).
|
||||
|
||||
---
|
||||
|
||||
## 📋 ГОТОВЫЙ ПРОМТ ДЛЯ СТАРТА ТЕСТИРОВАНИЯ (скопировать как есть)
|
||||
|
||||
```
|
||||
Начинаем тестирование «Конкурентного поля» глазами «самого тупого клиента».
|
||||
Сначала прочитай по порядку и ничего не упусти:
|
||||
1. docs/superpowers/plans/2026-06-30-konkurentnoe-pole-DUMB-CLIENT-TEST-charter.md ← этот файл: план, цепочка скилов, рамки, чек-лист
|
||||
2. docs/superpowers/findings/2026-06-30-konkurentnoe-pole-proto-vs-impl-gap.md ← что уже доделано (F1–F3, M2)
|
||||
3. docs/superpowers/plans/2026-06-29-konkurentnoe-pole-HANDOFF.md ← состояние фичи, окружение, стенд
|
||||
4. docs/superpowers/prototypes/2026-06-29-konkurentnoe-pole-proto.html ← визуал-эталон (localhost:8123)
|
||||
|
||||
ОБЯЗАТЕЛЬНО иди по согласованной ЦЕПОЧКЕ СКИЛОВ (звенья 1→10 в charter), КАЖДЫЙ скил
|
||||
инвокируй через Skill-tool ПЕРВЫМ для своего звена — не пропускать, не «срезать»:
|
||||
Звено 1 — skill superpowers:brainstorming (хартия теста + чек-лист, согласовать со мной)
|
||||
Звено 2 — skill superpowers:writing-plans (пошаговый сценарий «ожидал→увидел»)
|
||||
Звено 3 — поднять стенд (СВЕЖАЯ изолированная тест-БД, миграции, сид демо-Омеги, vite build, php artisan serve)
|
||||
Звено 4 — skill superpowers:test-driven-development (усилить заглушку Агента до реалистичной поставки; Pest зелёный)
|
||||
Звено 5 — Playwright MCP (прогон глазами как тупой клиент: пустые поля, мусор, двойные клики, Отмена, F5, назад)
|
||||
Звено 6 — skill frontend-design + Playwright (ВИЗУАЛ: сверка с эталоном :8123 бок-о-бок, палитра/шрифты/отступы/иерархия, единство «Поле»↔«Предложения», пустые состояния/модалки/тосты/бейджи, адаптив resize в мобильный)
|
||||
Звено 7 — Laravel Boost MCP database-query (ДЕНЬГИ: баланс ДО/ПОСЛЕ, транзакции, блокировки, «пусто→не списали»)
|
||||
Звено 8 — skill superpowers:systematic-debugging (только если реально падает)
|
||||
Звено 9 — субагент-верификатор + skill superpowers:verification (перепроверка находок, отсев ложных, ранжир по «больно клиенту»)
|
||||
Звено 10 — отчёт: находки (UX + ВИЗУАЛ + деньги) + рекомендации по улучшению, по приоритету
|
||||
|
||||
Глубина — ПОЛНАЯ (формы + групповые + биллинг с реальным списанием 300/50 + эмуляция поставки Агента
|
||||
+ сквозной путь лид→сделка). База — СВЕЖАЯ ИЗОЛИРОВАННАЯ тест-БД.
|
||||
|
||||
РАМКИ (жёстко): прод и gitea НЕ трогать; тест-БД и правки заглушки — ТОЛЬКО стенд; ничего не
|
||||
коммитить без моего «эскейп». Говори простым русским, без жаргона. Я — «самый тупой клиент»:
|
||||
любое место, где можно ошибиться/споткнуться/не понять — это находка.
|
||||
|
||||
Стартуй со звена 1 (brainstorming) — пришли мне чек-лист сценариев на согласование.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ СОГЛАСОВАНО (решения владельца)
|
||||
- **Глубина:** ПОЛНАЯ — все формы + групповые действия + биллинг с реальным списанием (300 ₽ сбор
|
||||
конкурентов / 50 ₽ сбор источников) + эмуляция поставки Агента + сквозной путь лид→сделка.
|
||||
- **Тест-база:** СВЕЖАЯ ИЗОЛИРОВАННАЯ (отдельная чистая тест-БД, миграции + сид демо-Омеги). Прод ни при чём.
|
||||
- **Персона:** «самый тупой клиент на свете» — нигде не должен ошибиться/споткнуться/не понять.
|
||||
- **Визуал — обязателен** (отдельное звено 6): не только «работает руками», но и «красиво/понятно глазом, как проектировали».
|
||||
|
||||
## 🔗 ЦЕПОЧКА СКИЛОВ (по звеньям)
|
||||
|
||||
| # | Звено | Скил / инструмент | Что делает |
|
||||
|---|---|---|---|
|
||||
| 1 | Хартия теста | **skill `superpowers:brainstorming`** | Персона + полный чек-лист сценариев. Согласовать с владельцем. |
|
||||
| 2 | План прогона | **skill `superpowers:writing-plans`** | Пошаговый сценарий «ожидал → увидел». |
|
||||
| 3 | Стенд | **Bash/PowerShell** + **Laravel Boost MCP** | Свежая изолированная тест-БД, миграции, сид, `vite build`, `php artisan serve`. |
|
||||
| 4 | Эмуляция Агента (dev-only) | **skill `superpowers:test-driven-development`** + **Edit** | Заглушка `FakeCompetitorAgent` → реалистичная поставка (конкуренты/источники/типы телефонов/лид); Pest остаётся зелёным. Каркас НЕ в прод/коммит. |
|
||||
| 5 | Прогон глазами | **Playwright MCP** | Кликаю как тупой клиент: пустые поля, мусор, двойные клики, Отмена, F5, назад, платное дважды. |
|
||||
| 6 | 🎨 Визуал и дизайн | **skill `frontend-design`** + **Playwright** (`browser_take_screenshot`, `browser_resize`) | Сверка с эталоном :8123 бок-о-бок: палитра Forest, шрифты, отступы, иерархия; единство «Поле»↔«Предложения»; пустые состояния/модалки/спиннеры/тосты/бейджи/bulkbar; адаптив (мобильный). |
|
||||
| 7 | Деньги | **Laravel Boost MCP** (`database-query`) | Баланс ДО/ПОСЛЕ каждого платного действия, транзакции, блокировки, «пусто → не списали». |
|
||||
| 8 | Корень бага (если есть) | **skill `superpowers:systematic-debugging`** | Докопаться до причины реального падения. |
|
||||
| 9 | Независимая перепроверка | **субагент-верификатор** (`Explore`/general-purpose) + **skill `superpowers:verification`** | Скептик воспроизводит находки, отсеивает ложные, ранжирует по «больно клиенту». |
|
||||
| 10 | Отчёт | я | Находки (UX + визуал + деньги) + рекомендации, по приоритету. |
|
||||
|
||||
Опора всей цепочки — `superpowers:using-superpowers` (скилы инвокируются ПЕРВЫМИ для своего звена; §12 Pravila — hard rule).
|
||||
|
||||
## 🧪 ЧЕРНОВИК ЧЕК-ЛИСТА СЦЕНАРИЕВ (доуточнить в звене 1)
|
||||
Формы и пути, которые тупой клиент должен пройти без спотыкания:
|
||||
- **Сбор конкурентов (300 ₽):** пустые поля, 1 пример вместо 2, мусорный сайт, «+ ещё пример», федералы Да/Нет, отмена, повтор клика, баланса не хватает.
|
||||
- **Добавить конкурента вручную:** без названия, без сайта и без справочника, кривой %, кривые ссылки 2ГИС/Яндекс.
|
||||
- **Сбор источников (50 ₽):** у конкурента без сайта/справочника, повтор, отмена, пустой результат.
|
||||
- **Добавить источник вручную:** сайт vs телефон, кривой телефон, переключение типа.
|
||||
- **Создать проект из источника:** регион/лимит/дни, лимит 0/огромный, все дни сняты, отмена.
|
||||
- **Настройки проекта / Изменить источник / Сменить источник:** тип залочен, подтверждение смены, тексты сроков (18:00/21:00 МСК).
|
||||
- **Групповые действия:** ≥2 конкурента (вкл/выкл проекты), ≥2 источника (создать/пауза/возобновить/удалить), смешанный выбор (с проектом и без), «Снять выбор», «Выбрать всех».
|
||||
- **Удаление:** конкурента с активным проектом (гвард 409), источника с активным проектом, предложения.
|
||||
- **Предложения:** перенос одного/массово в поле, править/удалить предложение, единое окно сбора.
|
||||
- **Биллинг:** доп.услуги показаны, списание 300/50 при успехе, НЕ списание при пустом, блок при нехватке баланса; админ-экран тарифов (правка цены + причина ≥30).
|
||||
- **Визуал каждого экрана** (звено 6): сверка с прототипом, адаптив, пустые/загрузочные состояния.
|
||||
|
||||
## 🔒 РАМКИ (жёстко)
|
||||
- Прод (liderra.ru / Managed PG) и gitea — **НЕ трогать**.
|
||||
- Тест-БД и правки заглушки Агента — **только стенд**, в прод/коммит не уходят.
|
||||
- Ничего не коммитить без «эскейп» владельца.
|
||||
- Простой русский, без жаргона. Любое спотыкание тупого клиента = находка.
|
||||
|
||||
## Статус
|
||||
Согласовано 30.06.2026. Тестирование ещё НЕ начато — стартуем со звена 1 после /compact.
|
||||
@@ -0,0 +1,168 @@
|
||||
# Прогон теста «Конкурентного поля» глазами тупого клиента — план
|
||||
|
||||
> **Для исполнителя:** это runbook теста, не сборка фичи. Шаги — checkbox для отслеживания.
|
||||
> Единственная правка кода — звено 4 (заглушка Агента, по TDD, dev-only, НЕ коммитить).
|
||||
|
||||
**Цель:** пройти чек-лист A–J ([спека](../specs/2026-06-30-konkurentnoe-pole-dumb-client-test-design.md))
|
||||
глазами «самого тупого клиента», зафиксировать находки «ожидал → увидел», сверить деньги по базе,
|
||||
сверить визуал с эталоном.
|
||||
|
||||
**Стенд:** воркстри `.claude/worktrees/avtopodbor`, код под `app/`. Свежая изолированная тест-БД
|
||||
`liderra_dumbtest` (НЕ прод, НЕ phpunit-овая `liderra_testing`). Прод/gitea не трогать.
|
||||
|
||||
**Инструменты:** Playwright MCP (клики+скрины), Laravel Boost MCP (деньги по базе),
|
||||
frontend-design (визуал), субагент-верификатор. Команды — через Bash (Git Bash, env-prefix работает).
|
||||
|
||||
---
|
||||
|
||||
## Звено 3 — Поднять стенд (свежая изолированная БД)
|
||||
|
||||
- [ ] **3.1 Собрать фронт**
|
||||
`cd .claude/worktrees/avtopodbor/app && npm run build`
|
||||
Ожидание: `vite build` exit 0.
|
||||
|
||||
- [ ] **3.2 Создать свежую БД `liderra_dumbtest`**
|
||||
Основной: `cd .claude/worktrees/avtopodbor/app && php artisan tinker --execute="DB::statement('DROP DATABASE IF EXISTS liderra_dumbtest'); DB::statement('CREATE DATABASE liderra_dumbtest');"`
|
||||
Фоллбэк (если CREATE DATABASE в транзакции падает): `createdb -h 127.0.0.1 -U postgres liderra_dumbtest`.
|
||||
⚠️ Это dev (postgres superuser, CREATEDB есть). Прод-кластер НЕ трогать.
|
||||
|
||||
- [ ] **3.3 Миграции на свежую БД**
|
||||
`cd .claude/worktrees/avtopodbor/app && DB_DATABASE=liderra_dumbtest php artisan config:clear && DB_DATABASE=liderra_dumbtest php artisan migrate --force`
|
||||
Ожидание: все миграции прошли (включая box, phone_type, autopodbor_*).
|
||||
|
||||
- [ ] **3.4 Партиции (если требуются логами/лидами)**
|
||||
`cd .claude/worktrees/avtopodbor/app && DB_DATABASE=liderra_dumbtest php artisan partitions:create-months`
|
||||
Если команда называется иначе — найти `php artisan list | grep partition` и выполнить аналог.
|
||||
|
||||
- [ ] **3.5 Сид демо-Омеги**
|
||||
`cd .claude/worktrees/avtopodbor/app && DB_DATABASE=liderra_dumbtest php artisan db:seed --class=OmegaDemoFieldSeeder --force`
|
||||
Ожидание: тенант `omega-demo@liderra.local` / `omega12345` создан, поле наполнено.
|
||||
|
||||
- [ ] **3.6 Поднять приложение** (фоном)
|
||||
`cd .claude/worktrees/avtopodbor/app && DB_DATABASE=liderra_dumbtest php artisan serve --port=8001`
|
||||
Ожидание: слушает http://127.0.0.1:8001 .
|
||||
|
||||
- [ ] **3.7 Поднять эталон-прототип** (фоном, для визуала)
|
||||
`node docs/superpowers/prototypes/serve.js` → http://localhost:8123 .
|
||||
|
||||
- [ ] **3.8 Зайти клиентом**
|
||||
Playwright: `browser_navigate` http://127.0.0.1:8001/login → войти omega-demo@liderra.local / omega12345
|
||||
→ открыть «Конкурентное поле». Снять стартовый скрин.
|
||||
|
||||
---
|
||||
|
||||
## Звено 4 — Эмуляция поставки Агента (TDD, dev-only, НЕ коммитить)
|
||||
|
||||
Заглушка `FakeCompetitorAgent` отдаёт ФИКСИРОВАННЫЕ данные. Чтобы D3 проверил значки ✓/🎭 и типы
|
||||
номеров, усилить заглушку до реалистичной поставки: конкуренты с разной похожестью + источники с
|
||||
разными `phone_type` (city/mobile/tollfree) и `phone_kind` (real/substitute). Pest остаётся зелёным.
|
||||
|
||||
- [ ] **4.1 Найти файл заглушки**
|
||||
`grep -rl "class FakeCompetitorAgent" .claude/worktrees/avtopodbor/app/app` — зафиксировать путь и
|
||||
текущий вид `findCompetitors` / `studyCompetitor`.
|
||||
|
||||
- [ ] **4.2 Написать падающий тест** (Pest, real-код, без моков)
|
||||
В `tests/Feature/Autopodbor/` новый тест: `studyCompetitor` возвращает ≥3 источника, среди них
|
||||
есть и `phone_type='city'`, и `'mobile'`, и `'tollfree'`, и хотя бы один `phone_kind='substitute'`.
|
||||
Использовать `uses(SharesSupplierPdo::class)` + `SET LOCAL app.current_tenant_id` при записи.
|
||||
|
||||
- [ ] **4.3 Прогнать — убедиться, что падает**
|
||||
`cd .claude/worktrees/avtopodbor/app && DB_DATABASE=liderra_testing php artisan migrate --force && php vendor/bin/pest tests/Feature/Autopodbor/<NewTest>.php`
|
||||
Ожидание: FAIL (сейчас типов меньше/однообразны).
|
||||
|
||||
- [ ] **4.4 Минимальная правка заглушки**
|
||||
В `FakeCompetitorAgent::studyCompetitor` вернуть реалистичный набор источников с разными
|
||||
`phone_type` и `phone_kind`. Только заглушка, прод-интерфейс `CompetitorAgent` не трогать.
|
||||
|
||||
- [ ] **4.5 Прогнать — зелёный + регресс**
|
||||
`php vendor/bin/pest tests/Feature/Autopodbor tests/Unit/Autopodbor`
|
||||
Ожидание: новый PASS, остальные автоподбор-тесты зелёные.
|
||||
|
||||
- [ ] **4.6 Пересобрать фронт и перезалить демо-поле** (чтобы поставка была видна в UI)
|
||||
`npm run build`; при необходимости пере-сид `OmegaDemoFieldSeeder` на `liderra_dumbtest`.
|
||||
НИЧЕГО не коммитить.
|
||||
|
||||
---
|
||||
|
||||
## Звено 5 — Прогон глазами (Playwright), блоки A–G
|
||||
|
||||
Для каждого пункта: записать **ожидал → увидел**, снять скрин при спотыкании.
|
||||
|
||||
- [ ] **5.A** A1 первый взгляд · A2 пустое поле (отдельный пустой тенант/раздел) · A3 баннер-черновик.
|
||||
- [ ] **5.B** B1 пусто→Поехали · B2 один пример · B3 мусор-сайт · B4 «+ ещё» ×много · B5 федералы ·
|
||||
B6 двойной клик · B7 Отмена · B8 нехватка баланса. (баланс проверяется в звене 7)
|
||||
- [ ] **5.C** C1 без названия · C2 пусто · C3 кривой % · C4 кривые ссылки · **C5 находка M3**
|
||||
(похожесть+ссылки 2ГИС/Яндекс — сохранились?).
|
||||
- [ ] **5.D** D1 «Собрать источники» 50 ₽ (пусто/повтор/отмена/нехватка) · D2 источник вручную
|
||||
(сайт/телефон/кривой телефон/тип) · **D3 поставка Агента** — значки ✓/🎭 и тип верны.
|
||||
- [ ] **5.E** E1 создать проект (лимит 0/огромный/дни сняты/отмена) · E2 Настройки/Изменить/Сменить
|
||||
источник (тип залочен, подтверждение, тексты 18:00/21:00) · E3 удалить с активным проектом (гвард 409).
|
||||
- [ ] **5.F** F1 ≥2 конкурента массово · F2 ≥2 источника массово · F3 смешанный выбор ·
|
||||
F4 выбрать всех/снять/уход с экрана.
|
||||
- [ ] **5.G** G1 единый вид Поле↔Предложения · G2 перенос один/массово · G3 править/удалить
|
||||
предложение · G4 «Собрать» из Предложений → окно 300 ₽.
|
||||
- [ ] **5.J** Админ `/admin/autopodbor-pricing`: J1 сменить цену (причина <30 → блок; ≥30 → сохранение) ·
|
||||
J2 проверить, что окна сбора у клиента показывают новую цену.
|
||||
|
||||
---
|
||||
|
||||
## Звено 6 — Визуал (frontend-design + Playwright)
|
||||
|
||||
- [ ] **6.1** Каждый экран бок-о-бок :8001 vs :8123 — `browser_take_screenshot` обоих, сравнить
|
||||
палитру Forest, шрифты, отступы, иерархию.
|
||||
- [ ] **6.2** Состояния: пустые, спиннеры, модалки, тосты, бейджи (✓/🎭, фед/рег), панель массовых действий.
|
||||
- [ ] **6.3** Адаптив: `browser_resize` 390×844 (мобильный) — ничего не разъехалось; затем обратно.
|
||||
- [ ] **6.4** Расхождения палитры/шрифтов/отступов — в находки с скрином.
|
||||
|
||||
---
|
||||
|
||||
## Звено 7 — Деньги (Laravel Boost database-query)
|
||||
|
||||
Для каждого платного действия — баланс ДО/ПОСЛЕ через `mcp__laravel-boost__database-query`
|
||||
(подключение к `liderra_dumbtest`).
|
||||
|
||||
- [ ] **7.1** Снять баланс тенанта ДО (таблица балансов/тенанта).
|
||||
- [ ] **7.2** H1: после успешного «Собрать конкурентов» — списано ровно 300 ₽; «Собрать источники» — ровно 50 ₽.
|
||||
- [ ] **7.3** H2: при пустом результате — баланс НЕ изменился (списания нет).
|
||||
- [ ] **7.4** H3: двойной клик — ровно одно списание, не два (сверить транзакции/идемпотентность).
|
||||
- [ ] **7.5** H4: при нехватке — действие заблокировано, баланс не ушёл в минус.
|
||||
- [ ] **7.6** Сверить таблицу транзакций списаний на дубли/«висяки».
|
||||
|
||||
---
|
||||
|
||||
## Звено 8 — Корень бага (systematic-debugging, только если падает)
|
||||
|
||||
- [ ] **8.1** На каждое реальное падение из звеньев 5–7 — отдельная гипотеза, фальсификация командой,
|
||||
корневая причина. Не «замазывать» симптом.
|
||||
|
||||
---
|
||||
|
||||
## Звено 9 — Независимая перепроверка (субагент + verification)
|
||||
|
||||
- [ ] **9.1** Дать субагенту-скептику (`Explore`/general-purpose) список находок: воспроизвести,
|
||||
отсеять ложные, подтвердить реальные.
|
||||
- [ ] **9.2** Прогнать skill `superpowers:verification` по своим выводам — нет ли выданного за
|
||||
проверенное без доказательства.
|
||||
- [ ] **9.3** Отранжировать находки по «больно клиенту» (блокер / спотыкание / косметика).
|
||||
|
||||
---
|
||||
|
||||
## Звено 10 — Отчёт
|
||||
|
||||
- [ ] **10.1** Файл `docs/superpowers/findings/2026-06-30-konkurentnoe-pole-dumb-client-RESULTS.md`:
|
||||
находки (UX + визуал + деньги), по приоритету, со скринами и «ожидал → увидел».
|
||||
- [ ] **10.2** Рекомендации по улучшению (что и почему).
|
||||
- [ ] **10.3** Краткий устный итог владельцу простым русским.
|
||||
|
||||
---
|
||||
|
||||
## Рамки (жёстко)
|
||||
- Прод (liderra.ru / Managed PG) и gitea — НЕ трогать. БД операций — только `liderra_dumbtest`.
|
||||
- Правки заглушки Агента — dev-only, в коммит/прод не уходят.
|
||||
- Ничего не коммитить без «эскейп». Простой русский в отчётах.
|
||||
|
||||
## Самопроверка плана
|
||||
- Покрытие спеки A–J: A→5.A, B→5.B+7, C→5.C, D→4+5.D, E→5.E, F→5.F, G→5.G, H→7, I→6, J→ (добавить ниже).
|
||||
- **J (админ-тарифы)** — отдельный шаг: после звена 7 зайти в `/admin/autopodbor-pricing`, сменить
|
||||
цену (причина <30 → блок; ≥30 → сохранение), проверить что окна сбора показывают новую цену. → **5.J**
|
||||
- Плейсхолдеров нет; пути/команды конкретны (путь заглушки — найти grep в 4.1, это шаг, не плейсхолдер).
|
||||
@@ -0,0 +1,93 @@
|
||||
# Тест «Конкурентного поля» глазами «самого тупого клиента» — спека (согласовано 30.06.2026)
|
||||
|
||||
Персона: **самый тупой клиент на свете**. Любое место, где он может ошибиться, споткнуться
|
||||
или не понять — это находка. Глубина **полная**, база **свежая изолированная**.
|
||||
|
||||
Связано: [хартия+цепочка скилов](../plans/2026-06-30-konkurentnoe-pole-DUMB-CLIENT-TEST-charter.md) ·
|
||||
[находки прототип↔реализация](../findings/2026-06-30-konkurentnoe-pole-proto-vs-impl-gap.md) ·
|
||||
[HANDOFF фичи](../plans/2026-06-29-konkurentnoe-pole-HANDOFF.md) ·
|
||||
эталон-прототип `docs/superpowers/prototypes/2026-06-29-konkurentnoe-pole-proto.html` (:8123).
|
||||
|
||||
Решение владельца 30.06: чек-лист A–J принят целиком («Всё так, фиксируй и поехали») —
|
||||
**с** эмуляцией поставки Агента (D3), **с** визуалом (I), **без** отдельного сквозного лид→сделка
|
||||
(не выбран). Эмуляция Агента — dev-only, в прод/коммит не уходит.
|
||||
|
||||
---
|
||||
|
||||
## Чек-лист сценариев (согласован)
|
||||
|
||||
### A. Вход и первый взгляд
|
||||
- A1 — первый взгляд на «Поле»: понятно ли, что делать.
|
||||
- A2 — пустое «Поле»: есть ли подсказка «начните отсюда», не пугает ли пустота.
|
||||
- A3 — баннер-черновик «Лидерра подготовила N в предложениях» — клик ведёт куда ожидаешь.
|
||||
|
||||
### B. Сбор конкурентов «Собрать» (платно, 300 ₽)
|
||||
- B1 — пустые поля → «Поехали»: мягко остановить, НЕ списать.
|
||||
- B2 — один пример вместо двух.
|
||||
- B3 — мусор в сайт («ааа», «http://», «телефон сюда»).
|
||||
- B4 — «+ ещё пример» нажать много раз.
|
||||
- B5 — федералы Да/Нет — переключения.
|
||||
- B6 — двойной клик «Поехали» → не списать 300 дважды.
|
||||
- B7 — «Отмена» на полпути → деньги целы.
|
||||
- B8 — баланса не хватает → блок, не в минус.
|
||||
|
||||
### C. Добавить конкурента вручную
|
||||
- C1 — без названия. C2 — пусто (без сайта и справочника).
|
||||
- C3 — кривой % (−5, 999, буквы). C4 — кривые ссылки 2ГИС/Яндекс.
|
||||
- C5 — проверка находки **M3**: похожесть + ссылки 2ГИС/Яндекс сохранились или молча пропали.
|
||||
|
||||
### D. Изучение конкурента → источники (платно, 50 ₽)
|
||||
- D1 — «Собрать источники» (50 ₽): пусто / повтор / отмена / нехватка денег (аналог B1–B8).
|
||||
- D2 — добавить источник вручную: сайт vs телефон, кривой телефон, переключение типа
|
||||
(городской/мобильный/8-800 + настоящий ✓ / подменный 🎭).
|
||||
- D3 — **эмуляция Агента**: «поставка» вернула реалистичные источники с разными типами
|
||||
телефонов — значки ✓/🎭 и тип отображаются верно.
|
||||
|
||||
### E. Проекты из источника
|
||||
- E1 — создать проект: регион/лимит/дни; лимит 0; лимит огромный; все дни сняты; отмена.
|
||||
- E2 — Настройки / Изменить источник / Сменить источник: тип залочен; подтверждение смены;
|
||||
тексты сроков 18:00 / 21:00 МСК не путают.
|
||||
- E3 — удалить конкурента/источник с активным проектом → мягкий гвард 409.
|
||||
|
||||
### F. Групповые действия
|
||||
- F1 — ≥2 конкурента: вкл/выкл проекты массово.
|
||||
- F2 — ≥2 источника: создать/пауза/возобновить/удалить массово.
|
||||
- F3 — смешанный выбор (с проектом и без).
|
||||
- F4 — «Выбрать всех» / «Снять выбор»; уход на другой экран — сброс выбора.
|
||||
|
||||
### G. Предложения (доведённая находка F1)
|
||||
- G1 — вид «Поле» ↔ «Предложения» единый, не «прыгает».
|
||||
- G2 — перенос одного / массово «в поле».
|
||||
- G3 — править / удалить предложение в списке.
|
||||
- G4 — «Собрать конкурентов» из «Предложений» открывает то же окно 300 ₽.
|
||||
|
||||
### H. Деньги (сверка по базе, звено 7)
|
||||
- H1 — баланс ДО/ПОСЛЕ каждого платного действия (300/50).
|
||||
- H2 — пустой результат → не списали.
|
||||
- H3 — двойной клик → списали один раз.
|
||||
- H4 — нехватка → блок, не в минус.
|
||||
|
||||
### I. Визуал (звено 6, обязателен)
|
||||
- I1 — каждый экран бок-о-бок с :8123: палитра Forest, шрифты, отступы, иерархия.
|
||||
- I2 — пустые состояния, спиннеры, модалки, тосты, бейджи, панель массовых действий.
|
||||
- I3 — адаптив: сжать до мобильного — ничего не разъехалось.
|
||||
|
||||
### J. Админ (тарифы)
|
||||
- J1 — экран «Тарифы «Конкурентного поля»»: смена цены; причина <30 (не даёт); причина ОК → сохранил.
|
||||
- J2 — цены подхватились на клиентской стороне (300/50 в окнах сбора).
|
||||
|
||||
---
|
||||
|
||||
## Критерии успеха
|
||||
- Каждый пункт A–J пройден глазами клиента (Playwright) и зафиксирован «ожидал → увидел».
|
||||
- Деньги (H) сверены по базе ДО/ПОСЛЕ; ни одного ложного/двойного списания, ни одного минуса.
|
||||
- Визуал (I) сверен с эталоном; расхождения палитры/шрифтов/отступов — в находки.
|
||||
- Все находки независимо перепроверены (звено 9) и отранжированы по «больно клиенту».
|
||||
|
||||
## Рамки
|
||||
- Прод (liderra.ru / Managed PG) и gitea — НЕ трогать.
|
||||
- Тест-БД и правки заглушки Агента — только стенд; в прод/коммит не уходят.
|
||||
- Ничего не коммитить без «эскейп» владельца. Простой русский в отчётах.
|
||||
|
||||
## Статус
|
||||
Спека согласована 30.06.2026. Следующий шаг — звено 2 (writing-plans): пошаговый сценарий прогона.
|
||||