gendesign/tradein-mvp/backend/data/sql/169_osm_poi_ekb_local.sql
bot-backend 90731da537
All checks were successful
CI Trade-In / changes (pull_request) Successful in 7s
CI / changes (pull_request) Successful in 8s
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 1m36s
feat(tradein): location-coef MVP через FDW-мост к OSM POI Птицы (#2045)
Финальный PR issue #2045 (BE-3): GET /api/v1/trade-in/location-coef для
LocationDrawer. FDW foreign table -> локальное зеркало osm_poi_ekb_local
(TRUNCATE+INSERT, тот же паттерн что cad_buildings_local/cadastral_geo_match,
избегает ~1.16s/row FDW round-trip) -> straight-line POI-скоринг, портированный
из Site Finder poi_score.py::compute_poi_weighted_top7 (CATEGORY_WEIGHTS as-is,
радиус 1200м для квартир вместо Ptica 2000м для участков). score->coef -
новая MVP-эвристика (0.95..1.05, не откалибрована на реальных дельтах).

Graceful fallback (не 500, не фабрикуем факторы): пустая/не отрефрешенная
osm_poi_ekb_local или отсутствие lat/lon у оценки -> coef=1.0, factors=[],
geo_source="unavailable".

Scheduler: source=osm_poi_ekb_refresh, daily, зарегистрирован и в боевом
dispatch (scheduler.py), и в kit-registry (product_handlers.py) - иначе
test_kit_registry_completeness падает на ship-dark инварианте (#2192).

Frontend wiring (mappers.ts/LocationDrawer.tsx) - вне scope, отдельная задача
после проверки endpoint'а curl'ом на деплое.
2026-07-03 23:44:55 +03:00

42 lines
2.1 KiB
PL/PgSQL

-- 169_osm_poi_ekb_local.sql
-- Local materialized mirror of gendesign_osm_poi_ekb (postgres_fdw foreign table, migration
-- 168) for fast location-coef / POI scoring (#2045 BE-3, LocationDrawer).
--
-- WHY (mirrors 124_cad_buildings_local.sql — same perf fact measured for the analogous
-- gendesign_cad_buildings FDW): a per-request FDW nearest-POI query would pay a per-row FDW
-- round-trip (~1.16s/row without a geom index on the remote table) — UNUSABLE for a
-- synchronous endpoint (GET /api/v1/trade-in/location-coef). Solution: materialize the FDW
-- once (single bulk scan) into a LOCAL table with a real Point geom + GIST index, then run
-- fast local ST_DWithin/ST_Distance queries per estimate.
--
-- This migration creates the EMPTY table + index only. It does NOT read the FDW — deploy
-- never depends on the gendesign DB / FDW server being reachable. The table is populated by
-- the refresh job (app/tasks/osm_poi_ekb_refresh.py), driven by the in-app scheduler
-- (source='osm_poi_ekb_refresh', seed in 170_scrape_schedules_seed_osm_poi_ekb_refresh.sql).
--
-- DEPENDENCIES: PostGIS (postgis extension, present since geom on listings/houses).
-- Idempotent: CREATE TABLE/INDEX IF NOT EXISTS. Safe to re-run.
BEGIN;
CREATE TABLE IF NOT EXISTS osm_poi_ekb_local (
id bigserial PRIMARY KEY,
category text,
name text,
lat double precision,
lon double precision,
geom geometry(Point, 4326)
);
COMMENT ON TABLE osm_poi_ekb_local IS
'Local mirror of gendesign_osm_poi_ekb FDW (Site Finder OSM POI registry, EKB). '
'Populated by app/tasks/osm_poi_ekb_refresh.py (single bulk FDW scan, TRUNCATE+INSERT). '
'Point geom + GIST enables fast local nearest-POI scoring for '
'app/services/location_coef.py (GET /api/v1/trade-in/location-coef, LocationDrawer). '
'Migration 168/169. Refresh driven by scheduler source=osm_poi_ekb_refresh.';
-- GIST on geom — required for ST_DWithin / ST_Distance nearest-POI scoring.
CREATE INDEX IF NOT EXISTS osm_poi_ekb_local_geom_idx
ON osm_poi_ekb_local USING GIST (geom);
COMMIT;