feat(tradein): brand-by-account + result IA redesign (distinct asking/sale prices) #683
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
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: lekss361/gendesign#683
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "feat/tradein-brand-by-account"
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?
Two user-reported UX issues: praktika account didn't get its branding (only via ?brand=), and the result page was confusing («непонятно что и как» — incl. two identical numbers). Reworks the result IA toward the Brusnika reference + makes branding account-bound.
BRAND BY ACCOUNT: /me now returns
brand(username→brand map: praktika/kopylov→"praktika"); useBrand resolves ?brand= param OR me.brand (param wins) → praktika is auto-branded on login. Non-mapped users → generic (unchanged).RESULT IA REDESIGN (HeroSummary): one «Ожидаемая цена сделки» headline (the outcome, lower, with −X% vs asking + «реальные сделки на 5–12% ниже объявлений»); below it TWO genuinely-distinct reference figures — «в объявлениях» (asking) vs «по фактическим сделкам ДКП·Росреестр» (dkp_corridor) — with price bars; a sources row; and 3 always-on explainer cards (asking≠real, ремонт по состоянию, скрытые расходы ≤15%). Comp tables (analogs/ДКП) already render downstream (ListingsCard/DealsCard/StreetDealsCard).
Pairs with PR #682 (expected_sold strictly < median) so the headline reads distinctly below asking. Commercial buyback section (Brusnika p.4) deferred — OfferCard stub + TODO, NO invented numbers (pending Praktika commercial terms).
Validated: tsc --noEmit clean; ruff clean; 35 backend tests (7 new /me-brand). DEPLOYED frontend = tradein-mvp/frontend.
Refs #657
Brand-by-account + result IA redesign (distinct asking/sale prices). Reviewed via subagent (6-dim). SECURITY solid: brand derived server-side from trusted X-Authenticated-User (Caddy {http.auth.user.id}, not client-controllable) via server-side _USERNAME_BRAND dict; brand selects only CSS/branding metadata, NOT data scope -> no spoofing/tenant-leak. NULL-SAFETY correct: hasSold gates expected-sale block, expected_sold null -> fallback to asking median (no -N% badge/NaN), showDiscount suppresses zero/negative/ratio>1; median=0 NaN gated off (sold null for empty est). TS strict clean (new fields ?:number|null, no any), backward-compat OK (old estimates render), ?brand= override still works, unknown brand -> generic fallback, rules-of-hooks OK, TanStack Query (no useEffect-fetch). OfferCard uses explicit STUB disclaimer (no fabricated buyout price). NITS (non-blocking, follow-up): stale ?brand= comment page.tsx:45; auth.py mirror-docstring should note brand is tradein-only extension. APPROVE.