fix(sf-fe): /site-finder — adapt B1 response shape (markers invisible) + restore CadInput #349
No reviewers
Labels
No labels
admin
analytics
auth
automation
bug
business
chore
ci
compliance
data
data-moat
docs
duplicate
dx
enhancement
Fable 5 ревью
feedback/max
generative
GG-форсайт
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
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: lekss361/gendesign#349
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "fix/sf-entry-parcel-adapter-cadinput"
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?
Summary
2 prod регрессии замеченных user после deploy #347:
Bug A — markers невидимы
Backend (B1) возвращает:
Frontend
useParcelsBboxQueryтипизировал ответ как плоскийParcelBboxItem[]с полями{lat, lon, area_ha, district, vri, address, status}. Результат:.map()итерировался по объекту, а не массиву → CircleMarker'ы не создавалисьcenter=[undefined, undefined]из-за разницы имёнFix: adapter в
queryFnраспаковывает.parcels, переименовываетcentroid_lat/centroid_lon → lat/lon, конвертируетarea_m2 → area_ha(÷10000),status: null → 'free'по умолчанию.district/vri/address— placeholders до enrichment B1 (—/other/"").applyFiltersостаётся client-side.Bug B — нет ручного ввода кадастра
A2 #343 при замене placeholders «потерял» существующий
<CadInput/>компонент (вход для quick analysis без клика по карте). Восстановлен в правый sidebar над<RecentParcels/>. Submit →router.push('/site-finder/analysis/{cad}').Verify
После deploy:
/site-finder— CircleMarker'ы на карте, tooltip сXX га66:41:0204016:10+ кнопка «Анализировать»/site-finder/analysis/{cad}Mock-mode (
NEXT_PUBLIC_USE_MOCKS=true) не affected — фикстура ParcelBboxItem уже в правильном shape.Tracking: B1 backend extension (district / vri / address) — vault
code/modules/site-finder/B1-enrichment.md(TBD).Deep Code Review — verdict APPROVE
Status: APPROVE
Files reviewed: 2 (P2:
frontend/src/app/site-finder/page.tsx,frontend/src/lib/site-finder-api.ts)Lines: +35 / -3
PR: #349
Adapter correctness (site-finder-api.ts)
raw.parcels.map(...)correctly unpacks{parcels, count, limit, bbox_area_km2}toParcelBboxItem[]— fixes the root cause where.map()ran on object instead of array.centroid_lat/centroid_lon -> lat/lon,area_m2 / 10000 -> area_ha— correct (1 ha = 10 000 m²). Null-safety onarea_m2 != null ? .../10000 : 0is right.status ?? "free"is type-safe —ParcelStatus = "free" | "in_progress" | "favorite"so"free"is a valid literal default.district: "—",vri: "other",address: ""are safe in context:applyFiltersspecial-casesvri === "other"(skip filter) anddistrict === ""(skip filter), so these placeholders won't accidentally filter out all rows when a user picks a real filter.district: "—"means a user-selecteddistrict !== "—"will reject everything; in practice the district dropdown is populated from real values so it's benign. Will resolve naturally when B1 enrichment lands.applyFiltersreused client-side — matches existing mock-path semantics, consistent.MOCK_PARCELS_BBOX) untouched, still returnsParcelBboxItem[]directly from fixture — correct.CadInput restore (page.tsx)
(cadNum: string) => void, loading: booleanmatches<CadInput onSubmit={handleCadSubmit} loading={false} />exactly.CadInputhas internalCAD_REGEX = /^\d+:\d+:\d+(?::\d+)?$/pre-validation before callingonSubmit, so the value reachingencodeURIComponent(cad)is already constrained to digits + colons → URL-safe.router.push(...encodeURIComponent(cad))— correct Next.js navigation, no full reload, no XSS (validated input + percent-encoding).<RecentParcels/>in the right sidebar matches PR description.TS strict / conventions
any, inline type forrawis explicit and bounded.queryKeyunchanged,staleTimeunchanged → no cache invalidation needed).Blast radius
useParcelsBboxQuerycallers (page.tsx, map components) continue to receiveParcelBboxItem[]— public hook signature unchanged, no callers need updating.Merging via squash.