gendesign/tradein-mvp/backend/app
Light1YT 086603cf25 feat(tradein): sales-vs-listings endpoint (PR K — foundation #564 Phase 1)
Связь ДКП Росреестра с listings (avito/cian/yandex/n1) через street
normalization + area window + listing-date window. Foundation для
sales-vs-asks comparison (discount_pct per pair).

DDL:
- data/sql/067_v_street_sales_vs_listings.sql:
  * table-valued function street_sales_vs_listings(street, area, rooms,
    window_days, area_tol) для filtered query с indexes
  * view v_street_sales_vs_listings — full crossjoin для analytical queries
    (used в reporting; для transactional path use TVF)
  * Encapsulated JOIN logic: street ILIKE + area ±15% + listing_date в окне
    [deal_date - window_days, deal_date]
  * Computed columns: days_listing_to_deal, discount_pct

API:
- GET /api/v1/sales-vs-listings?address=...&area_m2=...&rooms=...
  * Pydantic SalesVsListingsResponse с street/period/total_deals/
    deals_with_listings/linkage_rate_pct/median_discount_pct/pairs list
  * Использует extract_street_name() из existing estimator code

Schema:
- schemas/trade_in.py: SalesListingPair + SalesVsListingsResponse

Production verification:
- Migration applied на проде: CREATE FUNCTION + CREATE VIEW
- View total: 50,139 (deal, listing) pairs
- Sample case: «Бисертская» — ДКП 6.3 млн (86 м²) vs listing 8.5 млн (79 м²)
  с listing_date за 4 дня до сделки → discount_pct = −25.88%

Tests: 8/8 pass в test_sales_vs_listings.py — happy path, no matches,
LEFT JOIN behavior, median discount, defaults, response shape.
Ruff clean.

Out of scope (separate PR L+M):
- Frontend extend StreetDealsCard «Связанные ASK»
- Estimator revert NOTE 2026-05-24 (rosreestr_deals в actual_deals)

Refs #564 (Phase 1 — backend foundation).
2026-05-27 16:55:20 +05:00
..
api feat(tradein): sales-vs-listings endpoint (PR K — foundation #564 Phase 1) 2026-05-27 16:55:20 +05:00
core feat(tradein): persistent infra для backfill scripts (PR F) (#592) 2026-05-27 06:59:54 +00:00
schemas feat(tradein): sales-vs-listings endpoint (PR K — foundation #564 Phase 1) 2026-05-27 16:55:20 +05:00
services feat(tradein): hook matching в save_listings — fill listing_sources (PR I) (#595) 2026-05-27 10:02:37 +00:00
tasks feat(tradein): persistent infra для backfill scripts (PR F) (#592) 2026-05-27 06:59:54 +00:00
__init__.py feat: add tradein-mvp subproject (Trade-In Estimator под /trade-in) 2026-05-21 00:25:39 +03:00
main.py feat(rbac): role-based access control via X-Authenticated-User middleware (#585) 2026-05-26 06:18:40 +00:00