(high) trade-in/page.tsx restoredEstimate: восстановленный по shared-ссылке отчёт показывает выдуманные параметры объекта (0 м², «Студия», «0 из 0», чужой адрес) #1424

Closed
opened 2026-06-15 05:53:56 +00:00 by bot-backend · 1 comment
Collaborator

Severity: high · Категория: report · Файл: frontend/src/app/trade-in/page.tsx:62-75

page.tsx:62-75 — при восстановлении результата из URL (?id=...) синтезируется фиктивный input: address = restoredEstimate.data.analogs[0]?.address (адрес ПЕРВОГО аналога — чужого объявления, тип AnalogLot.address, types/trade-in.ts:28), а area_m2/rooms/floor/total_floors жёстко = 0. EstimateResult.tsx (строки 233-243) безусловно рендерит блок «Параметры объекта» по полям input: «Площадь» → ${0} м² = «0 м²»; «Комнат» → input.rooms === 0 ? 'Студия' (строка 238) = «Студия»; «Этаж» → 0 из 0; «Балкон» → has_balcony undefined → «Нет». Импакт: любой, кто открыл расшаренную ссылку или обновил страницу с ?id, в клиентском отчёте по оценке недвижимости видит характеристики объекта, заполненные неверными данными (квартира объявлена студией 0 м² на 0 этаже по чужому адресу), при этом оценочная цена реальная — рассинхрон данных и текста в отчёте. Как чинить: либо бэкенд должен возвращать оригинальный input вместе с AggregatedEstimate (добавить поле input в схему) и рендерить его при restore, либо при отсутствии исходного input не рендерить карточку «Параметры объекта» (скрывать секцию для restored-кейса вместо подстановки нулей/чужого адреса).

Почему баг: EstimateResult.tsx (строки 205-296) всегда рендерит блок «Параметры объекта» по полям input. Для restored-кейса это даёт: «Площадь» → ${0} м² = «0 м²»; «Комнат» → input.rooms === 0 ? 'Студия' = «Студия» (строка 238 EstimateResult — ноль трактуется как студия!); «Этаж» → 0 из 0; «Балкон» → has_balcony undefined → «Нет». Плюс «Адрес» = адрес первого аналога, а не самой квартиры. Это клиентский отчёт по оценке недвижимости: любой, кто открыл расшаренную ссылку или обновил страницу с ?id, видит блок характеристик объекта, заполненный неверными/выдуманными данными (квартира объявляется студией 0 м² на 0 этаже по чужому адресу), хотя оценочная цена при этом реальная — рассинхрон данных и текста в отчёте.

Как чинить: Не рендерить карточку «Параметры объекта» в restored-режиме (передавать флаг restored в EstimateResult и скрывать блок), либо хранить исходный input на бэке вместе с estimate и возвращать его в GET /estimate/{id}, либо не подставлять заведомо ложные 0/«Студия»/чужой адрес, а показывать прочерки «—» по всем полям.


deep-audit «армия ботов 2» · verify+harden, confidence 0.95 · unit U84

**Severity:** high · **Категория:** report · **Файл:** `frontend/src/app/trade-in/page.tsx:62-75` page.tsx:62-75 — при восстановлении результата из URL (?id=...) синтезируется фиктивный input: address = restoredEstimate.data.analogs[0]?.address (адрес ПЕРВОГО аналога — чужого объявления, тип AnalogLot.address, types/trade-in.ts:28), а area_m2/rooms/floor/total_floors жёстко = 0. EstimateResult.tsx (строки 233-243) безусловно рендерит блок «Параметры объекта» по полям input: «Площадь» → `${0} м²` = «0 м²»; «Комнат» → `input.rooms === 0 ? 'Студия'` (строка 238) = «Студия»; «Этаж» → `0 из 0`; «Балкон» → has_balcony undefined → «Нет». Импакт: любой, кто открыл расшаренную ссылку или обновил страницу с ?id, в клиентском отчёте по оценке недвижимости видит характеристики объекта, заполненные неверными данными (квартира объявлена студией 0 м² на 0 этаже по чужому адресу), при этом оценочная цена реальная — рассинхрон данных и текста в отчёте. Как чинить: либо бэкенд должен возвращать оригинальный input вместе с AggregatedEstimate (добавить поле input в схему) и рендерить его при restore, либо при отсутствии исходного input не рендерить карточку «Параметры объекта» (скрывать секцию для restored-кейса вместо подстановки нулей/чужого адреса). **Почему баг:** EstimateResult.tsx (строки 205-296) всегда рендерит блок «Параметры объекта» по полям input. Для restored-кейса это даёт: «Площадь» → `${0} м²` = «0 м²»; «Комнат» → `input.rooms === 0 ? 'Студия'` = «Студия» (строка 238 EstimateResult — ноль трактуется как студия!); «Этаж» → `0 из 0`; «Балкон» → has_balcony undefined → «Нет». Плюс «Адрес» = адрес первого аналога, а не самой квартиры. Это клиентский отчёт по оценке недвижимости: любой, кто открыл расшаренную ссылку или обновил страницу с ?id, видит блок характеристик объекта, заполненный неверными/выдуманными данными (квартира объявляется студией 0 м² на 0 этаже по чужому адресу), хотя оценочная цена при этом реальная — рассинхрон данных и текста в отчёте. **Как чинить:** Не рендерить карточку «Параметры объекта» в restored-режиме (передавать флаг restored в EstimateResult и скрывать блок), либо хранить исходный input на бэке вместе с estimate и возвращать его в GET /estimate/{id}, либо не подставлять заведомо ложные 0/«Студия»/чужой адрес, а показывать прочерки «—» по всем полям. --- <sub>deep-audit «армия ботов 2» · verify+harden, confidence 0.95 · unit U84</sub>
bot-backend added the
week ревью 1
label 2026-06-15 05:53:56 +00:00
bot-backend added the
scope/frontend
label 2026-06-15 11:02:02 +00:00
Owner

🔍 week ревью 1 — верификация (ПОДТВЕРЖДЕНО)

Текущее состояние кода: frontend/src/app/trade-in/page.tsx:62-75 (синтез фиктивного input); рендер в frontend/src/components/trade-in/EstimateResult.tsx:233-243 (Адрес/Площадь/Комнат/Этаж), guard на нулях отсутствует.

Корень: при restore по ?id= (freshResult===null, оценка тянется useEstimate(urlEstimateId)) исходный input не сохранён → собирается заглушка { address: restoredEstimate.data.analogs[0]?.address ?? "—", area_m2: 0, rooms: 0, floor: 0, total_floors: 0 }. EstimateResult безусловно печатает: ${input.area_m2} м² → «0 м²» (стр.235), input.rooms === 0 ? "Студия" → «Студия» (стр.238), ${input.floor} из ${input.total_floors} → «0 из 0» (стр.242), адрес — из первого аналога (чужого объявления).

Что править:

  • Предпочтительно: backend сохраняет исходный input при создании оценки и возвращает его в GET /api/v1/trade-in/estimate/{id}; рендерить реальный input при restore.
  • Минимум на фронте: передать в EstimateResult флаг restored (или признак синтетического input) и скрывать карточку «Параметры объекта» + адрес, либо показывать «—»/«данные не сохранены» при area_m2===0/total_floors===0.

Что посмотреть:

  • Код: page.tsx:58-75 (сборка resultData.input), EstimateResult.tsx:233-269 (блок «Параметры объекта»), lib/trade-in-api.ts:31-39 (useEstimate), backend GET /estimate/{id} схема (AggregatedEstimate).
  • Vault: релевантных заметок не найдено.
**🔍 week ревью 1 — верификация (ПОДТВЕРЖДЕНО)** **Текущее состояние кода:** `frontend/src/app/trade-in/page.tsx:62-75` (синтез фиктивного input); рендер в `frontend/src/components/trade-in/EstimateResult.tsx:233-243` (Адрес/Площадь/Комнат/Этаж), guard на нулях отсутствует. **Корень:** при restore по `?id=` (`freshResult===null`, оценка тянется `useEstimate(urlEstimateId)`) исходный input не сохранён → собирается заглушка `{ address: restoredEstimate.data.analogs[0]?.address ?? "—", area_m2: 0, rooms: 0, floor: 0, total_floors: 0 }`. EstimateResult безусловно печатает: `${input.area_m2} м²` → «0 м²» (стр.235), `input.rooms === 0 ? "Студия"` → «Студия» (стр.238), `${input.floor} из ${input.total_floors}` → «0 из 0» (стр.242), адрес — из первого аналога (чужого объявления). **Что править:** - Предпочтительно: backend сохраняет исходный input при создании оценки и возвращает его в `GET /api/v1/trade-in/estimate/{id}`; рендерить реальный input при restore. - Минимум на фронте: передать в `EstimateResult` флаг `restored` (или признак синтетического input) и скрывать карточку «Параметры объекта» + адрес, либо показывать «—»/«данные не сохранены» при `area_m2===0`/`total_floors===0`. **Что посмотреть:** - Код: `page.tsx:58-75` (сборка `resultData.input`), `EstimateResult.tsx:233-269` (блок «Параметры объекта»), `lib/trade-in-api.ts:31-39` (`useEstimate`), backend `GET /estimate/{id}` схема (`AggregatedEstimate`). - Vault: релевантных заметок не найдено.
Sign in to join this conversation.
No milestone
No project
No assignees
2 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#1424
No description provided.