fix(sf-07): median_12m alias + UI 12mo hint #280

Merged
lekss361 merged 1 commit from fix/sf-07-median-12m-alias into main 2026-05-17 11:31:19 +00:00
Owner

Summary

SF FixList #7 (Wave 2) — district.median_price_per_m2 отдавал 24-мес median из ekb_districts. Теперь LEFT JOIN на mv_quarter_price_per_m2 по кадастровому кварталу + COALESCE(mq.median_12m, d.median_price_per_m2) → 12-мес value где доступно, fallback на legacy для кварталов без покрытия в MV.

Изменения

  • Backend backend/app/api/v1/parcels.py ~line 1190:
    • LEFT JOIN mv_quarter_price_per_m2 mq ON mq.quarter_cad_number = REGEXP_REPLACE(:cad_num, ':[^:]+$', '')
    • SELECT: COALESCE(mq.median_12m, d.median_price_per_m2) AS median_price_per_m2
  • Frontend frontend/src/components/site-finder/OverviewTab.tsx ~line 78:
    • <span className="text-xs text-slate-500 ml-1">(12 мес)</span> рядом со значением
  • Vault fixes/Fix_SF_Median_12m_Alias_May17.md

Test plan

  • GET /api/v1/parcels/66:41:0702048:27/analyzedistrict.median_price_per_m2 ≈ 146 809 (из mv_quarter_price_per_m2.median_12m для квартала 66:41:0702048)
  • UI: рядом с медианой цены в OverviewTab отображается «(12 мес)»
  • Fallback участок без записи в MV → ekb_districts.median_price_per_m2 (не NULL)

Related: epic #271 item #7 · Wave 2 first

## Summary SF FixList #7 (Wave 2) — `district.median_price_per_m2` отдавал 24-мес median из `ekb_districts`. Теперь LEFT JOIN на `mv_quarter_price_per_m2` по кадастровому кварталу + `COALESCE(mq.median_12m, d.median_price_per_m2)` → 12-мес value где доступно, fallback на legacy для кварталов без покрытия в MV. ## Изменения - **Backend** `backend/app/api/v1/parcels.py` ~line 1190: - `LEFT JOIN mv_quarter_price_per_m2 mq ON mq.quarter_cad_number = REGEXP_REPLACE(:cad_num, ':[^:]+$', '')` - SELECT: `COALESCE(mq.median_12m, d.median_price_per_m2) AS median_price_per_m2` - **Frontend** `frontend/src/components/site-finder/OverviewTab.tsx` ~line 78: - `<span className="text-xs text-slate-500 ml-1">(12 мес)</span>` рядом со значением - **Vault** `fixes/Fix_SF_Median_12m_Alias_May17.md` ## Test plan - [ ] `GET /api/v1/parcels/66:41:0702048:27/analyze` → `district.median_price_per_m2` ≈ 146 809 (из `mv_quarter_price_per_m2.median_12m` для квартала `66:41:0702048`) - [ ] UI: рядом с медианой цены в OverviewTab отображается «(12 мес)» - [ ] Fallback участок без записи в MV → `ekb_districts.median_price_per_m2` (не NULL) Related: epic #271 item #7 · Wave 2 first
lekss361 added 1 commit 2026-05-17 11:29:41 +00:00
ekb_districts.median_price_per_m2 was populated from a 24-month window.
LEFT JOIN mv_quarter_price_per_m2 on the cad quarter and COALESCE(median_12m,
fallback) so the API returns the 12-month median where available.
Frontend OverviewTab adds a "(12 мес)" hint next to the value.

Closes #271 item 7
lekss361 merged commit df2b47d27c into main 2026-05-17 11:31:19 +00:00
Author
Owner

Merged via deep-code-reviewer — verdict APPROVE.

Проверено:

  • mv_quarter_price_per_m2 существует, unique index на quarter_cad_number (PK) → JOIN Index Scan, cost ~0.29..8.31
  • EXPLAIN на реальном запросе: план чистый, Nested Loop + Index Scan для MV
  • REGEXP_REPLACE(:cad_num, ':[^:]+$', '') — корректно strip'ает :27 из 66:41:0702048:2766:41:0702048
  • COALESCE(mq.median_12m, d.median_price_per_m2) — корректный fallback на legacy 24-мес
  • Vault entry fixes/Fix_SF_Median_12m_Alias_May17.md присутствует
  • Frontend: TS type не меняется (number | null), backward compat OK

Smoke после deploy:

  • GET /api/v1/parcels/66:41:0702048:27/analyzedistrict.median_price_per_m2 ≈ 146 809 (из MV)
  • UI: «(12 мес)» рядом со значением в OverviewTab

Potential follow-up (MINOR, не блокирующий):

  • Label «(12 мес)» показывается всегда, но при fallback значение из 24-мес ekb_districts. Желательно вернуть backend-флаг is_12mo: bool и conditional rendering на фронте, чтобы не вводить пользователя в заблуждение для кварталов без покрытия MV.
  • psycopg v3: bind :cad_num — Python str, REGEXP_REPLACE принимает text, CAST не требуется.
Merged via deep-code-reviewer — verdict APPROVE. **Проверено:** - `mv_quarter_price_per_m2` существует, unique index на `quarter_cad_number` (PK) → JOIN Index Scan, cost ~0.29..8.31 - EXPLAIN на реальном запросе: план чистый, Nested Loop + Index Scan для MV - `REGEXP_REPLACE(:cad_num, ':[^:]+$', '')` — корректно strip'ает `:27` из `66:41:0702048:27` → `66:41:0702048` - `COALESCE(mq.median_12m, d.median_price_per_m2)` — корректный fallback на legacy 24-мес - Vault entry `fixes/Fix_SF_Median_12m_Alias_May17.md` присутствует - Frontend: TS type не меняется (`number | null`), backward compat OK **Smoke после deploy:** - `GET /api/v1/parcels/66:41:0702048:27/analyze` → `district.median_price_per_m2` ≈ 146 809 (из MV) - UI: «(12 мес)» рядом со значением в OverviewTab **Potential follow-up (MINOR, не блокирующий):** - Label «(12 мес)» показывается всегда, но при fallback значение из 24-мес `ekb_districts`. Желательно вернуть backend-флаг `is_12mo: bool` и conditional rendering на фронте, чтобы не вводить пользователя в заблуждение для кварталов без покрытия MV. - `psycopg v3`: bind `:cad_num` — Python str, REGEXP_REPLACE принимает text, CAST не требуется.
Sign in to join this conversation.
No reviewers
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#280
No description provided.