feat(site-finder): domrf→cad geom-match + parking_ratio конкурентов (#96) #1327

Merged
bot-backend merged 2 commits from feat/domrf-cad-match-parking-wire-96 into main 2026-06-14 14:49:29 +00:00
Showing only changes of commit 3dee18743d - Show all commits

View file

@ -409,6 +409,36 @@ export interface paths {
patch?: never;
trace?: never;
};
"/api/v1/parcels/{cad_num}/competitors-parking": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
get?: never;
put?: never;
/**
* Get Parcel Competitors Parking
* @description parking_ratio top-N конкурентов (#96 wiring) ЛЕНИВЫЙ путь, вне analyze.
*
* Резолвит top-3 конкурента (relevance_weight DESC) domrfcad_buildings через
* PostGIS geom-match, затем on-demand НСПД premises-lookup parking_ratio.
* Намеренно ОТДЕЛЬНЫЙ от analyze/forecast: N×НСПД (~0.6-2с каждый) добавил бы
* секунды в хот-путь и убил p95 фронт дёргает этот эндпоинт лениво после
* отрисовки списка конкурентов.
*
* sync `def` (не async): premises_lookup изолирует НСПД-async через
* asyncio.run() его нельзя вызвать из async-handler (running loop). FastAPI
* исполняет sync-handler в threadpool, не блокируя event loop.
*/
post: operations["get_parcel_competitors_parking_api_v1_parcels__cad_num__competitors_parking_post"];
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/api/v1/parcels/{cad_num}/best-layouts": {
parameters: {
query?: never;
@ -3049,6 +3079,44 @@ export interface components {
[key: string]: number;
} | null;
};
/**
* CompetitorParking
* @description parking_ratio одного конкурента (#96). obj_id связывает с Competitor.
*
* matched_cad_num здание cad_buildings, на которое сматчился domrf-центроид
* (None если geom-match не нашёл здание в радиусе). parking_ratio /
* parking_count / flats_count из НСПД tab-group (None если здание не
* сматчилось ИЛИ НСПД недоступен graceful, НЕ нулевой паркинг).
* match_distance_m расстояние domrf-центроид footprint (диагностика).
*/
CompetitorParking: {
/** Obj Id */
obj_id: number;
/** Matched Cad Num */
matched_cad_num?: string | null;
/** Match Distance M */
match_distance_m?: number | null;
/** Parking Ratio */
parking_ratio?: number | null;
/** Parking Count */
parking_count?: number | null;
/** Flats Count */
flats_count?: number | null;
};
/**
* CompetitorsParkingResponse
* @description Ответ ленивого /{cad}/competitors-parking (#96).
*
* items по одному CompetitorParking на top-N конкурентов (по relevance_weight
* DESC из get_competitors). matched_count сколько реально получили
* parking_ratio (диагностика покрытия для фронта / мониторинга).
*/
CompetitorsParkingResponse: {
/** Items */
items: components["schemas"]["CompetitorParking"][];
/** Matched Count */
matched_count: number;
};
/** CompetitorsRequest */
CompetitorsRequest: {
/**
@ -5052,6 +5120,41 @@ export interface operations {
};
};
};
get_parcel_competitors_parking_api_v1_parcels__cad_num__competitors_parking_post: {
parameters: {
query?: never;
header?: never;
path: {
cad_num: string;
};
cookie?: never;
};
requestBody: {
content: {
"application/json": components["schemas"]["CompetitorsRequest"];
};
};
responses: {
/** @description Successful Response */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["CompetitorsParkingResponse"];
};
};
/** @description Validation Error */
422: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
get_parcel_best_layouts_api_v1_parcels__cad_num__best_layouts_post: {
parameters: {
query?: never;