This commit is contained in:
lekss361 2026-04-26 15:30:02 +03:00
parent ae8abf9f15
commit 0569ccdcf3
2 changed files with 102 additions and 27 deletions

View file

@ -0,0 +1,71 @@
"""Append v3 — per-flat endpoint discovery for ДОМ.РФ.
Visible script. Manually delete when done."""
import json
import pathlib
target = pathlib.Path(__file__).parent / "memory-gendesign.jsonl"
addendum = {
"type": "entity",
"name": "DataSources_DomRF_PerFlat_Apr26",
"entityType": "research",
"observations": [
"Дата: 26.04.2026 вечер. ОТКРЫТИЕ: ДОМ.РФ выдает per-квартира данные через GET /сервисы/api/kn/flats. До этого думали что только per-ЖК доступен",
"Endpoint: GET https://наш.дом.рф/сервисы/api/kn/flats?regions=66&offset=0&limit=N&flatStatus=free,booked",
"Auth: Authorization: Basic MTpqd2U= (тот же что для всех /сервисы/api/kn/*)",
"Параметры: regions (через запятую), offset, limit, flatStatus, + любые из 30+ фильтров (priceFrom/To, areaFrom/To, roomCount, type, energyEff, wall, hasParking, и т.д.)",
"По Свердл. обл. возвращает 24 441 квартиру в продаже/брони. Через offset/limit можно качать пачками (например limit=500, ~50 запросов на регион)",
"Структура per-flat (17 полей):",
"id (int) — глобальный ID квартиры в ЕИСЖС",
"odsId (string) — формат objId/sectionNum/flatNum (например '64057/2/55') — связь с реестром проектных деклараций",
"elemId (UUID) — токен для URL детальной страницы квартиры",
"type (string) — Квартира-студия / 1-комнатная / 2-комнатная / 3-комнатная / 4+комнатная / Апартаменты",
"number (string) — номер квартиры по застройщику",
"isStudio (bool)",
"totalArea (float) — общая площадь м² (это та что продаётся)",
"livingArea (float) — ЖИЛАЯ площадь м² (без коридоров/санузлов) — для финмодели важно отдельно",
"rooms (int) — количество комнат (для студии = 1)",
"status (enum) — free / booked / sold",
"price (int) — полная цена в ₽",
"pricePerSquareMeter (int) — цена м² в ₽",
"priceChangeDate (string DD-MM-YYYY HH:MM) — дата последнего изменения цены ⭐ КЛЮЧЕВОЕ ПОЛЕ для velocity",
"socialMortgage (bool) — доступна соц-ипотека",
"numberFloors (int) — этажность дома",
"floor (int) — этаж этой квартиры",
"image {attachmentId, attachmentIdSmall, hash, size, source, type} — type='layout' = планировка квартиры. URL для скачивания: /api/ext/file/{attachmentId}?type=png",
"objInfo {hobjId, objTransferPlanDt, objReady100PercDt, objCommercNm, objAddr} — связь с ЖК (плановая дата передачи + дата готовности + название + адрес)",
"🔥 priceChangeDate — это золотая жила. Снимая снапшот раз в день, мы видим:",
"1) Какие квартиры подешевели/подорожали (delta price)",
"2) Какие квартиры перешли в booked/sold (status changes)",
"3) Velocity по ЖК: кол-во квартир сменивших status за период",
"4) Эффективность ценовой стратегии: ЖК с активными priceChangeDate (последние 7 дней) vs ЖК где цены не двигались месяцами",
"Это ровно то что нужно для Plan A 'плитка 3 — за какое время продастся': вывожу absorption rate (квартир/мес) для ЖК-аналогов в радиусе 5 км → проектирую на наш концепт",
"🛠 ETL-стратегия для backend:",
"1) Daily full-refresh: для каждого региона из таргетов (66=Свердл, 50=МО, 77=Москва) → loop offset/limit с шагом 500 → upsert в таблицу dom_rf_flats",
"2) Daily delta tracking: SQL diff dom_rf_flats vs dom_rf_flats_yesterday → вычислить (a) кто перешёл в sold, (b) кому изменилась цена, (c) кто новый. Записать в dom_rf_flat_events",
"3) Materialized views: median(pricePerSquareMeter) по (region, type, year_quarter), absorption_rate по hobjId (sold quarters / 30 days)",
"📦 SQL schema для миграции (Stage 2a):",
"CREATE TABLE dom_rf_flats (id BIGINT PRIMARY KEY, ods_id VARCHAR(50), elem_id VARCHAR(64), obj_id INT, hobj_id INT, type VARCHAR(50), number VARCHAR(20), is_studio BOOL, rooms SMALLINT, total_area NUMERIC(8,2), living_area NUMERIC(8,2), price NUMERIC(12,2), price_per_sqm NUMERIC(10,2), price_change_dt TIMESTAMPTZ, status VARCHAR(20), social_mortgage BOOL, floor SMALLINT, num_floors SMALLINT, layout_attachment_id VARCHAR(80), obj_commerc_nm TEXT, obj_addr TEXT, obj_transfer_plan_dt TIMESTAMPTZ, obj_ready_dt TIMESTAMPTZ, last_synced_at TIMESTAMPTZ, raw JSONB, region_cd SMALLINT)",
"Индексы: (region_cd), (hobj_id), (status), (type), (price_per_sqm), (price_change_dt). Для радиус-запросов нужно JOIN с dom_rf_objects по hobj_id чтобы получить geom",
"CREATE TABLE dom_rf_flat_events (flat_id BIGINT, event_dt TIMESTAMPTZ, event_type VARCHAR(20), old_value JSONB, new_value JSONB, PRIMARY KEY(flat_id, event_dt)) -- тип event: 'status_change', 'price_change', 'new_listing', 'delisting'",
"💎 Что ещё можно подсосать через этот endpoint:",
"Скачивать ПЛАНИРОВКИ всех квартир (image.attachmentId, type='layout') — это набор ~24K image для Свердл. Можем использовать для AI-генерации (тренировка модели на схемах квартир) или показывать пользователю аналоги",
"objInfo.objTransferPlanDt vs objReady100PercDt — это плановая дата передачи квартир (когда фактически передают по ДДУ) vs дата готовности дома (когда строительство закончено). Лаг между ними обычно 3-6 мес и важен для absorption analysis",
"🔬 Качество данных: проверил на 2 квартирах из ЛО ('LIBERTY DOM'), цены 2.6М и 2.7М ₽, площадь 22 и 23 м² — реалистично. priceChangeDate '30-11-2025' = 5 мес. назад → значит эти квартиры в LIBERTY DOM плохо продаются (цена не двигалась)",
"Юридический статус (повтор): данные публикуются в ЕИСЖС в соответствии с 214-ФЗ как открытая информация по строящимся объектам. Использование в коммерческом продукте легально, для реестра ПО декларируем 'интеграция с ЕИСЖС ДОМ.РФ'",
],
}
relations = [
{"type": "relation", "from": "DataSources_DomRF_PerFlat_Apr26", "to": "DataSources_DomRF_Catalog_Apr26", "relationType": "extends"},
{"type": "relation", "from": "DataSources_DomRF_PerFlat_Apr26", "to": "PlanA_AnalyticsFirst_Apr25", "relationType": "fully_unblocks"},
{"type": "relation", "from": "DataSources_DomRF_PerFlat_Apr26", "to": "SalesTracking_Strategy_Apr25", "relationType": "supersedes"},
]
with target.open("a", encoding="utf-8") as f:
f.write(json.dumps(addendum, ensure_ascii=False) + "\n")
for r in relations:
f.write(json.dumps(r, ensure_ascii=False) + "\n")
print(f"Appended 1 entity + {len(relations)} relations")
print(f"Final line count: {sum(1 for _ in target.open('r', encoding='utf-8'))}")

File diff suppressed because one or more lines are too long