🟠 #34 D2 Velocity-score — sub-PR 1/2 backend service #144

Closed
opened 2026-05-14 22:12:38 +00:00 by lekss361 · 0 comments
lekss361 commented 2026-05-14 22:12:38 +00:00 (Migrated from github.com)

Per audit + Sprint 4 backlog: sale_graph 15876 строк в domrf_kn_sale_graph не используется в текущем scoring. D2 — главный demand signal.

What

Compute velocity (темп продаж м²/мес) для конкурентов в радиусе вокруг участка.

Sub-PR 1/2 (this) — Backend service

backend/app/services/site_finder/velocity.py:

def compute_velocity(
    db: Session,
    parcel_geom_wkt: str,  # WGS84 WKT
    radius_km: float = 3.0,
    obj_class: str | None = None,  # optional filter
) -> VelocityResult:
    """Темп продаж м²/мес для конкурентов в радиусе.
    
    Logic:
    1. ST_DWithin запрос на domrf_kn_objects в радиусе → conku_obj_ids
    2. JOIN domrf_kn_sale_graph (за последние 6 месяцев)
    3. Aggregate: SUM(contracted_area) / N_months
    4. Normalize vs ЕКБ median → score 0..1
    
    Returns:
        VelocityResult {
          competitors_count: int,
          monthly_velocity_sqm: float,
          ekb_median_sqm: float,
          velocity_score: float,  # 0..1 normalized
          confidence: 'high' | 'medium' | 'low' (зависит от competitors_count)
        }
    """

Integration в analyze_parcel

Response gains:

"demand": {
  "velocity": {
    "competitors_count": 12,
    "monthly_velocity_sqm": 6800,
    "ekb_median_sqm": 4500,
    "velocity_score": 0.75,
    "confidence": "high"
  }
}

Sub-PR 2/2 — Frontend

"Темп продаж конкурентов" блок в MarketTab.

Acceptance

  • compute_velocity() с tests
  • Backend integration в analyze response
  • No new HTTP calls в request path (uses cached DB data)
  • EKB median computed/cached (либо materialized view либо lazy compute)

Refs: #34, audit #127

Per audit + Sprint 4 backlog: `sale_graph` 15876 строк в `domrf_kn_sale_graph` **не используется** в текущем scoring. D2 — главный demand signal. ## What Compute velocity (темп продаж м²/мес) для конкурентов в радиусе вокруг участка. ### Sub-PR 1/2 (this) — Backend service `backend/app/services/site_finder/velocity.py`: ```python def compute_velocity( db: Session, parcel_geom_wkt: str, # WGS84 WKT radius_km: float = 3.0, obj_class: str | None = None, # optional filter ) -> VelocityResult: """Темп продаж м²/мес для конкурентов в радиусе. Logic: 1. ST_DWithin запрос на domrf_kn_objects в радиусе → conku_obj_ids 2. JOIN domrf_kn_sale_graph (за последние 6 месяцев) 3. Aggregate: SUM(contracted_area) / N_months 4. Normalize vs ЕКБ median → score 0..1 Returns: VelocityResult { competitors_count: int, monthly_velocity_sqm: float, ekb_median_sqm: float, velocity_score: float, # 0..1 normalized confidence: 'high' | 'medium' | 'low' (зависит от competitors_count) } """ ``` ### Integration в analyze_parcel Response gains: ```json "demand": { "velocity": { "competitors_count": 12, "monthly_velocity_sqm": 6800, "ekb_median_sqm": 4500, "velocity_score": 0.75, "confidence": "high" } } ``` ### Sub-PR 2/2 — Frontend "Темп продаж конкурентов" блок в MarketTab. ## Acceptance - [ ] compute_velocity() с tests - [ ] Backend integration в analyze response - [ ] No new HTTP calls в request path (uses cached DB data) - [ ] EKB median computed/cached (либо materialized view либо lazy compute) Refs: #34, audit #127
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#144
No description provided.