Stage 2b: Скоринг + API + UI Site Finder #8

Closed
opened 2026-04-26 11:25:13 +00:00 by lekss361 · 1 comment
lekss361 commented 2026-04-26 11:25:13 +00:00 (Migrated from github.com)

Backend:

  • app/services/site_finder/scorer.py — 3 эвристических критерия:
    1. Расстояние до центра города
    2. Плотность POI в радиусе 1 км (метро, школы, поликлиники)
    3. Цена района (ДОМ.РФ + ЦИАН baseline)
  • (опционально) 4-й критерий: Velocity Score из sales_tracker — сколько квартир продаётся/мес в радиусе 1 км
  • POST /api/v1/parcels/search — фильтры по площади, ВРИ, рейтингу

Frontend:

  • Страница /site-finder (есть скелет)
  • Mapbox/Leaflet с градацией маркеров по рейтингу (зелёный/жёлтый/красный)
  • Фильтры в сайдбаре
  • Карточка участка справа: рейтинг, площадь, ВРИ, адрес, ссылка на ПКК

Acceptance:

  • Карта показывает 1000+ участков с цветовой градацией
  • Фильтры работают (площадь, ВРИ)
  • Можно отсортировать по рейтингу
  • Скоринг работает быстро (≤500мс на запрос с филтрами)
**Backend:** - `app/services/site_finder/scorer.py` — 3 эвристических критерия: 1. Расстояние до центра города 2. Плотность POI в радиусе 1 км (метро, школы, поликлиники) 3. Цена района (ДОМ.РФ + ЦИАН baseline) - (опционально) 4-й критерий: Velocity Score из sales_tracker — сколько квартир продаётся/мес в радиусе 1 км - `POST /api/v1/parcels/search` — фильтры по площади, ВРИ, рейтингу **Frontend:** - Страница `/site-finder` (есть скелет) - Mapbox/Leaflet с градацией маркеров по рейтингу (зелёный/жёлтый/красный) - Фильтры в сайдбаре - Карточка участка справа: рейтинг, площадь, ВРИ, адрес, ссылка на ПКК **Acceptance:** - [ ] Карта показывает 1000+ участков с цветовой градацией - [ ] Фильтры работают (площадь, ВРИ) - [ ] Можно отсортировать по рейтингу - [ ] Скоринг работает быстро (≤500мс на запрос с филтрами)
lekss361 commented 2026-05-11 16:37:50 +00:00 (Migrated from github.com)

Закрыто — Site Finder Stage 2b (Скоринг + API + UI) задеплоен.

Реализовано в session 2026-05-11:

DB (migration 82):

  • Новая таблица osm_poi_ekb (PK, GIST на geom, category enum, last_osm_edit_date, tags jsonb)
  • 8 загруженных категорий: 1020 bus_stop, 811 shop_small, 656 pharmacy, 468 kindergarten, 350 tram_stop, 287 park, 258 hospital, 59 shop_mall = 3909 POI total

Backend:

  • backend/app/services/site_finder/poi_loader.py — Overpass API client (per-category split, User-Agent header, soft 2-year freshness filter)
  • backend/app/workers/tasks/poi_sync.py — Celery task tasks.poi_sync.sync_osm_poi_ekb
  • Beat schedule 0 3 * * mon (понедельник 03:00 МСК)
  • POST /api/v1/admin/scrape/poi-sync — manual trigger
  • POST /api/v1/parcels/{cad_num}/analyze — scoring endpoint:
    • cad → geom (cad_quarters_geom / cad_buildings)
    • POI в радиусе 1км через GIST ST_DWithin с distance decay
    • Tram_stop carries NEGATIVE weight (по требованию Максима)
    • District context из ekb_districts
    • 20 competitors в радиусе 3км из domrf_kn_objects (с DISTINCT ON dedup)

Frontend /site-finder:

  • CadInput.tsx — regex-validation, default 66:41:0204016:10
  • SiteMap.tsx — Leaflet через next/dynamic, полигон участка
  • ScoreCard.tsx — color-coded (>5 зелёный, 2-5 жёлтый, <2 красный), tram-warning
  • CompetitorTable.tsx — top-20 с подсветкой "same district"
  • useSiteAnalysis.ts hook (TanStack Query)

E2E verified (66:41:0206030 Железнодорожный): score=28.58, poi_count=93, district=Железнодорожный, competitors=20.

Открыто на следующую итерацию (отдельные issues если нужно):

  • Геометрия для cad-участков (4-part) — нужна таблица cad_parcels_geom или интеграция с rosreestr2coord для thematic_id=1
  • POI lat/lon в analyze response чтобы маркеры рисовались на карте
  • OSM coverage: school/supermarket/metro вернули 0 в bbox — нужен расширенный фильтр

Commits: 688e094, 6dea341, a4e8fff, f81bd71, 9742219, 93f1379, 3aeda29, a7d7dc9, e6c062c.

Закрыто — Site Finder Stage 2b (Скоринг + API + UI) задеплоен. **Реализовано в session 2026-05-11:** DB (migration 82): - Новая таблица `osm_poi_ekb` (PK, GIST на geom, category enum, last_osm_edit_date, tags jsonb) - 8 загруженных категорий: 1020 bus_stop, 811 shop_small, 656 pharmacy, 468 kindergarten, 350 tram_stop, 287 park, 258 hospital, 59 shop_mall = **3909 POI total** Backend: - `backend/app/services/site_finder/poi_loader.py` — Overpass API client (per-category split, User-Agent header, soft 2-year freshness filter) - `backend/app/workers/tasks/poi_sync.py` — Celery task `tasks.poi_sync.sync_osm_poi_ekb` - Beat schedule `0 3 * * mon` (понедельник 03:00 МСК) - `POST /api/v1/admin/scrape/poi-sync` — manual trigger - `POST /api/v1/parcels/{cad_num}/analyze` — scoring endpoint: - cad → geom (cad_quarters_geom / cad_buildings) - POI в радиусе 1км через GIST ST_DWithin с distance decay - **Tram_stop carries NEGATIVE weight** (по требованию Максима) - District context из ekb_districts - 20 competitors в радиусе 3км из domrf_kn_objects (с DISTINCT ON dedup) Frontend `/site-finder`: - `CadInput.tsx` — regex-validation, default `66:41:0204016:10` - `SiteMap.tsx` — Leaflet через next/dynamic, полигон участка - `ScoreCard.tsx` — color-coded (>5 зелёный, 2-5 жёлтый, <2 красный), tram-warning - `CompetitorTable.tsx` — top-20 с подсветкой "same district" - `useSiteAnalysis.ts` hook (TanStack Query) **E2E verified** (66:41:0206030 Железнодорожный): score=28.58, poi_count=93, district=Железнодорожный, competitors=20. **Открыто на следующую итерацию (отдельные issues если нужно):** - Геометрия для cad-участков (4-part) — нужна таблица `cad_parcels_geom` или интеграция с rosreestr2coord для thematic_id=1 - POI lat/lon в analyze response чтобы маркеры рисовались на карте - OSM coverage: school/supermarket/metro вернули 0 в bbox — нужен расширенный фильтр Commits: `688e094`, `6dea341`, `a4e8fff`, `f81bd71`, `9742219`, `93f1379`, `3aeda29`, `a7d7dc9`, `e6c062c`.
Sign in to join this conversation.
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#8
No description provided.