"""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'))}")