Commit graph

180 commits

Author SHA1 Message Date
103dc22b8c Merge pull request 'feat(tradein/support): чат поддержки без входа — экран логина и «доступа нет»' (#2577) from feat/tradein-anon-support into main
All checks were successful
Deploy Trade-In / changes (push) Successful in 17s
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / test (push) Successful in 2m33s
Deploy Trade-In / build-frontend (push) Successful in 3m1s
Deploy Trade-In / build-backend (push) Successful in 1m16s
Deploy Trade-In / deploy (push) Successful in 1m22s
2026-07-31 13:22:20 +00:00
bot-backend
40fc94ee91 feat(tradein/support): чат поддержки без входа — экран логина и «доступа нет»
All checks were successful
CI / changes (pull_request) Successful in 12s
CI Trade-In / changes (pull_request) Successful in 12s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Successful in 1m42s
CI Trade-In / backend-tests (pull_request) Successful in 2m31s
После cutover'а на свою авторизацию (#2558) единственным каналом в поддержку
остался чат ЗА логином, а самая частая причина писать в поддержку — как раз
«не могу войти». 2026-07-31 это выстрелило: «Практика» весь день билась в форму
входа (5 неудачных попыток с трёх разных IP, ни одной успешной) и сообщить об
этом из продукта не могла ничем — на /login не было ни чата, ни контакта.

Backend — 4 ручки /api/v1/trade-in/support/anon/* (public в rbac_guard):
- Идентичность анонима — opaque-токен в httpOnly+Secure куке; тред живёт в тех
  же web_support_threads под ключом `anon:<token>`. Двоеточие делает коллизию с
  реальным логином структурно невозможной (CHECK миграции 193 разрешает только
  `^[A-Za-z0-9._-]{3,64}$`) — аноним не может попасть в чужой тред.
- Изоляция та же, что у авторизованной ветки: thread_id снаружи не принимается
  ни в каком виде, тред резолвится ИСКЛЮЧИТЕЛЬНО из куки.
- Форма куки валидируется — мусор из браузера не становится ключом треда.
- В Telegram-топик уходит не токен (это bearer треда), а `anon-<6 hex sha256>`;
  зеркало помечено «[С САЙТА · БЕЗ ВХОДА]» — оператору важно, что аккаунта нет.
- Анти-абуз: два бюджета — per-token (12/мин) и per-IP (10/10мин). Второй ловит
  обход ротацией куки, без него публичная ручка записи в общий топик беззащитна.
- Кука и запись в БД — только после успешного sendMessage (порядок операций H1),
  неудачная отправка не закрепляет за посетителем пустой тред.

Frontend:
- `SupportScope = "auth" | "anon"` в useSupportChat: scope выбирает базовый путь
  и входит в ключ кэша (иначе после логина в панели висела бы переписка анонима).
  Дефолт "auth" — существующие места монтирования не меняются.
- `AnonSupportWidget` монтируется на /login и в NoAccessScreen — обе точки тупики,
  из которых пользователю больше некуда идти. На /login добавлена подсказка.

Ответы оператора маршрутизируются без изменений в bridge.py: реплай резолвится
по topic_message_id → thread_id, кто автор треда — там неважно.

Тесты: 13 новых на анонимную ветку + 2 на границу public/authed в rbac_guard.
62 passed (test_support + test_rbac).
2026-07-31 16:04:51 +03:00
bot-backend
5817e0b31a fix(tradein/team): admin управляет менеджерами — сброс пароля и блокировка (#2556)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 12s
CI / changes (pull_request) Successful in 12s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Successful in 1m28s
CI Trade-In / backend-tests (pull_request) Successful in 2m27s
После cutover'а на DB-auth (#2558) аккаунты `kopylov` и `praktika` живут с
`role='manager'`, а team-API жёстко фильтровал `role='employee'` — сбросить
менеджеру пароль или заблокировать его было НЕЧЕМ, кроме ручного psql на проде.
Всплыло 2026-07-31: «Практика» весь день билась в логин (5 failed, 0 успешных),
а восстановить доступ через UI админ не мог.

Что меняется:
- `_fetch_employee_row` берёт actor: admin → `role IN ('employee','manager')`,
  manager → по-прежнему только `role='employee'` + свои по `manager_id`.
- `GET /employees` без фильтра отдаёт admin'у и менеджеров (`?manager_id=` —
  без изменений, только сотрудники этого менеджера).
- `EmployeeOut.role` — новое поле, UI показывает бейдж «менеджер» и
  склоняет тексты («Заблокировать менеджера ...» вместо «сотрудника»).

Инвариант self-lockout сохранён и усилен тестом: строки `role='admin'`
недостижимы через этот роутер ни для кого, включая самого админа, поэтому
ни block, ни смена пароля с `revoke_user_sessions` не могут вырубить
действующего админа. Раздача роли admin остаётся вне API.

Тесты: 6 новых (список с менеджерами, сброс пароля менеджеру + отзыв сессий,
блокировка, manager не достаёт до чужого менеджера, admin не достаёт до
admin-строки), 3 существующих обновлены под новое ожидание списка.
2026-07-31 15:51:50 +03:00
bot-backend
a3628843c3 fix(tradein/ui): вход в «Команду» из v2-навигации + понятный 401 (#2556)
All checks were successful
CI / changes (pull_request) Successful in 10s
CI Trade-In / changes (pull_request) Successful in 10s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Successful in 1m11s
`/trade-in/` редиректит на `/trade-in/v2`, а v2-навигация (TopNav.tsx)
не знала про team-дашборд вообще — пункт «Команда» был только в legacy
Topbar.tsx (NAV_ITEMS), который на v2-страницах не рендерится. Дашборд
существовал, но был недостижим кликом.

- app/v2/page.tsx: showTeamNavItem — тот же двойной гейт, что и
  Topbar.NAV_ITEMS "team" (isPathAllowed(/api/v1/team) + роль
  admin/manager), передаётся в TopNav.
- v2/TopNav.tsx: пункт «Команда» в user-меню рядом с «Выйти» (не таб
  SectionOverlay — /team отдельный роут, а не секция текущей страницы).

Второй дефект: team-API требует session-cookie, легаси Caddy-роль
(/me 200) через него не проходит → GET /api/v1/team/employees отдаёт
401, UI показывал невнятную красную плашку. app/team/page.tsx теперь
ловит 401 отдельно от 403 и уводит на /login?next=/team (тот же
redirect-паттерн, что RouteGuard.tsx для 401 от /me; в dev — сообщение
с кнопкой «Войти» вместо авто-редиректа, тот же NODE_ENV-гейт что и в
RouteGuard).
2026-07-31 00:13:46 +03:00
bot-backend
1ed0338b95 fix(tradein/ui): пагинация на границе страницы + запрос списка только для admin/manager (#2556)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 14s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI / changes (pull_request) Successful in 14s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Successful in 1m30s
EmployeeTable: убран ранний return при пустом списке — на offset>0 (ровно
50/100/150 сотрудников) пейджер и кнопка «Назад» теперь остаются доступны;
текст различает «сотрудников вообще нет» (offset=0) и «страница за концом
списка» (offset>0).

team/page.tsx: useEmployees получает enabled=isAllowedRole, вычисленный ДО
вызова хука — прямой заход employee/analyst/pilot на /team больше не шлёт
обречённый GET до отрисовки role-gate.
2026-07-30 22:12:18 +03:00
bot-backend
f112a4affb feat(tradein/ui): team-дашборд менеджера — сотрудники, квоты, история (#2556)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 9s
CI / changes (pull_request) Successful in 9s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Successful in 1m9s
Единая страница /team для ролей admin/manager (backend сам скоупит список
по org-изоляции) — таблица сотрудников с пагинацией, создание сотрудника
с ручным паролем, изменение месячной квоты + сброс пароля одним PATCH,
drawer с историей оценок. Nav-пункт «Команда» в Topbar виден только
admin/manager (доп. roleGate поверх isPathAllowed — legacy analyst-роль
иначе тоже прошла бы path-фильтр).
2026-07-30 22:02:41 +03:00
bot-backend
e6d68c349e fix(tradein/ui): харденинг sanitizeNext + сохранение query в next (#2555)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 9s
CI / changes (pull_request) Successful in 9s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Successful in 1m1s
PR #2562 review, 3 однострочника:
1. sanitizeNext обходился: WHATWG URL-парсер (router.push) вырезает ASCII
   tab/CR/LF из ВСЕЙ строки перед парсингом, так что "/\t//evil" проходил
   regex (позиция 1 — таб, не "/"/"\\"), а после навигации резолвился в
   protocol-relative "//evil" → чужой origin. Теперь сначала strip
   [\t\r\n], потом валидация — regex видит ту же строку, что увидит парсер.
2. next=/login (или /login?...) кидал юзера обратно на форму входа
   (RouteGuard не гейтит /login) — dead-end. Фолбэк на "/".
3. RouteGuard брал next= только из usePathname(), без query — сессия,
   истёкшая на deep-link (/v2?id=<uuid>), теряла отчёт после релогина.
   Добавлен window.location.search в next (effect всегда client-side).
2026-07-30 20:57:54 +03:00
bot-backend
15d506b7dd feat(tradein/ui): login-форма + session-aware RouteGuard (#2555)
All checks were successful
CI / changes (pull_request) Successful in 10s
CI Trade-In / changes (pull_request) Successful in 10s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Successful in 1m4s
POST /api/v1/auth/login/logout уже в main (DB-backed session, httponly
cookie tradein_session). Фронт: /login-форма (username+password, ошибки
401/429 по-русски, next= redirect с open-redirect guard), RouteGuard
редиректит на /login при 401 вместо NoAccessScreen variant=session
(prod-only, dev-режим без Caddy не трогаем), useLogout хук чистит
/me-кэш и уходит на /login. Role расширена admin|manager|employee (новые)
+ pilot|analyst|expired (legacy dual-mode resolver на бэке).
2026-07-30 20:46:33 +03:00
cf3d0eb4f6 fix(tradein/v2): доступность — ориентир главного содержимого и заголовок первого уровня (#2542)
All checks were successful
Deploy Trade-In / changes (push) Successful in 12s
Deploy Trade-In / test (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 2m4s
Deploy Trade-In / deploy (push) Successful in 49s
2026-07-26 22:03:43 +00:00
d6b9891fe2 fix(tradein/v2): заглушка карты в шапке заезжала под адресную карточку (#2537)
All checks were successful
Deploy Trade-In / changes (push) Successful in 13s
Deploy Trade-In / test (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 2m5s
Deploy Trade-In / deploy (push) Successful in 49s
2026-07-26 22:00:23 +00:00
580be61914 fix(tradein/location): заменить сломанный коэффициент локации на калиброванный индекс (#2531)
All checks were successful
Deploy / build-backend (push) Successful in 6m30s
Deploy / build-worker (push) Successful in 6m44s
Deploy / changes (push) Successful in 11s
Deploy Trade-In / changes (push) Successful in 15s
Deploy Trade-In / build-backend (push) Successful in 1m19s
Deploy / build-frontend (push) Has been skipped
Deploy / deploy (push) Successful in 2m26s
Deploy Trade-In / deploy (push) Successful in 3m10s
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 3m6s
Deploy Trade-In / test (push) Successful in 5m5s
2026-07-26 21:48:15 +00:00
a0647a53a9 feat(tradein/ui): окно чата поддержки на сайте вместо ухода в Telegram (#2533)
All checks were successful
Deploy Trade-In / changes (push) Successful in 12s
Deploy Trade-In / test (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 2m11s
Deploy Trade-In / deploy (push) Successful in 51s
2026-07-26 20:52:30 +00:00
c9ba1b15ba fix(tradein/v2): вернуть адресную карточку поверх карты и координаты при restore-by-id (#2530)
All checks were successful
Deploy Trade-In / changes (push) Successful in 13s
Deploy Trade-In / test (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 2m12s
Deploy Trade-In / deploy (push) Successful in 48s
2026-07-26 20:26:08 +00:00
06bf8dfada fix(tradein/ui): мини-карта адреса вместо статичного фото чужого дома в шапке (#2529)
All checks were successful
Deploy Trade-In / changes (push) Successful in 13s
Deploy Trade-In / test (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 2m18s
Deploy Trade-In / deploy (push) Successful in 51s
2026-07-26 20:15:54 +00:00
e0b63cc637 fix(tradein/v2): настоящая карта Leaflet+OSM вместо декоративного псевдо-SVG (#2528)
All checks were successful
Deploy Trade-In / changes (push) Successful in 13s
Deploy Trade-In / test (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 2m21s
Deploy Trade-In / deploy (push) Successful in 52s
2026-07-26 20:02:28 +00:00
bot-backend
7fd40f6ea5 feat(tradein/ui): вход в поддержку с сайта — плавающая кнопка + живая «Помощь»
All checks were successful
CI / changes (pull_request) Successful in 11s
CI Trade-In / changes (pull_request) Successful in 12s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Successful in 1m15s
Support-мост (#2526) уже работает на проде, но попасть в бота с сайта было
неоткуда — клиент о нём просто не узнавал.

Два входа, оба ведут в @MERAsupport_bot:
- SupportButton — плавающая кнопка в правом нижнем углу, на всех экранах /v2
- «Помощь» в меню TopNav — была задизейблена с «скоро появится», теперь живая

Закрывает перекос пошире: LeadForm монтируется только при hasEstimate
(v2/page.tsx:1064), т.е. до расчёта оценки у клиента не было НИ ОДНОГО способа
связаться. Единственная другая ссылка на связь во всём UI — NoAccessScreen.tsx:84,
и та лишь на экране «доступ закончился».

Решения:
- Это внешняя ссылка, а не чат-виджет: бот живёт в Telegram, поэтому ни API,
  ни состояния, ни сокетов не нужно.
- URL — module-константа, не NEXT_PUBLIC_*: env инлайнятся на build-time, так что
  переменная не дала бы гибкости рантайма, только лишний build-arg. Источник
  правды один — SUPPORT_BOT_URL в SupportButton.tsx, TopNav импортирует его.
- Монтаж в v2/layout, не в глобальный app/layout: последний накрывает ещё админку
  /scrapers/** и /sale-share — другой продукт без бренда МЕРА.
- createPortal в document.body: /v2 рисует HUD внутри артборда 1536×1024 с
  transform: scale(), а position:fixed внутри трансформированного предка
  позиционируется относительно него, а не вьюпорта — без портала кнопку унесло бы
  вместе с HUD.
- z-index 25 — осознанно НИЖЕ всех оверлеев v2 (SectionOverlay 29/30,
  LocationDrawer 40/41, TopNav 50, UserMenu 200): при открытой модалке кнопка
  должна уходить под неё, а не воровать клики и таб-порядок.
- Стиль только через tokens.ts (файл прямо запрещает хардкодить hex);
  готового <Button> в проекте нет, следуем инлайн-паттерну LeadForm.

Профиль/Настройки в том же меню остаются задизейбленными — страниц под них нет.

A11y: aria-label, тач-таргет 44px, focus-visible ring, инлайновый SVG с aria-hidden.

Проверка: tsc --noEmit чисто, lint чисто (3 warning'а pre-existing, не в этих
файлах), npm run build успешно (/v2 49.4 kB, все 15 страниц prerender).
Визуальная проверка — на проде после деплоя: локально RouteGuard без бекенда
возвращает null (RouteGuard.tsx:46) и рендер не доходит до кнопки.
2026-07-16 22:09:26 +03:00
67b50bf713 feat(tradein/ui): admin links to audit + analytics in UserMenu (#2524)
All checks were successful
Deploy Trade-In / changes (push) Successful in 11s
Deploy Trade-In / test (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 1m54s
Deploy Trade-In / deploy (push) Successful in 55s
Admin-only «Аудит доступа» → /admin/audit and «Активность» → /admin/analytics links in the UserMenu dropdown. Navigates via API_BASE_URL prefix (Topbar convention, basePath-safe). Pilot menu unchanged.
2026-07-13 21:16:29 +00:00
c904fbf94e feat(tradein/admin): audit + activity dashboards (Feature 2/3 UI) (#2521)
All checks were successful
Deploy Trade-In / changes (push) Successful in 10s
Deploy Trade-In / test (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 1m56s
Deploy Trade-In / deploy (push) Successful in 46s
Admin-only /admin/audit (accounts × IP/device × searches) and /admin/analytics (KPIs, daily chart, top searches/paths/accounts) over the user_events read API. Gated like /scrapers; 403 → NoAccessScreen.
2026-07-13 20:45:34 +00:00
2c5b30f8c9 fix(tradein/auth): RouteGuard session/error screens with retry CTA (#2516)
Some checks failed
Deploy Trade-In / test (push) Blocked by required conditions
Deploy Trade-In / build-backend (push) Blocked by required conditions
Deploy Trade-In / build-frontend (push) Blocked by required conditions
Deploy Trade-In / build-browser (push) Blocked by required conditions
Deploy Trade-In / deploy (push) Blocked by required conditions
Deploy Trade-In / changes (push) Has been cancelled
Co-authored-by: bot-frontend <bot-frontend@gendsgn.local>
Co-committed-by: bot-frontend <bot-frontend@gendsgn.local>
2026-07-13 20:19:12 +00:00
749c96cd0c feat(tradein/ui): Telegram feedback button in Topbar (env-gated) (#2514)
All checks were successful
Deploy Trade-In / changes (push) Successful in 12s
Deploy Trade-In / test (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 2m1s
Deploy Trade-In / deploy (push) Successful in 47s
Env-gated Telegram feedback button next to UserMenu; renders only when NEXT_PUBLIC_FEEDBACK_TG_URL is set. safeUrl() sanitized, outside RBAC nav.
2026-07-13 19:44:00 +00:00
69ca746673 fix(tradein/v2): location coefficient informational + price-history clarity (LOW audit R2 #7c/#8) (#2508)
Some checks failed
Deploy Trade-In / build-backend (push) Blocked by required conditions
Deploy Trade-In / deploy (push) Blocked by required conditions
Deploy Trade-In / changes (push) Successful in 10s
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / build-frontend (push) Has been cancelled
Deploy Trade-In / test (push) Has been cancelled
2026-07-12 22:11:08 +00:00
bot-backend
219cdfdbcc fix(tradein/v2): честность гистограмм и оси scatter + мобильный guard + a11y графика
All checks were successful
CI / changes (pull_request) Successful in 13s
CI Trade-In / changes (pull_request) Successful in 13s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Successful in 1m23s
- Гистограммы флагман-карточки (ОБЪЯВЛЕНИЯ) и ДКП/сделок биннятся по
  outlier-guarded пулу (guardPriceOutliers().clean) — консистентно с числом
  «выброс исключён» и спредом на той же карточке. Раньше bins8 спанил
  [min,max] ВКЛЮЧАЯ выброс 872k, схлопывая реальные аналоги в левые бины.
- Ось детального scatter «СРОК ПРОДАЖИ» → «СРОК НА РЫНКЕ»: для активных лотов
  x = дней на рынке (today−listing_date, нижняя граница), а не измеренный
  срок продажи. Обновлены title/aria-label/подзаголовок карточки.
- <1024px: honest desktop-only notice вместо нечитаемого ~25%-scaled артборда
  (client-side width guard, ранний return после всех хуков; десктоп не тронут).
- WCAG 2.1.1: точки истории цен теперь фокусируемы с клавиатуры
  (role=button / tabIndex / Enter+Space / onFocus-onBlur), мышиный hover сохранён.
2026-07-12 22:38:29 +03:00
fcc37c46ab fix(tradein/v2): аналитика — выровнять два графика в равную высоту (#2483)
All checks were successful
Deploy Trade-In / changes (push) Successful in 13s
Deploy Trade-In / build-browser (push) Successful in 29s
Deploy Trade-In / test (push) Successful in 49s
Deploy Trade-In / build-backend (push) Successful in 30s
Deploy Trade-In / build-frontend (push) Successful in 2m0s
Deploy Trade-In / deploy (push) Successful in 1m47s
2026-07-12 15:16:34 +00:00
338ccbb78f fix(tradein/v2): честность+консистентность — реконсиляция счётчика аналогов, убрать фейк-donut/линейку, outlier-guard, created_at, дисклеймеры (#2481)
All checks were successful
Deploy Trade-In / changes (push) Successful in 11s
Deploy Trade-In / test (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 1m55s
Deploy Trade-In / deploy (push) Successful in 44s
2026-07-12 15:09:10 +00:00
a88e755403 fix(tradein/v2): аналитика — 2 графика в ряд, чтобы Цена×срок влезала на экран (#2480)
All checks were successful
Deploy Trade-In / changes (push) Successful in 10s
Deploy Trade-In / test (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 1m55s
Deploy Trade-In / deploy (push) Successful in 44s
2026-07-12 14:56:08 +00:00
4f205bd7da fix(tradein/v2): polish АНАЛИТИКА — растянуть scatter, клэмп оси к 0, честные легенды/бакеты, убрать фейк-тренд (#2479)
All checks were successful
Deploy Trade-In / changes (push) Successful in 10s
Deploy Trade-In / test (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 1m53s
Deploy Trade-In / deploy (push) Successful in 43s
2026-07-12 14:37:05 +00:00
8dd35c01d8 feat(tradein/v2): карта вторички — сделки Росреестра + объявления по источникам (SourcesView) (#2478)
All checks were successful
Deploy Trade-In / changes (push) Successful in 11s
Deploy Trade-In / test (push) Has been skipped
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 2m3s
Deploy Trade-In / deploy (push) Successful in 45s
2026-07-12 13:26:55 +00:00
cfed042712 fix(tradein/v2): гонка при клике по строке «Предыдущие оценки» — отчёт не загружался (#2428)
All checks were successful
Deploy Trade-In / changes (push) Successful in 11s
Deploy Trade-In / test (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 2m3s
Deploy Trade-In / deploy (push) Successful in 46s
2026-07-04 14:47:01 +00:00
3a2b4ba825 feat(tradein/v2): кликабельные строки + параметры в оверлее «Предыдущие оценки» (#2424)
All checks were successful
Deploy Trade-In / changes (push) Successful in 10s
Deploy Trade-In / test (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 1m52s
Deploy Trade-In / deploy (push) Successful in 43s
2026-07-04 13:49:18 +00:00
155d5ec3a9 fix(tradein/v2): смонтировать форму лида (#2377) в живое v2-дерево (#2395) (#2398)
All checks were successful
Deploy Trade-In / changes (push) Successful in 10s
Deploy Trade-In / test (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 2m1s
Deploy Trade-In / deploy (push) Successful in 43s
2026-07-04 08:46:10 +00:00
a7e1391814 feat(tradein/v2): replace mailto lead CTA with real form (#2377) (#2393)
All checks were successful
Deploy Trade-In / changes (push) Successful in 10s
Deploy Trade-In / test (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 1m57s
Deploy Trade-In / deploy (push) Successful in 44s
2026-07-04 08:03:00 +00:00
98df57827e fix(tradein/v2): audit #2081 residual — 404 short-circuit, disabled-tab tooltips, stale hex token, ДКП decode (#2392)
All checks were successful
Deploy Trade-In / changes (push) Successful in 10s
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / test (push) Successful in 1m42s
Deploy Trade-In / build-frontend (push) Successful in 2m17s
Deploy Trade-In / build-backend (push) Successful in 33s
Deploy Trade-In / deploy (push) Successful in 4m52s
2026-07-04 07:47:56 +00:00
293184ebc6 fix(tradein/v2): mobile layout — remove overflow floor + honest stacked mobile block (#2275) (#2389)
All checks were successful
Deploy Trade-In / changes (push) Successful in 11s
Deploy Trade-In / test (push) Has been skipped
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 2m20s
Deploy Trade-In / deploy (push) Successful in 47s
2026-07-04 07:02:56 +00:00
1d9e25ce07 fix(tradein/v2): подключить реальные данные location-coef в LocationDrawer + HeroBar (#2317) (#2341)
All checks were successful
Deploy Trade-In / changes (push) Successful in 10s
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / test (push) Successful in 1m37s
Deploy Trade-In / build-frontend (push) Successful in 2m12s
Deploy Trade-In / build-backend (push) Successful in 53s
Deploy Trade-In / deploy (push) Successful in 1m9s
2026-07-03 22:47:40 +00:00
793234cff1 fix(tradein/v2): гейтить PDF-кнопку на hasEstimate (#2081 M4) (#2332)
All checks were successful
Deploy Trade-In / changes (push) Successful in 10s
Deploy Trade-In / test (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 1m56s
Deploy Trade-In / deploy (push) Successful in 42s
2026-07-03 22:16:00 +00:00
279e7de778 fix(tradein/v2): пометка «В ОФФЕР» + сузить реестровую карточку (#1991) (#2321)
All checks were successful
Deploy Trade-In / changes (push) Successful in 9s
Deploy Trade-In / test (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 2m6s
Deploy Trade-In / deploy (push) Successful in 52s
2026-07-03 21:28:50 +00:00
a8b504c3de fix(tradein/v2): визуальный аудит — иерархия/честность/микрокопи (#2266) (#2312)
All checks were successful
Deploy Trade-In / changes (push) Successful in 10s
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / test (push) Successful in 1m35s
Deploy Trade-In / build-frontend (push) Successful in 2m8s
Deploy Trade-In / build-backend (push) Successful in 56s
Deploy Trade-In / deploy (push) Successful in 47s
2026-07-03 20:35:38 +00:00
0e2b4998c8 Merge pull request 'fix(tradein/pii): удалить телефоны продавцов (NULL) + PII клиента (DROP) (#2217, #1969)' (#2303) from fix/tradein-pii-purge-phones-client into main
All checks were successful
Deploy Trade-In / changes (push) Successful in 10s
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / test (push) Successful in 2m16s
Deploy Trade-In / build-frontend (push) Successful in 3m28s
Deploy Trade-In / build-backend (push) Successful in 1m51s
Deploy Trade-In / deploy (push) Successful in 1m34s
2026-07-03 20:21:46 +00:00
3945060f0c Merge pull request 'feat(tradein/v2): реальный display-профиль в TopNav через /me (#2046)' (#2300) from feat/tradein-me-profile-fields into main
All checks were successful
Deploy Trade-In / changes (push) Successful in 10s
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / test (push) Successful in 1m38s
Deploy Trade-In / build-frontend (push) Successful in 2m21s
Deploy Trade-In / build-backend (push) Successful in 1m6s
Deploy Trade-In / deploy (push) Successful in 50s
2026-07-03 20:17:14 +00:00
bot-backend
6f170504ba fix(tradein/pii): удалить телефоны продавцов (NULL) + PII клиента (DROP) (#2217, #1969)
All checks were successful
CI / changes (pull_request) Successful in 9s
CI Trade-In / changes (pull_request) Successful in 10s
CI / frontend-tests (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Successful in 1m21s
CI Trade-In / backend-tests (pull_request) Successful in 1m46s
- listings.phones: миграция 166 обнуляет данные; cian.py + scraper-kit
  serp.py (golden-parity зеркало) перестают читать offer.get("phones") на
  входе — write-path выключен у источника, колонка/поле в модели остаются.
  Мёртвая запись "phones" в LISTING_FIELD_PRIORITY убрана.
- trade_in_estimates.client_name/client_phone: миграция 167 дропает колонки;
  синхронно убраны из TradeInEstimateInput, обоих INSERT в estimator.py
  (основной путь + _empty_estimate), frontend TradeInEstimateInput и
  CRM-блока EstimateForm (поля "Имя клиента"/"Телефон").
- sentry_scrub.py и management_companies.phones не тронуты — вне scope.
2026-07-03 23:00:42 +03:00
bot-backend
dafd12d9fa feat(tradein/v2): реальный display-профиль в TopNav через /me (#2046)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 9s
CI / changes (pull_request) Successful in 10s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Successful in 1m37s
CI Trade-In / backend-tests (pull_request) Successful in 2m0s
/me теперь отдаёт display_name/org/email (kopylov -> "Копылов", остальные None).
TopNav использует их вместо фабрикации username-as-name; org/email фолбэк
остаётся прежним для юзеров без известного профиля.
2026-07-03 22:55:12 +03:00
bot-backend
c672e0322d feat(tradein/v2): wire AnalyticsView + SourcesView overlays to real API data (#2040, #2041)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI / changes (pull_request) Successful in 8s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Successful in 1m19s
Audit of /trade-in/v2 found the FE-3/FE-4 overlay wiring (mapAnalytics/mapSources
feeding AnalyticsView/SourcesView from useEstimateHouseAnalytics,
useEstimateSellTimeSensitivity, analogs[]/actual_deals[]) already shipped in
267585e3. The remaining gap was BE-1 (#2043, merged 2026-07-02) landing real
cv/source_counts/created_at on AggregatedEstimate AFTER that wiring pass, so
v2/mappers.ts was still FE-approximating cv and duplicating a hardcoded source
label map instead of the single source-registry (#2211).

- mapSources' marketAds.kpi.cv (#2041) now prefers the real estimate.cv
  (0..1 ratio from BE-1) and only falls back to the FE coefficient-of-variation
  of analog prices for pre-#2043 cached estimates where cv is absent.
- adRows/dealRows source badges (#2041) now resolve via the shared
  src/lib/source-registry sourceLabel() instead of a local SOURCE_LABEL map,
  picking up etagi/canonical labels and staying in sync with the #2211 roster.
- AnalyticsView (#2040) KPIs/sell-time/price-history/scatterDetail were already
  wired to real data with no gaps found against the issue spec.
2026-07-03 22:49:30 +03:00
703f6f60c0 Merge pull request 'fix(tradein/v2/a11y): немодальный SectionOverlay + контраст токенов + headings — a11y round 3 (#2264)' (#2279) from fix/tradein-v2-a11y-round3 into main
Some checks failed
Deploy Trade-In / changes (push) Successful in 10s
Deploy Trade-In / test (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 3m27s
Deploy Trade-In / deploy (push) Has been cancelled
2026-07-03 07:47:09 +00:00
bot-backend
a3cab9023f fix(tradein/v2/a11y): немодальный SectionOverlay + контраст токенов + headings — a11y round 3 (#2264)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 16s
CI / changes (pull_request) Successful in 16s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Successful in 1m13s
- SectionOverlay: убран aria-modal (честный non-modal fullscreen-view); focus-trap
  теперь охватывает живой верхний nav + оверлей (query по артборду, фильтр [inert]),
  Tab из nav возвращается в оверлей, не в спрятанный main/footer.
- Контраст 6 muted/disabled токенов затемнён до >=4.6:1 vs worst-case #dce6f1
  (hue сохранён, lightness-only): muted2/3/4, hint, disabledValue/Label.
- accent -> accentDeep как мелкий текст: номер секции оверлея (15px), счётчик
  "Мои отчёты" (10px).
- Семантика заголовков: sr-only h1 «Мера — оценка квартиры» + h2 (оверлей,
  ResultPanel, ObjectSummary, placeholder-панели).
- HeroBar «КОЭФ. ЛОКАЦИИ»: role=button + tabIndex + Enter/Space + aria-label.
- Фокус после успешной оценки переносится на результат-регион (role=region,
  tabIndex=-1, aria-labelledby); live-region «Оценка готова» сохранён.
- Инпут focus-ring усилен (2px solid accentDeep).
- combobox адреса: aria-live анонс количества подсказок; aria-required на
  адрес + площадь; декоративные inline-SVG помечены aria-hidden.
2026-07-03 10:37:42 +03:00
bot-backend
ca0a51c876 chore(tradein/ui): вычистить источник n1 из source-registry и UI (#2204)
All checks were successful
CI / changes (pull_request) Successful in 9s
CI Trade-In / changes (pull_request) Successful in 9s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Successful in 1m36s
CI Trade-In / backend-tests (pull_request) Successful in 1m57s
2026-07-03 10:16:53 +03:00
bot-backend
9de867631b feat(tradein/ui): честное раскрытие покрытия диапазона в hero (#2209)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI / changes (pull_request) Successful in 8s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Successful in 1m3s
Хинт диапазона expected_sold дополнен замеренной точностью: «фактическая
цена продажи попадает в диапазон в ~80% случаев (июль 2026)» — по живому
бэктесту на реальных ДКП Росреестра (n=276, coverage 81.5%, engine=full).
Раскрытие вместо молчаливой выдачи Q1-Q3 за прогнозный интервал —
acceptance-пункт «явно раскрыть точность/покрытие» из #2209.

Refs #2209
2026-07-03 00:23:03 +03:00
19ecd941f3 fix(tradein/ui): единый source-registry + честные знаменатели/лейблы источников (#2211) (#2227)
All checks were successful
Deploy Trade-In / changes (push) Successful in 12s
Deploy Trade-In / test (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 3m3s
Deploy Trade-In / deploy (push) Successful in 1m4s
2026-07-02 20:57:26 +00:00
72d26b35fa fix(tradein): не запекать preview-флаг в прод-образ + noindex/баннер (#2205) (#2223)
All checks were successful
Deploy Trade-In / changes (push) Successful in 9s
Deploy Trade-In / build-browser (push) Successful in 33s
Deploy Trade-In / test (push) Successful in 1m35s
Deploy Trade-In / build-backend (push) Successful in 32s
Deploy Trade-In / build-frontend (push) Successful in 2m13s
Deploy Trade-In / deploy (push) Successful in 57s
2026-07-02 20:21:58 +00:00
e6000cb029 ci(tradein): pre-merge гейт — backend pytest + frontend type-check/lint (#2208) (#2220)
All checks were successful
Deploy Trade-In / changes (push) Successful in 10s
Deploy Trade-In / build-browser (push) Successful in 34s
Deploy Trade-In / test (push) Successful in 1m38s
Deploy Trade-In / build-backend (push) Successful in 1m29s
Deploy Trade-In / build-frontend (push) Successful in 3m21s
Deploy Trade-In / deploy (push) Successful in 1m18s
2026-07-02 19:56:22 +00:00
bot-backend
35a0e29122 fix(tradein/v2): keep top nav active over overlays, stronger «К оценке», backdrop-close
All checks were successful
CI / changes (pull_request) Successful in 6s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
Three UX fixes on the /trade-in/v2 overlays (feedback):

1. TopNav stays interactive while a section overlay is open. The a11y
   audit #2081 put inert on the whole content wrap (which contains
   TopNav), so opening an overlay disabled the top tabs. Move inert off
   the wrap onto <main>/<footer> only; the nav is inert just for the
   full-screen LocationDrawer. Users can now switch sections directly
   from an open overlay. role=dialog/aria-modal/Esc/focus-trap kept.

2. «← К ОЦЕНКЕ» made a clear filled primary button (solid accentDeep bg,
   white text ≥4.9:1 AA, shadow, hover lift) instead of the weak ghost
   pill. Uses existing accent tokens only.

3. Backdrop click closes the overlay. Add a transparent sibling layer
   below the panel (z below it, starting under the nav so tabs stay
   clickable); clicks in the margin close it. Clicks inside the panel /
   on its buttons never reach it (sibling, not ancestor) so they don't
   close. Esc + focus restore preserved.
2026-07-02 21:28:47 +03:00