gendesign/tradein-mvp/frontend/src/app/ui-preview/estimate/fixture.ts
bot-backend f22ca1f17e
Some checks failed
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / test (push) Has been skipped
Deploy Trade-In / build-frontend (push) Failing after 1s
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / deploy (push) Has been skipped
fix(tradein): seed sales-vs-listings → StreetDeals в preview (1:1) (#801) (#831)
Co-authored-by: bot-backend <bot-backend@gendsgn.local>
Co-committed-by: bot-backend <bot-backend@gendsgn.local>
2026-05-30 20:04:17 +00:00

413 lines
12 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// #801: статичная фикстура результата оценки для preview-маршрута (a11y/lighthouse).
// Полностью оффлайн — никакой сети. Значения правдоподобны (ЕКБ, 2-к вторичка),
// заполнены ВСЕ surface'ы «денежного экрана»: asking + expected-sold + Avito IMV +
// ДКП-коридор + cian valuation + price_trend + аналоги/сделки.
// photo_url=null у всех лотов — намеренно, чтобы не тянуть внешние картинки
// (чистый оффлайн-рендер для lighthouse/axe).
import type {
AggregatedEstimate,
AnalogLot,
HouseAnalyticsResponse,
HouseInfoForEstimate,
IMVBenchmarkResponse,
PlacementHistoryItem,
SalesVsListingsResponse,
SellTimeSensitivityResponse,
TradeInEstimateInput,
} from "@/types/trade-in";
const analogs: AnalogLot[] = [
{
address: "ул. Репина, 73",
area_m2: 54,
rooms: 2,
floor: 7,
total_floors: 16,
price_rub: 9_700_000,
price_per_m2: 179_629,
listing_date: "2026-05-12",
days_on_market: 18,
photo_url: null,
source: "avito",
source_url: "https://www.avito.ru/ekaterinburg/kvartiry/preview-1",
distance_m: 120,
tier: null,
lat: 56.8401,
lon: 60.5702,
},
{
address: "ул. Викулова, 33",
area_m2: 57,
rooms: 2,
floor: 4,
total_floors: 10,
price_rub: 9_950_000,
price_per_m2: 174_561,
listing_date: "2026-05-20",
days_on_market: 10,
photo_url: null,
source: "cian",
source_url: "https://www.cian.ru/sale/flat/preview-2",
distance_m: 340,
tier: null,
lat: 56.8389,
lon: 60.5681,
},
{
address: "ул. Кирова, 28",
area_m2: 53,
rooms: 2,
floor: 9,
total_floors: 12,
price_rub: 9_400_000,
price_per_m2: 177_358,
listing_date: "2026-05-04",
days_on_market: 31,
photo_url: null,
source: "avito",
source_url: "https://www.avito.ru/ekaterinburg/kvartiry/preview-3",
distance_m: 510,
tier: null,
lat: 56.8372,
lon: 60.5749,
},
];
const actualDeals: AnalogLot[] = [
{
address: "ул. Репина",
area_m2: 55,
rooms: 2,
floor: null,
total_floors: null,
price_rub: 8_800_000,
price_per_m2: 160_000,
listing_date: "2026-01-01",
days_on_market: null,
photo_url: null,
source: "rosreestr",
source_url: null,
distance_m: null,
tier: "T1_per_street",
lat: null,
lon: null,
},
{
address: "ул. Викулова",
area_m2: 58,
rooms: 2,
floor: null,
total_floors: null,
price_rub: 9_280_000,
price_per_m2: 160_000,
listing_date: "2025-10-01",
days_on_market: null,
photo_url: null,
source: "rosreestr",
source_url: null,
distance_m: null,
tier: "T1_per_street",
lat: null,
lon: null,
},
];
export const FIXTURE_ESTIMATE: AggregatedEstimate = {
estimate_id: "preview-0000-0000-0000-000000000000",
median_price_rub: 9_850_000,
range_low_rub: 9_100_000,
range_high_rub: 10_600_000,
median_price_per_m2: 178_000,
expected_sold_price_rub: 8_900_000,
expected_sold_range_low_rub: 8_300_000,
expected_sold_range_high_rub: 9_500_000,
expected_sold_per_m2: 160_800,
asking_to_sold_ratio: 0.9,
ratio_basis: "per_rooms",
confidence: "high",
confidence_explanation: "12 аналогов в радиусе 800 м, разброс цен ±9%.",
n_analogs: 12,
insufficient_data: false,
period_months: 24,
analogs,
actual_deals: actualDeals,
expires_at: "2026-06-30T00:00:00Z",
target_address: "Екатеринбург, ул. Репина, 75/2",
target_lat: 56.84,
target_lon: 60.57,
sources_used: ["avito", "cian", "rosreestr"],
data_freshness_minutes: 35,
last_scraped_at: "2026-05-30T12:00:00Z",
est_days_on_market: 48,
address_precision: "house",
area_m2: 55.3,
rooms: 2,
floor: 5,
total_floors: 11,
year_built: 2018,
house_type: "monolith",
repair_state: "good",
has_balcony: true,
cian_valuation: {
sale_price_rub: 9_700_000,
rent_price_rub: 42_000,
chart: [
{ date: "2025-11", price: 9_300_000 },
{ date: "2025-12", price: 9_420_000 },
{ date: "2026-01", price: 9_510_000 },
{ date: "2026-02", price: 9_560_000 },
{ date: "2026-03", price: 9_640_000 },
{ date: "2026-04", price: 9_700_000 },
],
chart_change_pct: 3.2,
chart_change_direction: "increase",
},
avito_imv: {
recommended_price: 10_200_000,
lower_price: 9_400_000,
higher_price: 11_000_000,
market_count: 7,
},
dkp_corridor: {
count: 9,
low_ppm2: 150_000,
median_ppm2: 162_000,
high_ppm2: 178_000,
period_months: 24,
},
price_trend: [
{ month: "2025-11", ppm2: 168_000 },
{ month: "2025-12", ppm2: 170_500 },
{ month: "2026-01", ppm2: 172_000 },
{ month: "2026-02", ppm2: 174_000 },
{ month: "2026-03", ppm2: 176_500 },
{ month: "2026-04", ppm2: 178_000 },
],
};
export const FIXTURE_INPUT: TradeInEstimateInput = {
address: "Екатеринбург, ул. Репина, 75/2",
area_m2: 55.3,
rooms: 2,
floor: 5,
total_floors: 11,
year_built: 2018,
house_type: "monolith",
repair_state: "good",
has_balcony: true,
};
// ── IMV Benchmark fixture ─────────────────────────────────────────────────────
// available:true обязательно — иначе IMVBenchmark возвращает null.
export const FIXTURE_IMV: IMVBenchmarkResponse = {
available: true,
cache_key: "ekb:preview-house:2k",
recommended_price: 10_200_000,
lower_price: 9_400_000,
higher_price: 11_000_000,
market_count: 7,
fetched_at: "2026-05-30T12:00:00Z",
our_median_price: 9_850_000,
diff_pct: -3.4,
};
// ── HouseInfo fixture ─────────────────────────────────────────────────────────
// houses.length > 0 обязательно — иначе HouseInfoCard возвращает null.
export const FIXTURE_HOUSES: HouseInfoForEstimate[] = [
{
house_id: 42001,
ext_house_id: "ekb-repin-75",
address: "Екатеринбург, ул. Репина, 75",
short_address: "Репина, 75",
lat: 56.84,
lon: 60.57,
year_built: 2018,
total_floors: 11,
house_type: "monolith",
passenger_elevators: 2,
cargo_elevators: 1,
has_concierge: false,
closed_yard: true,
has_playground: true,
parking_type: "подземная",
developer_name: "Атомстройкомплекс",
rating: 4.3,
reviews_count: 28,
raw_characteristics: [],
},
];
// ── PlacementHistory fixture ──────────────────────────────────────────────────
// items.length > 0 обязательно — иначе PlacementHistoryCard возвращает null.
export const FIXTURE_PLACEMENT: PlacementHistoryItem[] = [
{
id: 1001,
source: "avito",
house_id: 42001,
ext_item_id: "avito-preview-1001",
title: "2к, 54 м², 7/16 эт.",
rooms: 2,
area_m2: 54,
floor: 7,
total_floors: 16,
start_price: 10_200_000,
start_price_date: "2025-11-01",
last_price: 9_700_000,
last_price_date: "2026-03-15",
removed_date: "2026-04-10",
exposure_days: 160,
notes: null,
},
{
id: 1002,
source: "cian",
house_id: 42001,
ext_item_id: "cian-preview-1002",
title: "2к, 57 м², 4/10 эт.",
rooms: 2,
area_m2: 57,
floor: 4,
total_floors: 10,
start_price: 9_800_000,
start_price_date: "2025-09-10",
last_price: 9_500_000,
last_price_date: "2025-12-20",
removed_date: "2026-01-05",
exposure_days: 117,
notes: null,
},
{
id: 1003,
source: "avito",
house_id: 42001,
ext_item_id: "avito-preview-1003",
title: "2к, 55 м², 5/11 эт.",
rooms: 2,
area_m2: 55,
floor: 5,
total_floors: 11,
start_price: 9_500_000,
start_price_date: "2025-06-01",
last_price: 9_100_000,
last_price_date: "2025-08-30",
removed_date: "2025-09-05",
exposure_days: 96,
notes: null,
},
];
// ── HouseAnalytics fixture ────────────────────────────────────────────────────
// kpi.total_lots > 0 обязательно — иначе HouseAnalyticsSection возвращает null.
// price_history >= 2 точки — для рендера PriceHistoryChart.
// recent_sold > 0 — для рендера RecentSoldList.
export const FIXTURE_ANALYTICS: HouseAnalyticsResponse = {
house_ids: [42001],
radius_m: 0,
kpi: {
total_lots: 38,
sold_count: 24,
sold_rate_pct: 63.2,
median_exposure_days: 112,
median_bargain_pct: 4.8,
},
price_history: [
{ year: 2022, source: "avito_imv", median_price_per_m2: 155_000, n_lots: 6, median_price_rub: 8_525_000 },
{ year: 2023, source: "avito_imv", median_price_per_m2: 161_000, n_lots: 9, median_price_rub: 8_855_000 },
{ year: 2024, source: "avito_imv", median_price_per_m2: 170_000, n_lots: 12, median_price_rub: 9_350_000 },
{ year: 2025, source: "avito_imv", median_price_per_m2: 176_000, n_lots: 11, median_price_rub: 9_680_000 },
],
recent_sold: [
{
id: 2001,
source: "avito_imv",
rooms: 2,
area_m2: 54,
floor: 7,
start_price: 10_200_000,
last_price: 9_700_000,
removed_date: "2026-04-10",
exposure_days: 160,
discount_pct: 4.9,
},
{
id: 2002,
source: "avito_imv",
rooms: 2,
area_m2: 57,
floor: 4,
start_price: 9_800_000,
last_price: 9_500_000,
removed_date: "2026-01-05",
exposure_days: 117,
discount_pct: 3.1,
},
],
};
// ── SellTimeSensitivity fixture ───────────────────────────────────────────────
export const FIXTURE_SELLTIME: SellTimeSensitivityResponse = {
house_ids: [42001],
radius_m: 0,
target_median_price_per_m2: 178_000,
buckets: [
{ price_premium_label: "cheap", price_premium_pct: -5, median_exposure_days: 38, p25_days: 21, p75_days: 55, n_lots: 8 },
{ price_premium_label: "median", price_premium_pct: 0, median_exposure_days: 112, p25_days: 60, p75_days: 160, n_lots: 14 },
{ price_premium_label: "plus5", price_premium_pct: 5, median_exposure_days: 185, p25_days: 90, p75_days: 240, n_lots: 10 },
{ price_premium_label: "plus10", price_premium_pct: 10, median_exposure_days: 270, p25_days: 150, p75_days: 360, n_lots: 6 },
],
};
// Секция 12: StreetDealsCard — useSalesVsListings(address, area_m2, rooms).
// Guard: street != null И pairs.length > 0 — иначе return null.
export const FIXTURE_SALES: SalesVsListingsResponse = {
street: "Репина",
period_months: 24,
window_days: 180,
area_tolerance: 0.15,
total_deals: 9,
deals_with_listings: 5,
linkage_rate_pct: 55.6,
median_discount_pct: -6.2,
data_quality: "house_linked",
pairs: [
{
deal_id: 9001,
deal_date: "2026-04-18",
deal_price_rub: 8_900_000,
deal_price_per_m2: 161_818,
deal_area_m2: 55,
deal_rooms: 2,
deal_floor: 6,
deal_address: "Екатеринбург, ул. Репина, 75/2",
listing_id: 50001,
listing_source: "avito",
listing_source_url: "https://www.avito.ru/ekaterinburg/kvartiry/preview-d1",
listing_date: "2026-03-20",
listing_price_rub: 9_500_000,
listing_price_per_m2: 172_727,
listing_area_m2: 55,
days_listing_to_deal: 29,
discount_pct: -6.3,
},
{
deal_id: 9002,
deal_date: "2026-02-27",
deal_price_rub: 9_100_000,
deal_price_per_m2: 159_649,
deal_area_m2: 57,
deal_rooms: 2,
deal_floor: 9,
deal_address: "Екатеринбург, ул. Репина, 73",
listing_id: 50002,
listing_source: "cian",
listing_source_url: "https://www.cian.ru/sale/flat/preview-d2",
listing_date: "2026-01-30",
listing_price_rub: 9_700_000,
listing_price_per_m2: 170_175,
listing_area_m2: 57,
days_listing_to_deal: 28,
discount_pct: -6.2,
},
],
};