[P1][tradein][frontend] StreetDealsCard: дисклеймер «по улице, не по дому» при data_quality=street_only #722

Closed
opened 2026-05-30 13:14:57 +00:00 by bot-analyst · 3 comments
Collaborator

Worker: это исполняемый спек. Делай ровно то, что ниже. Неясность/конфликт с кодом → коммент в issue, НЕ угадывай.
BLOCKED на #721 — этот issue читает поле data_quality, которое добавляет backend в #721. НЕ начинать пока #721 не смержен и data_quality не в ответе API. Решение: ADR variant 3 (честный дисклеймер вместо null-молчания).

Задача

В StreetDealsCard показать дисклеймер «Данные по улице, не по конкретному дому», когда data.data_quality === "street_only". Карточку НЕ скрывать. Добавить поле data_quality в TS-тип SalesVsListingsResponse.

Контекст

Backend (#721) добавляет в /sales-vs-listings enum data_quality: "house_linked" | "street_only" | "no_data". На текущих прод-данных всегда street_only (дом-уровневая привязка ДКП↔объявление физически невозможна из источника). Сейчас блок linkage рендерится только при hasAnyListing (стр. 86, data.deals_with_listings > 0), т.е. при street_only пользователь не понимает, почему пусто. Нужен честный дисклеймер.

Files (точные — проверено чтением)

  • tradein-mvp/frontend/src/types/trade-in.ts:
    • export interface SalesVsListingsResponse — строки 316–326. Последнее скалярное поле median_discount_pct: number | null; (стр. 324), затем pairs: SalesListingPair[]; (стр. 325). Добавить data_quality между ними.
  • tradein-mvp/frontend/src/components/trade-in/StreetDealsCard.tsx (компонент StreetDealsCard({ estimate }: Props) — строка 66):
    • const { data, isLoading, isError } = useSalesVsListings(...) — строка 67.
    • const hasAnyListing = data.deals_with_listings > 0; — строка 86.
    • Блок-заголовок <div className="card-head"> — строки 91–124; внутри {hasAnyListing && (<div className="linkage-hint">...)} — строки 95–116.

Контракт (точное соответствие backend #721)

В SalesVsListingsResponse (types/trade-in.ts, после median_discount_pct, стр. 324):

  data_quality: "house_linked" | "street_only" | "no_data";

Definition of Done (бинарно проверяемо)

  • grep -n 'data_quality' tradein-mvp/frontend/src/types/trade-in.ts → 1 совпадение (поле в интерфейсе).
  • В StreetDealsCard.tsx при data.data_quality === "street_only" рендерится текстовый дисклеймер, содержащий подстроку «по улице» (напр. «Данные по улице, не по конкретному дому»), размещённый в card-head (рядом с блоком linkage-hint, после стр. 116). grep -n 'по улице' tradein-mvp/frontend/src/components/trade-in/StreetDealsCard.tsx → ≥1.
  • Карточка НЕ размонтируется при street_only — существующий рендер (count-strip, data.total_deals стр. 130) остаётся виден; дисклеймер добавляется аддитивно.
  • cd tradein-mvp/frontend && npx tsc --noEmit → 0 ошибок.
  • cd tradein-mvp/frontend && npx eslint src/components/trade-in/StreetDealsCard.tsx src/types/trade-in.ts → clean.

Не делать (out of scope)

  • НЕ менять backend / API hook useSalesVsListings (контракт задан #721).
  • НЕ скрывать карточку, НЕ удалять/менять существующий {hasAnyListing && ...} linkage-hint блок (он остаётся для house_linked).
  • НЕ трогать /street-deals-часть и pair-рендер (SalesListingPair, стр. 87).

Depends on

  • #721 (backend data_quality field). Снять status/blockedstatus/ready только ПОСЛЕ merge #721.

Связано

  • ADR: vault inbox/2026-05-30-1604-main-session-adr-dkp-listing-linkage-impossible.
> Worker: это исполняемый спек. Делай ровно то, что ниже. Неясность/конфликт с кодом → коммент в issue, НЕ угадывай. > **BLOCKED на #721** — этот issue читает поле `data_quality`, которое добавляет backend в #721. НЕ начинать пока #721 не смержен и `data_quality` не в ответе API. Решение: ADR variant 3 (честный дисклеймер вместо null-молчания). ## Задача В `StreetDealsCard` показать дисклеймер «Данные по улице, не по конкретному дому», когда `data.data_quality === "street_only"`. Карточку НЕ скрывать. Добавить поле `data_quality` в TS-тип `SalesVsListingsResponse`. ## Контекст Backend (#721) добавляет в `/sales-vs-listings` enum `data_quality: "house_linked" | "street_only" | "no_data"`. На текущих прод-данных всегда `street_only` (дом-уровневая привязка ДКП↔объявление физически невозможна из источника). Сейчас блок linkage рендерится только при `hasAnyListing` (стр. 86, `data.deals_with_listings > 0`), т.е. при `street_only` пользователь не понимает, почему пусто. Нужен честный дисклеймер. ## Files (точные — проверено чтением) - `tradein-mvp/frontend/src/types/trade-in.ts`: - `export interface SalesVsListingsResponse` — строки **316–326**. Последнее скалярное поле `median_discount_pct: number | null;` (стр. 324), затем `pairs: SalesListingPair[];` (стр. 325). Добавить `data_quality` между ними. - `tradein-mvp/frontend/src/components/trade-in/StreetDealsCard.tsx` (компонент `StreetDealsCard({ estimate }: Props)` — строка **66**): - `const { data, isLoading, isError } = useSalesVsListings(...)` — строка **67**. - `const hasAnyListing = data.deals_with_listings > 0;` — строка **86**. - Блок-заголовок `<div className="card-head">` — строки **91–124**; внутри `{hasAnyListing && (<div className="linkage-hint">...)}` — строки **95–116**. ## Контракт (точное соответствие backend #721) В `SalesVsListingsResponse` (types/trade-in.ts, после `median_discount_pct`, стр. 324): ```ts data_quality: "house_linked" | "street_only" | "no_data"; ``` ## Definition of Done (бинарно проверяемо) - [ ] `grep -n 'data_quality' tradein-mvp/frontend/src/types/trade-in.ts` → 1 совпадение (поле в интерфейсе). - [ ] В `StreetDealsCard.tsx` при `data.data_quality === "street_only"` рендерится текстовый дисклеймер, содержащий подстроку **«по улице»** (напр. «Данные по улице, не по конкретному дому»), размещённый в `card-head` (рядом с блоком linkage-hint, после стр. 116). `grep -n 'по улице' tradein-mvp/frontend/src/components/trade-in/StreetDealsCard.tsx` → ≥1. - [ ] Карточка НЕ размонтируется при `street_only` — существующий рендер (`count-strip`, `data.total_deals` стр. 130) остаётся виден; дисклеймер добавляется аддитивно. - [ ] `cd tradein-mvp/frontend && npx tsc --noEmit` → 0 ошибок. - [ ] `cd tradein-mvp/frontend && npx eslint src/components/trade-in/StreetDealsCard.tsx src/types/trade-in.ts` → clean. ## Не делать (out of scope) - НЕ менять backend / API hook `useSalesVsListings` (контракт задан #721). - НЕ скрывать карточку, НЕ удалять/менять существующий `{hasAnyListing && ...}` linkage-hint блок (он остаётся для house_linked). - НЕ трогать `/street-deals`-часть и pair-рендер (`SalesListingPair`, стр. 87). ## Depends on - **#721** (backend `data_quality` field). Снять `status/blocked` → `status/ready` только ПОСЛЕ merge #721. ## Связано - ADR: vault `inbox/2026-05-30-1604-main-session-adr-dkp-listing-linkage-impossible`.
bot-analyst added the
priority/p1
scope/frontend
status/blocked
tradein
labels 2026-05-30 13:15:07 +00:00
bot-analyst added
status/ready
and removed
status/blocked
labels 2026-05-30 13:31:45 +00:00
Author
Collaborator

Разблокировано: зависимость #721 смержена (PR #723, data_quality enum в app/schemas/trade_in.py и /sales-vs-listings). Контракт API доступен → status/blockedstatus/ready. Frontend-worker может подхватывать.

Разблокировано: зависимость #721 смержена (PR #723, `data_quality` enum в `app/schemas/trade_in.py` и `/sales-vs-listings`). Контракт API доступен → `status/blocked` → `status/ready`. Frontend-worker может подхватывать.
bot-frontend self-assigned this 2026-05-30 13:36:47 +00:00
bot-frontend added
status/wip
and removed
status/ready
labels 2026-05-30 13:37:06 +00:00
bot-frontend added
status/review
and removed
status/wip
labels 2026-05-30 13:41:21 +00:00
Collaborator

Working on this in PR #725.

Working on this in PR #725.
bot-reviewer added
status/qa
and removed
status/review
labels 2026-05-30 13:44:35 +00:00
Collaborator

QA smoke PASS (PR #725, deployed & live on prod)

Result-страница street_only-estimate (Малышева, 1 — /sales-vs-listingsdata_quality="street_only", 47 ДКП-сделок), basic_auth user1, brand=praktika:

  • В StreetDealsCard (.linkage-hint в card-head) рендерится дисклеймер:

    «Данные по улице, не по конкретному дому: привязать сделки ДКП к отдельному объявлению по этому адресу нельзя — показаны все сделки на улице.»

  • Содержит требуемую подстроку «по улице» ✓ (+ «не по конкретному дому»).
  • Карточка НЕ скрыта: count-strip (47 сделок) + строки сделок с бейджем «ПО УЛИЦЕ» остаются видны — дисклеймер аддитивен ✓.
  • TS-тип/eslint/build — зелёные у воркера (tsc --noEmit 0, next build 10/10 pages).

Пользователь теперь видит честное объяснение пустого linkage вместо немой карточки. → status/done, closing.

NB: проверял на свежесозданном street_only-estimate (Малышева); дефолтный Олимп-estimate давал no_data (улица извлекается как «Екатеринбург») — для будущих QA #722-类 брать адрес с ненулевыми ДКП-сделками на улице.

✅ **QA smoke PASS** (PR #725, deployed & live on prod) Result-страница `street_only`-estimate (Малышева, 1 — `/sales-vs-listings` → `data_quality="street_only"`, 47 ДКП-сделок), basic_auth `user1`, brand=praktika: - В `StreetDealsCard` (`.linkage-hint` в card-head) рендерится дисклеймер: > «Данные по улице, не по конкретному дому: привязать сделки ДКП к отдельному объявлению по этому адресу нельзя — показаны все сделки на улице.» - Содержит требуемую подстроку **«по улице»** ✓ (+ «не по конкретному дому»). - Карточка НЕ скрыта: count-strip (47 сделок) + строки сделок с бейджем «ПО УЛИЦЕ» остаются видны — дисклеймер аддитивен ✓. - TS-тип/eslint/build — зелёные у воркера (`tsc --noEmit` 0, `next build` 10/10 pages). Пользователь теперь видит честное объяснение пустого linkage вместо немой карточки. → `status/done`, closing. NB: проверял на свежесозданном `street_only`-estimate (Малышева); дефолтный Олимп-estimate давал `no_data` (улица извлекается как «Екатеринбург») — для будущих QA #722-类 брать адрес с ненулевыми ДКП-сделками на улице.
bot-qa added
status/done
and removed
status/qa
labels 2026-05-30 13:58:40 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#722
No description provided.