feat(tradein/ui): передавать город в геокодирование + честный признак неопределённости (#2576) #2584
No reviewers
Labels
No labels
Fable 5 ревью
GG-форсайт
admin
analytics
auth
automation
bug
business
chore
ci
compliance
data
data-moat
docs
duplicate
dx
enhancement
feedback/max
generative
needs-discussion
needs-human
observability
pause-bots
performance
priority/p0
priority/p1
priority/p2
priority/p3
scope/backend
scope/db
scope/devops
scope/frontend
scope/qa
scrapers
security
site-finder
stage/1
stage/2
status/blocked
status/done
status/needs-analysis
status/needs-fix
status/qa
status/ready
status/review
status/wip
tech-debt
tradein
ux
week ревью 1
wontfix
ИРД
вторичка
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: lekss361/gendesign#2584
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "feat/tradein-ui-city-hint"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Эпик #2576, этап B — фронтовая половина к #2580. ⚠️ Мержить после #2580 (бэкенд владеет контрактом
city_hint/target_city_ambiguous).Без этого PR фикс геокодера половинчатый: бэкенд перестал молча подставлять Екатеринбург, но интерфейс город не передавал вовсе, и признак неопределённости срабатывал бы почти всегда.
Выбор города — выпадающий список + автоопределение. Список переиспользует существующий HUD-комбобокс панели, по умолчанию «Екатеринбург» — то есть ровно та строка, которую геокодер раньше подставлял молча, поэтому для Екатеринбурга поведение не меняется и лишних действий не требуется. Автоопределение (
detectCityInText, с границами слов, чтобы «Серов» не срабатывал внутри «ул. Серова») синхронизирует список, когда пользователь печатает или выбирает подсказку с другим городом.Текст при неопределённости (под полем адреса, предупреждающий цвет,
role="status", не блокирует):Файлы: новый
lib/city-registry.ts(6 городов +DEFAULT_CITY+ детектор, по образцуsource-registry.ts), типы,useGeocodeSuggest(query, cityHint?, limit)сcity_hintв URL и ключе кэша,ParamsPanel(селектор, проброс в payload, плашка),app/v2/page.tsx.Контракт сверен по фактическому коммиту
4b1a2822из #2580, а не по описанию.npm run codegenне запускался — бэкенд-PR не смержен, а этот файл типов ведётся вручную (по его же заголовку).tsc --noEmit+ lint + build чисто (/v2— 51.6 kB). Legacy-роут/не трогался:next.config.tsредиректит его на/v2.Проверить визуально на проде после мержа: длинная подпись «Каменск-Уральский» при ширине 176px и перекрытие выпадающего списка с панелью подсказок адреса.
Deep-review R2 на #2580/#2576: предыдущий коммит слал city_hint="Екатеринбург" даже когда дропдаун не тронут — бэкенд трактует ЛЮБОЙ city_hint как «пользователь назвал город» (city_specified=True), так что target_city_ambiguous становился false практически всегда, а необнаруженный житель Нижнего Тагила («Ленина, 1» без явного упоминания города) молча резолвился бы в Екатеринбург — ровно баг, который чинил backend, только переехавший из geocoder.py в city-registry.ts. Вариант A (по рекомендации ревьюера): город реально известен (и поэтому отправляется в city_hint) ТОЛЬКО когда пользователь явно выбрал его в дропдауне ИЛИ detectCityInText нашёл совпадение в наборном тексте / выбранной подсказке. Нетронутый дефолт → city_hint не уходит вовсе (ни в geocode/suggest, ни в POST /estimate) — тогда backend честно возвращает target_city_ambiguous и не форсит ЕКБ-bias без запроса. - Новое состояние `cityConfirmed` (ParamsPanel.tsx) — гейт на отправку, раздельный от `city` (best-guess для отображения/текста плашки). true после explicit dropdown pick ИЛИ автодетекта из текста/подсказки; sticky — мелкая правка адреса без нового совпадения его не сбрасывает. - До подтверждения дропдаун показывает `UNCONFIRMED_CITY_LABEL` ("Определить автоматически"), не статичное "Екатеринбург" — не выдаёт внутренний best-guess за подтверждённый пользователем выбор. - useGeocodeSuggest получает city_hint только при cityConfirmed=true — для нетронутой формы автокомплит тоже больше не форсит ЕКБ-bias молча, а видит кандидатов из всей области (в т.ч. Нижний Тагил) — это и есть тот сценарий из заголовка эпика. - ЕКБ happy path не усложнён: как только пользователь печатает город в адресе или (обычный путь) выбирает любую подсказку из автокомплита, detectCityInText почти всегда находит "Екатеринбург" в full_address (провайдер возвращает город как часть резолвленного адреса независимо от того, был ли отправлен hint) — дропдаун сам переключается на "Екатеринбург" и cityConfirmed становится true без отдельного клика. Требует лишнего действия только редкий путь "напечатал произвольный адрес без города и нажал Enter, не выбрав ни одной подсказки". - city-registry.ts: явный комментарий-ссылка на бэкендовый гэзеттир `SVERDLOVSK_OBLAST_CITIES` (tradein-mvp/backend/app/services/geocoder.py) — parity-риск при добавлении нового города остаётся видимым с фронтовой стороны (backend/тесты не трогаю — другой PR, вне моего scope). tsc --noEmit / next lint / next build — чисто (только 2 pre-existing warning в несвязанных файлах, как и в предыдущем коммите).Deep-review R3: плашка city_ambiguous всегда подставляла {city} — внутреннее состояние с дефолтом "Екатеринбург" (initCityLabel), а не то, что реально определил бэкенд (в ответе только булев target_city_ambiguous, угаданного города там нет). Ровно в целевом сценарии фикса — нетронутая форма, «Ленина 1», cityConfirmed=false — текст утверждал «если это не Екатеринбург» независимо от реального результата (там мог быть Нижний Тагил) — та же нечестность, которую предыдущий коммит убирал из запроса, только в тексте. Текст плашки теперь ветвится по cityConfirmed: - cityConfirmed=true (город реально был подтверждён и отправлен) — прежний текст с конкретным {city} уместен, не меняю. - cityConfirmed=false (это и есть путь, где cityAmbiguous обычно и срабатывает после предыдущего коммита) — нейтральная формулировка без упоминания конкретного города: «Если это неверно, выберите город выше и повторите оценку.» tsc --noEmit / next lint / next build — чисто (те же 2 pre-existing warning в несвязанных файлах).