{"type":"_aim","source":"mcp-knowledge-graph"}
{"type":"entity","name":"Project_GenDesign","entityType":"project","observations":["Стартап: AI-подбор земельных участков (Site Finder) + автоматическая генерация концепций застройки (Generative Design) для девелоперов РФ","Two-in-one воронка: от инвест-критериев → найденный участок → концепт застройки → финансовая модель","Конкуренты: rTIM (только концепт-стадия, нет site-selection), TestFit (нет РФ-данных)","Целевая аудитория: инвестдепартаменты + архитектурно-проектные отделы региональных девелоперов","Фаза 0 — Discovery MVP, апрель–июнь 2026 (3 месяца)","Бюджет Фазы 0: 0,9–1,2 млн ₽","Корневой репозиторий: C:\\Users\\user\\source\\repos\\gendesign","Документы хранятся в docs/ внутри репозитория"]}
{"type":"entity","name":"TechStack_v2.2","entityType":"tech_stack","observations":["Решение зафиксировано в апреле 2026: переход с .NET на Python для Discovery MVP","Backend: Python 3.12, FastAPI 0.115+, SQLAlchemy 2.0, GeoAlchemy2, Pydantic v2, Alembic, Celery + Redis, httpx","Геометрия: Shapely 2.0, GeoPandas 1.0, Pyproj (проекции WGS84 ↔ UTM ↔ МСК-66 для Свердловской обл.), Rasterio","ML: XGBoost (скоринг участков), scikit-learn, pandas, NumPy","База данных: PostgreSQL 16 + PostGIS 3.4, Redis 7","Frontend: Next.js 15, React 19, TypeScript 5, Tailwind CSS 4, shadcn/ui, TanStack Query, Mapbox GL JS или Leaflet","Экспорт: WeasyPrint (PDF), ezdxf (DXF), openpyxl (Excel)","Инфра: Yandex Cloud или VK Cloud, Docker, GitHub Actions, Sentry","Dev tools: uv (зависимости), ruff (линтер+форматтер), mypy (типизация), pytest"]}
{"type":"entity","name":"NorthStar_DiscoveryMVP","entityType":"goal","observations":["К концу месяца 3 (июнь 2026): 3 платящих пилотных клиента, ≥30 тыс. ₽/мес каждый","Заявка в реестр российского ПО подана","Це́ль: получить право пройти в Раунд А на 20–25 млн ₽","Acceptance criteria разбиты на 3 блока: функционально / бизнесово / технически","Правило перехода: 3/3 → Раунд А; 2/3 → продление Фазы 0 на 1–2 мес.; 1/3 или меньше → стоп проекта","В v2.2 цель = 3 пилота; в v2.1 (бизнес-план) указано 4 пилота — расхождение, требует синхронизации в пользу 3"]}
{"type":"entity","name":"Phase0_DiscoveryMVP","entityType":"phase","observations":["Discovery MVP, месяцы 1–3 после старта","Пилотный регион: Свердловская обл. (Екатеринбург, ПЗЗ Екатеринбурга, МСК-66)","Месяц 1 цели: ООО зарегистрировано, прототип Site Finder с 1000 участков, 50 целевых клиентов в CRM, 5 cold-outreach, 3 встречи","Месяц 2 цели: 15 встреч кумулятивно, 2 LOI, 1 платящий пилот (≥30 тыс. ₽/мес), демо на реальных участках, первая статья","Месяц 3 цели: 20+ встреч, 3 платящих пилота, 7+ LOI, 1 регадминистрация в переговорах, заявка в реестр ПО, инвест-deck (12 слайдов), финмодель на 5 лет"]}
{"type":"entity","name":"Validation_Findings_Apr25","entityType":"review","observations":["Дата валидации: 25 апреля 2026","КРИТИЧНО: бизнес-план v2.1 не синхронизирован со стеком v2.2 — в плане 12 мес. месяцы 1–4 ещё ссылаются на .NET Core 8","Несостыковка KPI: v2.1 = 4 платящих пилота, v2.2 = 3 — нужно остановиться на 3 (как в Acceptance Criteria v2.2)","Регион не зафиксирован однозначно: v2.1 пишет «Свердл. или Лен.», v2.2 — только Свердл. — закрепить Свердловскую","Прайсинг: пилот 30 тыс., прайс-лист 70–120 тыс. — уточнить в финмодели для инвесторов: 70 тыс./мес как baseline","Технические риски: Time to First Value ≤10 мин амбициозно (предложение: 15 мин); генерация концепции ≤10 сек требует профилировки с первого билда","PostgreSQL TDE отсутствует в open-source — заменить на pgcrypto + шифрование чувствительных полей на уровне приложения","mypy --strict для всего MVP избыточен соло-разработчику — оставить только для core-модулей (geometry/scoring/financial)","99% uptime в рабочие часы для соло-разработчика рискованно — реалистично 95% + ответ в течение рабочего дня","Заявка в реестр ПО ≠ свидетельство; срок рассмотрения 60–180 дней — учесть для расчёта Раунда А","Бюджет 1,2 млн ₽ + 3 мес. + один основатель плотный; рекомендация — заложить буфер +1 месяц или урезать DXF-экспорт из Discovery"]}
{"type":"entity","name":"Feedback_MemoryFirst","entityType":"feedback","observations":["Правило: вся информация по проекту gendesign хранится в memory-gendesign.jsonl (context=\"gendesign\"). Информация = факты, решения, результаты анализа, обсуждения стратегии, KPI, списки рисков, протоколы валидации и т.д.","НИКОГДА не создавать .md / .docx / .pdf / .pptx файлы самостоятельно — даже если кажется, что это поможет. Документы генерируются ТОЛЬКО по явному запросу («сделай md», «собери в документ», «выгрузи в docx»).","При поступлении новых фактов/решений в разговоре — сразу сохраняем в память через aim_memory_store / aim_memory_add_facts в context=\"gendesign\".","Для файловой генерации по запросу: запрос срез из памяти (aim_memory_search/read_all) → сборка документа. Память = единый источник правды, файлы = производные.","**Why:** пользователь хочет избежать разъехавшейся инфы между версиями доков (как случилось с v2.1/v2.2). Единый источник (граф памяти) — синхронен по определению.","**How to apply:** в любом обмене по этому проекту — (1) сначала читаем gendesign-память, (2) ведём диалог/анализ, (3) сохраняем новые выводы в память, (4) файлы только если пользователь явно запросил."]}
{"type":"entity","name":"Team_Setup","entityType":"team","observations":["2 фуллстек-разработчика (оба пишут Python + TypeScript)","Оба part-time по 20 ч/неделю — итого ~40 person-hours/неделю (эффективных с координацией ~33)","Разделение по фичам, а не по слоям — оба трогают backend и frontend","Ритм координации: 1 синк/неделю (30 мин), daily-async в Telegram, PR review обязательный","Ветвление: trunk-based, feature ветки ≤ 3 дней","Критичный тулинг: openapi-typescript для codegen TS-типов из Pydantic-схем (иначе два фуллстека плодят расхождения в API-контракте)"]}
{"type":"entity","name":"Stages_MVP_v1","entityType":"plan","observations":["Порядок: строго последовательный — Generative полностью, потом Site Finder","Общая оценка: 12 недель (Stage 0: 1 нед., Stage 1: 6 нед., Stage 2: 5 нед.)","Stage 0 (нед. 1) — скелет: монорепо backend+frontend, Docker с PostGIS+Redis, FastAPI hello, Next.js hello, openapi-typescript codegen, GitHub Actions CI, ruff+mypy(core)+pytest. Без JWT (single-tenant + X-Demo-User до Раунда А)","Stage 1a (нед. 2-3) — геометрия + API-контракт. A: Shapely-сервис (отступы, сетка), Pydantic ConceptInput/Output, POST /api/v1/concepts с заглушкой. B: страница /concept, Leaflet, импорт GeoJSON + отрисовка, форма параметров, вывод 3 вариантов в табах","Stage 1b (нед. 4-5) — алгоритм размещения. A: жадное заполнение, 3 стратегии, STRtree для коллизий, профилировка (цель ≤10с, fallback 15с). B: визуализация корпусов, метрики ТЭП, сравнение вариантов","Stage 1c (нед. 6-7) — ТЭП + финмодель + экспорты. A: teap.py, financial.py, openpyxl. B: WeasyPrint шаблон, ezdxf, UI кнопок скачивания","Acceptance Stage 1 (конец нед. 7): полигон→3 варианта→ТЭП+финмодель→PDF/Excel/DXF. Продаваемый артефакт для встреч с месяца 2","Stage 2a (нед. 8-9) — data pipeline. A: парсер ПКК Rosreestr (httpx async, retries), модель Parcel с GeoAlchemy2, загрузка 1000+ участков Екбурга. B: Overpass API для POI, ДОМ.РФ/ЦИАН для цен м², кеш в Redis","Stage 2b (нед. 10-11) — скоринг+API+UI. A: 3 критерия скоринга (эвристики, без XGBoost), POST /parcels/search. B: страница /site-finder, Mapbox, градация по рейтингу, фильтры, карточка","Stage 2c (нед. 12) — интеграция + полировка. Кнопка «Обсчитать концепцию», демо-наполнение 50 участков, бэкапы БД, подача в реестр ПО","Урезано из v2.2 из-за part-time ×2: XGBoost→Фаза 1, JWT-auth→перед Раундом А, mypy --strict только на core, время генерации ≤15с (а не 10с) как fallback"]}
{"type":"entity","name":"Hosting_Decision_Apr25","entityType":"decision","observations":["Дата: 25 апреля 2026","Выбор хостинга для РФ: рассматривались Yandex Cloud, VK Cloud, Selectel, Timeweb Cloud, Cloud.ru (Сбер)","Рекомендован Yandex Cloud как основной вариант для Discovery + Production","Обоснование: (1) лучшая поддержка PostGIS в Managed PostgreSQL в РФ; (2) Container Registry + Container Solution включены; (3) входит в реестр российского ПО — плюс к нашей заявке; (4) солидно выглядит для инвесторов Раунда А","Стоимость Discovery (~10–15 тыс ₽/мес): VM Compute s3-c2-m4 (~3-4 тыс), Managed Postgres 1vCPU/4GB/30GB SSD (~5-7 тыс), Container Registry (бесплатно до 5GB), Object Storage для бэкапов (~500₽)","Альтернатива для жёсткой экономии: Selectel дешевле в 1.5–2 раза, но требует ручной PostGIS-рутины. Резерв на случай проблем с YC","Архитектура production: 1×VM с Docker Compose (backend + frontend + Caddy reverse proxy + auto-TLS) + Managed PostgreSQL (отдельный сервис) + Object Storage (бэкапы)","Образы: backend + frontend пушатся в Yandex Container Registry из GitHub Actions; на VM выполняется docker compose pull && up -d","GitHub Secrets для deploy: YC_SA_JSON_CREDENTIALS, YC_REGISTRY_ID, DEPLOY_HOST, DEPLOY_USER, DEPLOY_SSH_KEY, DEPLOY_PORT (опционально)","Caddy выбран вместо nginx: авто-TLS через Let's Encrypt без ручных certbot-рутин — дешевле по времени сопровождения для part-time команды","Домен: покупать в .ru зоне (REG.RU или РуЦентр), DNS на Yandex Cloud DNS или Cloudflare бесплатный","Production-путь на VM: /opt/gendesign/docker-compose.prod.yml + .env + Caddyfile"]}
{"type":"entity","name":"Onboarding_Colleague_KG","entityType":"procedure","observations":["MCP-сервер для памяти: npm-пакет mcp-knowledge-graph (запуск через npx -y)","Команда в claude_desktop_config.json: command=npx, args=['-y','mcp-knowledge-graph','--memory-path','<путь к папке с .jsonl файлами>']","Путь в рабочей среде основателя: C:\\mcp\\.aim","Стратегия разделённой памяти между коллегами: git синхронизация файла memory-gendesign.jsonl + хард-линк из репо в MCP-папку. Источник правды — репо","Конфликты в .jsonl обычно простые (файл построчный): решаются выбором \"оставить обе стороны\". rebase, не merge","Ритуал: git pull перед началом работы, git commit+push после изменений памяти","Полный текст процедуры выдан в чате 25 апреля 2026; при повторном запросе — восстановить из этой сущности"]}
{"type":"entity","name":"Hosting_Pricing_Apr25","entityType":"research","observations":["Дата проверки: 25 апреля 2026, фактические цены с сайтов провайдеров","Целевой конфиг: 2 vCPU / 4 GB RAM / 30-40 GB NVMe SSD + public IPv4. 60 GB избыточен для Discovery (реальное использование диска 12-15 GB: OS+Docker 5-7 GB + Postgres+PostGIS 0.5-1 GB + логи+бэкапы 1-2 GB + буфер 5 GB)","Selectel Standard Line 2/4 GB = 2308.86 ₽/мес (CPU+RAM only) + диск 30 GB Network SSD ~270 ₽ + public IP. Итого ~2700-3000 ₽/мес. Дороже конкурентов в 2-3 раза","Selectel Shared Line 2/4 GB с 10% vCPU = 1239 ₽/мес — дешевле, но CPU слишком слабый для Postgres+PostGIS под реальной нагрузкой","Timeweb Cloud MSK 50: 2 vCPU 3.3 GHz / 4 GB / 50 GB NVMe / 1 Гбит/с = 1062 ₽/мес со скидкой 10% при годовом контракте (или ~1180 ₽ без контракта). IPv4 включён. Реестр ПО № 15725","Beget VPS Standard 2 vCPU 3+ GHz / 4 GB / 40 GB NVMe = 33 ₽/день сервер + 5 ₽/день IPv4 = 38 ₽/день ≈ 1140 ₽/мес. Автобэкапы раз в несколько дней бесплатно. KVM. Реестр ПО № 16697","Beget VPS 2/2/30 = 27 ₽/день + 5 ₽ IP = 32 ₽/день ≈ 960 ₽/мес — ещё дешевле, но 2 GB RAM маловато для Postgres+PostGIS+Redis+backend+frontend+Caddy","Рекомендация Discovery: Beget VPS 2/4/40 NVMe + IP ≈ 1140 ₽/мес (самый дешевый реально рабочий конфиг) или Timeweb Cloud MSK 50 ≈ 1062 ₽/мес (лучше NVMe, больше диск)","Ранее в Hosting_Decision_Apr25 был предложен Yandex Cloud (~10-15 тыс ₽/мес с managed services). Это вариант для продакшена после Раунда А, не для Discovery","Для Discovery Beget выигрывает по цене и бесплатным бэкапам. Timeweb выигрывает по UI/UX панели и большему диску. Selectel оправдан только если планируется быстрый перевод на managed Postgres/K8s в их экосистеме"]}
{"type":"entity","name":"SSH_Setup_Apr25","entityType":"infrastructure","observations":["SSH-ключ для проекта: ed25519, без passphrase (для автодеплоя из GitHub Actions)","Локация: $HOME\\.ssh\\gendesign_deploy (приватный) + .pub (публичный)","Comment ключа: 'gendesign-deploy'","SSH config alias: 'Host gendesign' с IdentityFile ~/.ssh/gendesign_deploy — коннект командой 'ssh gendesign'","Публичный ключ вручную загружается в панель хостинг-провайдера при создании сервера","Приватный ключ позже пойдёт в GitHub Secret DEPLOY_SSH_KEY (для deploy.yml workflow)","Windows-специфика: icacls нужен для ограничения прав на приватный ключ, иначе OpenSSH ругается на 'UNPROTECTED PRIVATE KEY FILE'"]}
{"type":"entity","name":"WorkSplit_Generative_Stage1","entityType":"plan","observations":["Принцип разделения: вертикальные срезы по этапам пользовательского пути, не по слоям","Person A — 'Geometry → Variants' owner: Shapely-сервис, нормативные отступы, жадный алгоритм с 3 стратегиями, STRtree коллизии, профилировка. API endpoint POST /concepts, владелец схемы ConceptInput+buildings_geojson. Фронт: Leaflet, импорт/отрисовка полигона, форма параметров, рендеринг 3 вариантов на карте","Person B — 'Variants → Reports' owner: TEAP-сервис, финансовая модель, экспорты PDF/Excel/DXF (WeasyPrint+openpyxl+ezdxf). API endpoint /concepts/:id/export, владелец схем TEAP+FinancialModel. Фронт: таблицы ТЭП, форма финмодели, кнопки скачивания, сравнение вариантов","Точка стыка = Pydantic-контракт ConceptVariant в backend/app/schemas/concept.py. Договариваются в первый день Stage 1a, дальше оба работают с заглушками друг друга без блокировки","Точка стыка 2 — codegen TS-типов: при любой правке схемы оба запускают 'npm run codegen' локально","Календарь по неделям (Stage 1, нед.2-7): A движется по вектору схема→отступы→алгоритм→стратегии→тесты. B движется по вектору схема→TEAP→financial→Excel→DXF→PDF→тесты","Альтернативный расклад при асимметрии навыков: Алгоритмист (A) берёт все 4 backend-сервиса (geometry+TEAP+financial+exporters), фронт минимум. Продуктовик (B) берёт весь фронт + UI экспортов, backend минимум (тонкий export endpoint)","Анти-паттерны: разделение backend/frontend (блокирует второго), общие прямые пуши в main, молчаливые правки Pydantic без codegen, pair programming на каждой задаче (дорого для part-time ×2)"]}
{"type":"entity","name":"DataSources_Pricing_Apr25","entityType":"research","observations":["Дата: 25 апреля 2026","В РФ открытых данных по реальным сделкам (Росреестр) НЕТ — только агрегаты. Цены и площади из агрегаторов (ЦИАН/ДомКлик/Авито) — по объявлениям, не по сделкам","Открытые официальные источники (бесплатно, без юрриска): ДОМ.РФ (наш.дом.рф + api.dom.rf, реестр новостроек, площади в жк, колво квартир по комнатностям, класс жилья); Росстат (fedstat.ru, средние цены м² по регионам квартально); Минстрой (норматив цены м² для субсидий); Главгосэкспертиза НЦС (gge.ru, себестоимость м² строительства)","Скрейпинг агрегаторов (серая зона): ЦИАН (cianparser/cianscraper либы на GitHub, но Cloudflare и рейтлимит); Авито; ДомКлик; Яндекс.Недвижимость. Юридически — нарушение ТОС, но исков против мелких парсеров немного","Платные отраслевые: ЕРЗ.РФ Премиум (50-100тыс ₽/год, отраслевой стандарт); Knight Frank/NF Group/CBRE отчеты; PROEstate Analytics; СберИндекс (бесплатно)","Industry-standard unit-mix (из практики): Студии/1к/2к/3к/4+к по классам. Эконом: 15-20/35-40/25-30/10-15/0-5%. Комфорт: 8-12/25-30/30-35/20-25/5-10%. Бизнес: 5-10/18-22/30-35/25-30/10-15%. Премиум: 0-5/10-15/30/30-35/20-25%","Средние площади квартир м² (студия/1к/2к/3к): Эконом 22-28/33-38/50-58/70-80; Комфорт 26-30/38-44/58-66/80-92; Бизнес 30-35/45-55/70-85/100-125; Премиум 35-45/55-70/90-110/130-180. Нормативная нижняя граница — СП 54.13330.2016","Рекомендация для Discovery: Цены — Росстат baseline + ручной парсинг/скрейп ЦИАН 200 объявлений по районам Екбурга. Площади+unit-mix — захардкодить таблицу с возможностью ручной правки. Себестоимость — НЦС Главгосэкспертизы. Новостройки-конкуренты — API ДОМ.РФ","Для реестра ПО декларируем только легальные источники: ДОМ.РФ, Росстат, Главгосэкспертиза, OpenStreetMap. Скрейп ЦИАН — «внутренний справочник curating». Для инвесторов Раунда А — «договорённости с источниками рыночных данных в проработке»"]}
{"type":"entity","name":"SalesTracking_Strategy_Apr25","entityType":"strategy","observations":["Дата анализа: 25 апреля 2026","Исходный вопрос: можно ли косвенно понять, какие квартиры продаются и какие нет. Ответ: да, через ejednevnyy мониторинг шахматок застройщиков + delta-tracking","Прямые данные о сделках в РФ закрыты: Росреестр ДДУ не в open data, нотариусы и банки — закрытые источники","Косвенные источники по точности: 1) Шахматки застройщиков — 95%+ точность, золотая жила. 2) ДОМ.РФ реестр ДДУ по ЖК — 100% на уровне агрегата. 3) Delta-tracking listings ЦИАН/Авито — 70% точность. 4) ДомКлик ипотечная статистика — sanity check на уровне района. 5) Фиксация снижений цен — сигнал «не продаётся»","Шахматки = золотая жила. На сайтах ПИК/Брусника/Атомстройкомплекс/ТЭН-Девелопмент/Стройтэк/ЛСР и др. интерактивная шахматка с поквартирным статусом (доступно/бронь/продано). Даёт площадь, комнатность, этаж, секцию, цену, дату продажи","Тех-план: воркер services/site_finder/sales_tracker.py + поадаптеру на каждого застройщика (brusnika_scraper.py, atomstroy_scraper.py...). Cron 1×в сутки. SPA-сайты — Playwright. SSR — httpx+BS4","Схема БД: apartments(id, jk_id, room_count, area_sqm, floor, section, price_rub, status, last_seen_at) + sales_history(apartment_id, sold_date, sold_price). Materialized views для velocity в радиусе X от точки","Три киллер-фичи из этих данных: A) Velocity Score в Site Finder — дополнительный 4-й критерий скоринга (сколько квартир продаётся/мес в радиусе 1км). B) Smart Unit-Mix в Generative — рекомендация долей 1/2/3-комн на основе реальных продаж в районе. C) Validation финмодели — бенчмарк прогноза выручки против факта по соседним ЖК","Это самый важный data moat: TestFit без РФ-данных, rTIM без site-selection и аналитики спроса. Через 6-12 мес накопления — уникальный источник данных для девелоперов, который не воспроизвести конкурентам быстро","План Discovery: Stage 2a нед.8-9 добавляется воркер sales_tracker параллельно парсеру ПКК. Реализуем 5-7 адаптеров (топ-застройщики Екбурга). К концу месяца 3 имеем 2-3 недели исторических данных","Целевые застройщики Екбурга для Discovery: Атомстройкомплекс, Брусника, ТЭН-Девелопмент, Стройтэк, Прогресс, УГМК-Застройщик, Кортрос, ЛСР-Урал, Forum-group, ПИК (если есть в ЕКБ)","Юридика: шахматки = публичные маркетинговые данные (без авторизации, серая зона мягче ЦИАН). Прецедентов исков застройщиков к парсерам практически нет (им нужны шахматки как воронка маркетинга). Для реестра ПО декларируем как «партнёрские интеграции с открытыми источниками застройщиков»","Анти-риски: 1) Сайт застройщика меняет вёрстку — скрейпер ломается, нужен Sentry alerting. 2) Юр-претензия от крупного застройщика — митигация через «партнёрство возамен аналитики» с топ-3 таргетов. 3) Низкое качество сайтов мелких застройщиков — берём только тех, у кого нормальный веб-интерфейс","Через 6 мес накопления: сезонные коэффициенты, absorption curves по типам квартир, ML-предсказание velocity для нового участка. Для Раунда А это идеальный narrative: «уникальная база продаж новостроек Свердловской обл., которой нет в открытых источниках и у западных игроков»"]}
{"type":"entity","name":"PlanA_AnalyticsFirst_Apr25","entityType":"decision_pending","observations":["Дата: 25 апреля 2026, вечер. Обсуждали с Антоном (второй разработчик)","Новые вводные: Антон сказал, что есть доступ ко всем сделкам для анализа. Детали по данным будут в понедельник 27 апреля 2026","Предложение Антона: сначала аналитика по продажам (что строить, какие квартиры, площади), потом всё остальное","Решение (предварительное, ждём детали): НЕ полный pivot. Перестановка порядка этапов: Stage 1 = Sales Analytics (нед 2-5), Stage 2 = Generative со Smart Defaults из аналитики (нед 6-10), Stage 3 = Site Finder с Velocity Score (нед 11-12)","Обоснование не полного pivot: Generative — главный дифференциатор против rTIM/TestFit. Без него конкурируем напрямую с ЕРЗ/ДОМ.РФ (у них 5 лет данных и команда). Аналитика становится мозгом для Generative и Site Finder, а не их заменой","Концепция «3 плитки»: ввод участок + класс жилья → (1) ЧТО СТРОИТЬ (unit-mix с velocity), (2) СКОЛЬКО ПРОСИТЬ (распределение цен м² по классам + тренд), (3) ЗА КАКОЕ ВРЕМЯ ПРОДАСТСЯ (absorption curves по АНАЛОГам). Кнопка «Сгенерировать концепцию» ведёт в Generative","Плюс нового плана: продаваемый артефакт уже после мес 1 (раньше был конец мес 2). Меньше технического риска. Другой ICP (инвестдепартамент вместо архитектуры)","КРИТИЧНО: «доступ ко всем сделкам» — это фундамент или мина. Бывают 4 сценария: 1) Легальный богатый ongoing (ЕРЗ Premium/банк/админ) → полный pivot, аналитика фундамент. 2) Легальный ограниченный → план A + шахматки параллельно для ongoing. 3) Серый канал → НЕ строим бизнес на этом, используем только «для себя». 4) Обещают но не дают → идём по плану шахматок, ждём","6 блоков вопросов к Антону на 27 апреля: Природа канала (что именно за доступ); Поля данных (цена/метраж/комнатность/покупатель?); Покрытие (регионы/история); Свежесть (разовая выгрузка или ongoing); Условия использования в коммерческом продукте; Цена доступа","Что делаем до пн (не останавливаемся, но с осторожностью): SSH-ключ, выбор хостинга (Beget/Timeweb), Stage 0 скелет уже сделан. НЕ начинаем Shapely геометрию или парсер ПКК — приоритет может сместиться","Шахматки застройщиков НЕ отменяются даже если данные Антона полные: 1) Сделки в Росреестре регистрируются с лагом 1-3 месяца. 2) Бронирования и доступность — сделки этого не показывают. 3) Маркетинговая цена vs фактическая различается","Сообщили Кене ответ Антону: направление в точку, но не полный pivot. Ждём детали по данным в пн. Вижу 6 блоков вопросов. От ответов зависит тип плана","Уточнение 25.04.2026 вечер: Антон подтвердил — речь идёт о ДДУ (Договорах Долевого Участия). Это идеальный источник для аналитики: ground truth по продажам новостроек, выше качеством чем шахматки","ДДУ поля стандартно: кадастровый номер квартиры, площадь, цена, дата регистрации, застройщик, ЖК. иногда комнатность/этаж/секция. ПН-поверхность: ПДн покупателя часто включены — обязательное обезличивание до записи в нашу БД (152-ФЗ)","Лаг ДДУ: 30-90 дней от реальной сделки до регистрации в Росреестре. Поэтому шахматки застройщиков НЕ отменяются — они дают 'today snapshot', ДДУ дают 'historical truth'","5 блоков к понедельнику (сужены до ДДУ-специфики): 1) Канал — держатель и договор (DOM.RF API/ЕРЗ Premium/банк/администрация/другое). 2) Поля (все ли обязательные + комнатность и ПДн). 3) Покрытие (регионы/история). 4) Свежесть (разовая/ongoing/real-time и лаг). 5) Условия коммерческого использования","Преимущество ДДУ над шахматками: ground truth по фактической цене (не маркетинговой), историческая глубина, юридически чистый источник (если канал легален), data moat относительно TestFit/rTIM"]}
{"type":"entity","name":"Runbook_VPS_Setup_Beget","entityType":"runbook","observations":["Источник: фактическая настройка сервера Jolly Yakov в Beget Cloud, 25.04.2026. Сервер 2 vCPU / 4GB RAM / 40GB NVMe / Ubuntu 24.04, IP 46.173.16.127","ШАГ 1: Создание сервера в cp.beget.com/cloud → Создать сервис → VPS → Standard 3+ GHz → 2 ядра/4GB/40GB. ОС: Ubuntu 24.04. Включить публичный IPv4. После создания сервер получает IP, root пароль выслан на email","ШАГ 2: Генерация SSH-ключа локально (если ещё нет). Windows PowerShell: ssh-keygen -t ed25519 -C 'gendesign-deploy' -f $HOME\\.ssh\\gendesign_deploy. Пароль оставить пустым (Enter Enter) — нужно для автодеплоя","ШАГ 3: Добавление публичного ключа на сервер через панель Beget. При проблемах со SSH (Connection reset, fail2ban) — войти через VNC терминал в браузере и добавить в ~/.ssh/authorized_keys","ШАГ 4: Первый вход по SSH с явным ключом. Команда: ssh -i $HOME\\.ssh\\gendesign_deploy root@<IP>. При первом коннекте спросит fingerprint — yes","ШАГ 5: На сервере (root): обновить пакеты 'apt update && apt upgrade -y'. Если [-f /var/run/reboot-required] то ребут. Установить hostname/timezone: hostnamectl set-hostname gendesign; timedatectl set-timezone Europe/Moscow","ШАГ 6: Создание non-root пользователя. adduser gendesign (задать сильный пароль, остальное Enter). usermod -aG sudo gendesign. Копия SSH-ключа root→gendesign: mkdir -p /home/gendesign/.ssh && cp ~/.ssh/authorized_keys /home/gendesign/.ssh/ && chown -R gendesign:gendesign /home/gendesign/.ssh && chmod 700 /home/gendesign/.ssh && chmod 600 /home/gendesign/.ssh/authorized_keys","ШАГ 7: Тест первого входа как gendesign. Важно: хранить root-сессию открытой как safety net до конца. В новом окне: ssh -i $HOME\\.ssh\\gendesign_deploy gendesign@<IP>. Проверка sudo: sudo whoami → root","ШАГ 8 (Windows-специфика): SSH config не создавать через Notepad — он добавляет .txt и сохраняет в UTF-8 с BOM. Правильный способ: PowerShell heredoc | Out-File -Encoding ascii -FilePath $HOME\\.ssh\\config. Блок Host: HostName <IP>, User gendesign, Port 22, IdentityFile ~/.ssh/gendesign_deploy, IdentitiesOnly yes, ServerAliveInterval 60. Критично включать IdentitiesOnly yes — иначе Windows OpenSSH перебирает все ключи и получает MaxAuthTries reset не дойдя до нужного","ШАГ 9: Отключение root-логина и паролей в SSH. ТОЛЬКО ПОСЛЕ подтверждения gendesign работает и sudo работает. sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak; sudo nano /etc/ssh/sshd_config → PermitRootLogin no, PasswordAuthentication no, PubkeyAuthentication yes. sudo sshd -t для валидации. sudo systemctl reload ssh","ШАГ 10: Критический тест в третьем окне: ssh gendesign → пускает по ключу. В четвёртом: ssh root@<IP> → должен отказать. Старую root-сессию закрываем только после этого","Распространённые грабли: 1) Connection reset при неверном пароле = fail2ban Beget. Обход через VNC. 2) Notepad вместо config пишет config.txt — проверять ls $HOME\\.ssh\\. 3) Windows OpenSSH без IdentitiesOnly перебирает все ключи. 4) Группа sudo не подхватывается без выхода-входа. 5) При UNPROTECTED PRIVATE KEY FILE использовать icacls /inheritance:r /grant:r '<имя>:(R)'","Статус 25.04.2026 вечер: Шаги 1-7+8 выполнены. gendesign@46.173.16.127 работает по ключу, sudo работает. Осталось: SSH hardening (Шаг 9), UFW firewall, установка Docker, клонирование репо в /opt/gendesign","Статус 25.04.2026 вечер (обновлён): Базовая настройка VPS завершена. gendesign@46.173.16.127 работает по ключу, sudo работает. UFW активен (22/80/443). SSH hardening: PermitRootLogin no, PasswordAuthentication no, PubkeyAuthentication yes через drop-in /etc/ssh/sshd_config.d/00-gendesign-hardening.conf (приоритет 00- перебивает cloud-init defaults). Docker и git установлены. Репо клонировано в /opt/gendesign через deploy key github_deploy. PostgreSQL+PostGIS и Redis работают в докер-компоуз. PostGIS_Version() = 3.4 USE_GEOS=1 USE_PROJ=1 USE_STATS=1","Осталось: GHCR setup (замена YCR на GHCR в deploy.yml + docker-compose.prod.yml), GitHub Secrets, Caddy reverse proxy, домен, первый автодеплой backend+frontend","ВЕХА 25.04.2026 вечер: Первый успешный автодеплой. GitHub Actions воркфлоу deploy.yml прошёл полный цикл: build обоих образов (backend ~2.5мин, frontend ~1мин) → push в GHCR (ghcr.io/lekss361/gendesign-backend, gendesign-frontend, приватные) → SSH на сервер → docker compose pull (с PAT-авторизацией) → up -d. /health отвечает {status:ok, environment:prod}","GHCR пакеты остаются ПРИВАТНЫМИ (решение пользователя для защиты алгоритмов). Сервер авторизуется в GHCR через PAT с read:packages, сохранён в ~/.docker/config.json. PAT с длительным сроком или без срока","Исправлены во время деплоя: backend Dockerfile (убрал невалидный conditional COPY для alembic, перешли на uv sync без --frozen до генерации lockfile); frontend package.json (react-leaflet 4→5 для совместимости с React 19); frontend Dockerfile (npm install --legacy-peer-deps вместо npm ci, пока нет lockfile); frontend/public/.gitkeep для Next.js standalone build","Статус инфраструктуры к 25.04.2026 19:00: VPS Beget работает (Москва, 2/4/40 NVMe). UFW + SSH hardening + non-root user. Docker compose prod поднят с 5 сервисами (postgres+redis+backend+frontend+caddy). GitHub Actions автодеплой работает на push в main. /health публичен внутри VM (127.0.0.1:8000)","Осталось до «infra-ready»: домен, Caddy TLS с Let's Encrypt на этот домен, регулярные pg_dump в Object Storage, frontend NEXT_PUBLIC_API_BASE_URL на реальный домен (сейчас пустая). И дальше — Stage 1 разработки по выбранному PlanA_AnalyticsFirst_Apr25 (после понедельника с Антоном по ДДУ-данным)"]}
{"type":"entity","name":"Hardlink_Test_Apr25","entityType":"test","observations":["Тестовая запись, дата 25.04.2026 поздний вечер","Цель: проверить, что после пересоздания хард-линка записи MCP попадают в репо-файл memory/memory-gendesign.jsonl","Ожидаемый результат: размер репо-файла увеличится, git status покажет modified","Наблюдение: предыдущий хард-линк разорвался (LinkType был null, синхронизация репо-файла с MCP-папкой прекратилась). Репо-файл был 16550 байт, источник 43957 байт","Если тест пройдёт (синхронизация восстановлена) — рабочий цикл из README снова валиден. Если не пройдёт — нужен sync-memory.ps1 скрипт или альтернатива"]}
{"type":"entity","name":"Domain_Setup_Apr26","entityType":"infrastructure","observations":["Дата: 26.04.2026","Домен: gendsgn.ru, регистрация в Beget, срок до 26.04.2027","Стоимость: 199 ₽ первый год, 420 ₽/год продление. Сравнение из браузера 26.04.2026: Reg.ru 169₽ первый год + ~890₽ продление; Timeweb 200/399; nic.ru 747₽ регистрация (премиум)","Решение: Beget — потому что (1) хостинг VPS уже там, единая админка и единая платежка для бухгалтерии; (2) продление 420₽ — лучшее на рынке; (3) free DNS включён","DNS-серверы: ns1.beget.com, ns2.beget.com (плюс ns1.beget.pro, ns2.beget.pro как backup)","A-записи прописаны 26.04.2026: @ (apex) и www → 46.173.16.127. Beget NS отдают корректно (проверено nslookup gendsgn.ru ns1.beget.com → 46.173.16.127). Публичные резолверы (8.8.8.8, 1.1.1.1) на 26.04 ещё NXDOMAIN — пропагация .ru registry → public DNS, ожидаемо 30 мин - 4 часа","Caddyfile обновлён под gendsgn.ru: основной site block с auto-TLS Let's Encrypt, www → 301 redirect на apex, :80 fallback для IP-доступа сохранён. Закоммичен 68e95aa, запушен в main. На VM не применён (старый deploy.yml не делает git pull)","deploy.yml будет дополнен `git fetch + reset --hard origin/main` + `caddy reload --config /etc/caddy/Caddyfile` после `up -d`. Закоммитим и запушим когда DNS пропагируется. Это финальный шаг для HTTPS","Важное правило отрасли: с 1 сентября 2026 владелец .ru-домена обязан иметь подтверждённую учётку ЕСИА (Госуслуги) — иначе домен не продлят. Для ИП/ООО — через ЭДО/СБИС. Касается всех регистраторов одинаково. К моменту продления (26.04.2027) ООО уже должно быть зарегистрировано — учёт без проблем"]}
{"type":"entity","name":"Sentry_Setup_Apr26","entityType":"infrastructure","observations":["Дата: 26.04.2026","Sentry организация: qqq (qqq-5y.sentry.io), free tier (5К ошибок + 10К транзакций / мес)","Sentry проект: gendesign-backend, платформа FastAPI, регион Frankfurt (ingest.de.sentry.io)","DSN сохранён в /opt/gendesign/backend/.env как SENTRY_DSN. На локальной машине — не нужен (Sentry init в backend/app/main.py условный — отключён если DSN пустой)","Конфиг init: sentry_sdk.init(dsn=settings.sentry_dsn, environment=settings.environment, traces_sample_rate=0.1) — 10% запросов трейсятся для performance","Алерты: «high priority» по умолчанию + email на alexandro361@gmail.com","Тестовое событие отправлено и получено 26.04.2026 — event_id 67f05bdd59234a608a828fa81f72ded5. Sentry интеграция работает на проде","Важная операционная заметка: docker compose restart НЕ перечитывает env_file. После правки backend/.env нужно `docker compose -f docker-compose.prod.yml up -d --force-recreate --no-deps backend`. Применимо к любым env-изменениям, не только Sentry","DSN — не критичный секрет (в frontend SDK всегда зашит публично в JS-бандл). Держим в .env, не в репе. Ротация при необходимости через Sentry → Settings → Client Keys (DSN) → New Key"]}
{"type":"entity","name":"OpsBundle_Apr26","entityType":"infrastructure","observations":["Дата: 26.04.2026","Подготовлен пакет инфраструктурных правок (в working tree, не закоммичено): Alembic baseline + TIGER cleanup + pre-commit + pg_dump backups + Makefile targets","Alembic: создан backend/alembic.ini + backend/alembic/env.py (импорт Base из app.core.db, моделей через app.models.*) + script.py.mako + versions/.gitkeep. Первая реальная миграция — в Stage 2a, когда Parcel-модель будет финализирована. Сейчас versions/ намеренно пуст","TIGER cleanup: backend/db/init/99_drop_unused_extensions.sql дропает postgis_tiger_geocoder + postgis_topology + fuzzystrmatch на свежем postgres-volume (через bind-mount ./backend/db/init:/docker-entrypoint-initdb.d:ro в обоих compose-файлах). Срабатывает только при первой инициализации пустого volume","Pre-commit: .pre-commit-config.yaml в корне (trailing-whitespace, end-of-file-fixer, ruff lint+format на backend/, prettier на frontend/, detect-private-key, check-yaml/toml). Pre-commit добавлен в dev-deps backend/pyproject.toml. Локально — `python -m pre_commit install` или `make pre-commit-install`","pg_dump: ops/backup.sh — cron-скрипт с опциональной выгрузкой в S3. Ретенция 7 дней локально. ops/restore.sh с защитой RESTORE_CONFIRM=yes","Makefile: добавлены `make migration NAME=...` и `make pre-commit-install`. `make migrate` использует `alembic` напрямую (uv нет в production-образе)","backend/Dockerfile: COPY alembic.ini + COPY alembic в обе стадии (builder и runner)","S3 для бэкапов: пока не настроено. Когда настроим Selectel или Yandex Object Storage, env-конфиг — /etc/default/gendesign-backup на VM, cron — `30 3 * * * /usr/local/bin/gendesign-backup`"]}
{"type":"entity","name":"Production_Wipe_Apr26","entityType":"event","observations":["Дата: 26.04.2026","Прод полностью пересоздан с нуля для чистого состояния. Не было критичных данных — БД содержала только postgis-defaults","Команды на VM: `docker compose down -v` → `docker rmi` GHCR-образов и базовых (caddy:2, postgis/postgis:16-3.4, redis:7-alpine) → `git pull --ff-only` (Caddyfile, compose) → `docker system prune -af --volumes`","Re-deploy через GitHub Actions Deploy → все 5 контейнеров поднялись с image-тегом 08a63f6 (главный коммит на момент wipe)","Состояние после re-deploy: postgres healthy, redis healthy (новый healthcheck), backend healthy (фикс curl-healthcheck в multi-stage Dockerfile), frontend up, caddy up. PostGIS 3.4 USE_GEOS=1 USE_PROJ=1","TIGER-мусор вернулся (как ожидалось) при свежей инициализации postgis-image. Будет автоматически удаляться при следующих wipe-ах когда применим OpsBundle_Apr26 (init-скрипт 99_drop_unused_extensions.sql)"]}
{"type":"entity","name":"DockerOps_Apr26","entityType":"infrastructure","observations":["Дата: 26.04.2026","Серия Docker-фиксов задеплоена в main: e22aeb9 (multi-stage + npm ci + healthcheck + same-origin API), d0909e6 (ruff fixes), 08a63f6 (mypy fixes), 68e95aa (real domain Caddyfile)","backend/Dockerfile: переписан на multi-stage (builder с build-essential + libgdal-dev + uv sync; runner только с runtime-либами libpq5, libgdal36, libproj25, libgeos-c1t64, libcairo2, libpango*, curl). Финальный образ 1.44 GB вместо ~2 GB. Запускается под non-root пользователем `app` (uid 1000)","backend curl healthcheck в docker-compose.prod.yml теперь работает (до этого был баг — curl не был установлен в slim-образе)","frontend/Dockerfile: переключён на `npm ci --legacy-peer-deps` вместо `npm install`. Запускается под `node` (uid 1000). package-lock.json закоммичен","docker-compose.prod.yml + dev: убран dead NEXT_PUBLIC_API_BASE_URL (Next.js bakes NEXT_PUBLIC_* на build-time, runtime override no-op). Frontend ходит на same-origin /api/* — в проде через Caddy, в dev через Next.js rewrites (BACKEND_URL env)","Caddyfile: исправлен баг — handle_path /api/* стрипал префикс /api, FastAPI router на /api/v1/* возвращал 404. Заменено на handle /api/*","backend/uv.lock сгенерирован (через docker run python:3.12-slim + pip install uv && uv lock). Дальнейшие билды детерминированы: `uv sync --frozen --no-dev`","Ruff config: ignore=['RUF001','RUF002','RUF003'] — проект русскоязычный, кириллица в комментариях/docstring (МСК-66 etc.) — норма, иначе постоянно ругается"]}
{"type":"entity","name":"HTTPS_Live_Apr26","entityType":"milestone","observations":["Дата: 26.04.2026, ~14:41 MSK","Прод официально живой на HTTPS: https://gendsgn.ru/ возвращает 200, https://gendsgn.ru/health → {\"status\":\"ok\",\"environment\":\"prod\"}, https://www.gendsgn.ru/ → 301 на apex","Цепочка: ЕСИА-верификация в Beget → реестр .ru обновился → DNS пропагировался к 8.8.8.8/1.1.1.1 → push deploy.yml с git-pull+caddy-reload не делался (юзер сделал руками на VM) → пришлось вычищать caddy_data volume чтобы сбросить старый retry-state на gendesign.example.ru и Let's Encrypt staging fallback → Caddy перезагрузился чисто → cert получен с production Let's Encrypt","Урок: при wipe `down -v` мы убрали весь caddy volume включая ACME-state. Если бы оставили — Caddy продолжал бы фоновые retry-задачи на старый плейсхолдер gendesign.example.ru, и accumulated failures могли бы триггернуть staging fallback. На будущее: `caddy reload` не сбрасывает retry queue — для чистого старта нужен `restart` или volume-wipe","GitHub-issues #1 (ЕСИА) и #2 (push deploy.yml) можно закрывать как done","Стек живет: HTTP/2 + HTTP/3 (alt-svc), Caddy reverse-proxy фронт+бэк, FastAPI корректно отвечает через /api/* префикс (handle вместо handle_path сработал)"]}
{"type":"entity","name":"DataSources_Analysis_Apr26","entityType":"research","observations":["Дата: 26.04.2026. Глубокий анализ источников данных для GenDesign — проверено через debug-браузер на наш.дом.рф","🥇 ГЛАВНАЯ НАХОДКА: ДОМ.РФ имеет ОТКРЫТЫЕ JSON API без аутентификации. Это меняет всё для Plan A и Site Finder","ДОМ.РФ Аналитика API (`naash.dom.rf/portal-analytics/api/`): /dictionaries/regions, /dictionaries/developers, /dashboard/by-room-count, /dashboard/by-flat-area, /dashboard/by-developer, /dashboard/by-region. Возвращают JSON: по каждому региону id, flatCount, area, и details — разбивка по комнатности (ONE/TWO/THREE/FOUR с площадями и %). Базовый URL хоста: https://xn--80az8a.xn--d1aqf.xn--p1ai (он же наш.дом.рф). Без auth, accept: application/json. Свердл. обл. id=66, flatCount=115205, area=5.67M м²","ДОМ.РФ Каталог квартир API (`/сервисы/api/kn/`): /flats/map?latitudePoint1=...&latitudePoint2=...&longitudePoint1=...&longitudePoint2=...&flatStatus=free,booked возвращает per-ЖК записи {objId, latitude, longitude, priceMin, objStatus}. /flats/filters даёт диапазоны фильтров. Auth: header `Authorization: Basic MTpqd2U=` (= base64('1:qwe')) — хардкод в фронте, действующий ключ. По Свердл. обл. видно 24 441 квартир в продаже","ДОМ.РФ доступные на per-flat фильтры (которые присутствуют в JSON): кол-во комнат (студия/1/2/3/4+), год сдачи (Сдан/2026/2027/2028+), цена (от 2.6М до 4.8 млрд), площадь (16-1001 м²), этаж (1-68), цена м² (82К-7.2М), отделка (без/черновая/предчистовая/чистовая/под ключ), класс (типовой/комфорт/бизнес/элитный), материал стен (блоки/кирпич/панель/монолит/монолит-кирпич), тип (жилое/нежилое), эскроу, безбарьерная среда, благоустройство, энергоэффективность, наличие апартаментов","ДОМ.РФ покрытие России: 2.4 млн квартир в строящихся домах, 118.7 млн м². По регионам ТОП-20 включает Свердл.обл (4-е место, 5.67М м²). По девелоперам ТОП-15: Самолет, ПИК, DOGMA, ТОЧНО, ФСК, Брусника, Setl Group, ЛСР и др.","ДОМ.РФ распределение площадей квартир в РФ: 0-25м²: 6%, 25-35м²: 17%, 35-45м²: 30% (мода), 45-55м²: 14%, 55-70м²: 20%, 70-85м²: 8%, 85-100м²: 3%, более 100м²: 2%. В среднем около 49 м² (118.7М/2.4М). Это ВАЖНЕЙШИЙ benchmark для smart unit-mix Plan A","ДОМ.РФ распределение по комнатности: 1-комн 54% (1.31М), 2-комн 32% (0.78М), 3-комн 12% (0.30М), 4+комн 1% (33К)","ДОМ.РФ есть еще API endpoints: Единый реестр застройщиков, Единый реестр МЖК, Единый реестр ЖСК, Единый реестр проблемных объектов, Реализация квартир в строящихся домах (динамика продаж!), Распроданность и стройготовность (что-то вроде velocity!). Все по naash.dom.rf/аналитика/*. Велоситит и распроданность — могут быть прокси для нашего sales_tracker без необходимости парсить шахматки","🥈 ВЫВОД: для Plan A не нужно ждать ДДУ-данные от Антона. ДОМ.РФ открыто отдает агрегаты + ground truth по объектам. Это юридически чистый канал ('через API ДОМ.РФ' можно официально декларировать в реестре ПО)","Overpass API (OpenStreetMap, https://overpass-api.de/api/interpreter): бесплатно, без авторизации. Синтаксис Overpass QL: `[out:json][timeout:25]; node[\"amenity\"=\"school\"](56.7,60.5,56.9,60.7); out body;` — все школы в bbox. Поддерживает radius `node(around:1000)[\"amenity\"=\"hospital\"]`. Релевантные tags для нас: amenity=school|hospital|clinic|kindergarten|university, public_transport=station+station=subway|tram|bus, shop=mall|supermarket, leisure=park|playground, highway=primary|secondary","Overpass rate limit: ~5 запросов/мин на IP. Для production — поднять свой mirror через Docker (overpass-api/docker-overpass-api), либо использовать кеш Redis (TTL 24-72 ч, POI редко меняются)","Росстат fedstat.ru (id=31452): 'Средняя цена 1 кв.м общей площади квартир на рынке жилья' — квартально по регионам РФ, разбивка первичка/вторичка, по типам квартир. Данные с 2000 по 2025. Скачивание SDMX/возможно CSV/XML. НЕТ публичного API. Подход: разовая выгрузка → Excel → загрузить в нашу БД, обновлять раз в квартал вручную","Минстрой РФ (minstroyrf.gov.ru): норматив средней рыночной стоимости 1 м² для расчета субсидий. Публикуется приказом Минстроя ежеквартально по всем регионам. Для Свердл. обл. ~85-95 тыс ₽/м² на 2025 год. Доступ: PDF приказа на сайте Минстроя, копия в КонсультантПлюс. Использовать как baseline для нашей финмодели","Главгосэкспертиза НЦС (gge.ru, был 404 на /ncs/, реальный URL на момент проверки изменился): нормативы цены строительства 1 м² по типам зданий + регионам. Используется для расчета бюджетов госзаказа. Публикуется приказом Минстроя ежегодно. Для частных девелоперов — сравнительный baseline 'минимальная себестоимость'. Найти актуальный URL через минстроя/КонсультантПлюс","ЕРЗ.РФ (erzrf.ru): главный конкурент по аналитике в РФ, премиум-доступ. Полные данные: реестр застройщиков, рейтинги ЖК, статистика продаж, вакантность. Цена доступа на сайте не раскрыта — нужно запрашивать. Industry knowledge: ~50-100 тыс ₽/год за подписку на регион, ~500 тыс ₽/год за всю РФ. У них есть API B2B (под NDA). Использовать как 'договорённости в проработке' для инвесторов Раунда А, реально подписываться когда будет budget","СберИндекс (sberindex.ru, не открылся через WebFetch — 'unable to verify the first certificate', попробовать через браузер позже): бесплатные агрегаты Сбера по экономике РФ, включая жилье. Покрытие хорошее, обновление часто. Использовать для cross-validation с ДОМ.РФ + Росстат","ДомКлик (domclick.ru): listings первички и вторички + ИПОТЕЧНАЯ статистика. Открытый каталог с ценами/площадями. Анти-бот защита есть, но не очень жёсткая. Публичный sitemap.xml. Подход: спарсить раз в неделю свердл.обл (~50 тыс листингов), сохранить в БД с history. Для cross-check ДОМ.РФ цен","ЦИАН (cian.ru): крупнейший аггрегатор РФ. Cloudflare защита + rate limit. Парсить рискованно (юридически серая зона + блокировки). Готовые либы: cianparser, cianscraper на GitHub. Использовать ОЧЕНЬ ограниченно (200-500 листингов на район для калибровки), не как основной источник","Авито Недвижимость (avito.ru): аналогично ЦИАНу — антибот, Cloudflare. Есть платный B2B API (через avito_business — недешево). Для Discovery — пропускаем","Яндекс.Недвижимость (realty.ya.ru): listings, иногда XML feed для риелторских CRM. Есть Yandex Realty API (документированный, но enterprise). Для Discovery — пропускаем","Шахматки застройщиков (Брусника, Атомстройкомплекс и т.д.): по факту самый ground-truth источник для today snapshot. SPA-сайты — Playwright. SSR — httpx+BS4. План в Stage 2a/sales_tracker уже описан в SalesTracking_Strategy_Apr25. ОДНАКО — теперь когда у нас есть 'Реализация квартир' из ДОМ.РФ, шахматки могут быть downgrade-нуты до 'дополнительной валидации'","Другие источники (mention only): ОКТМО (для region IDs), ФИАС (адреса), Росреестр ПКК (только границы участков, без ДДУ), ДомРФ.Bank (ипотечные ставки — отдельный поток для финмодели), ЖКХ.МО.РФ (управляющие компании — для оценки операционных расходов). Всё в реестре российских данных.","ИТОГ — приоритеты по источникам для Discovery MVP (от 1 = критично до 5 = можно отложить):","1) ДОМ.РФ portal-analytics + api/kn/flats — бесплатно, открыто, ground truth, ВСЁ нужное для Plan A и Site Finder. Базовый источник","2) Overpass API (OSM) — бесплатно, для POI вокруг участков. Site Finder скоринг","3) Росстат fedstat.ru — квартальный baseline цен, разовая выгрузка → БД. Финмодель + cross-validation","4) Минстрой норматив + НЦС — для реалистичной себестоимости в финмодели","5) Шахматки 5-7 застройщиков Екбурга — дополнительная свежесть к ДОМ.РФ. Stage 2a опционально","Приоритет 1 ('вынес' ДДУ-данные): ВСЁ можно собрать сегодня вечером без Антона. Это разбивает блокировку #10 — даже если канал ДДУ серый/нет — Plan A 'analytics first' технически выполним на ДОМ.РФ data","Метрики, которые мы можем считать прямо из ДОМ.РФ для Plan A '3 плитки':","ПЛИТКА 1 — ЧТО СТРОИТЬ: для участка → район → ID региона → /portal-analytics/api/dashboard/by-room-count?regionId=X → распределение комнатности что строится. Дополнительно /dashboard/by-flat-area по тому же региону → распределение площадей. Smart unit-mix готов","ПЛИТКА 2 — ПО КАКОЙ ЦЕНЕ: для координат (lat,lon) → запрос /api/kn/flats/map в bbox 5km → собрать все priceMin → median + p10/p90 → диапазон цен в районе. Cross-check с Росстатом по региону","ПЛИТКА 3 — ЗА КАКОЕ ВРЕМЯ: /аналитика/реализация_строящихся_квартир + /распроданность-стройготовность по региону → absorption curves по комнатностям. Если бы у Антона были ДДУ — было бы точнее, но и без них есть прокси-сигнал","Юридическая безопасность для реестра ПО: всё что используем — ОФИЦИАЛЬНО открытые источники (ДОМ.РФ, Росстат, Минстрой, OSM). Никакого скрейпинга в обязательных каналах. Шахматки и ЦИАН — опциональные, помечаем как 'партнерские интеграции в проработке'","Implementation effort estimates (часы разработчика):","ДОМ.РФ analytics API клиент + кеш Redis: 4-6 часов","ДОМ.РФ flats/map per-объект клиент с пагинацией bbox: 6-8 часов","Overpass клиент + tag mapping для POI: 3-4 часа","Росстат разовая выгрузка + ETL в БД: 2-3 часа","Минстрой парсинг приказа PDF → таблица: 2-3 часа","СУММАРНО: 17-24 часа на полный data layer без Антона"]}
{"type":"entity","name":"DomRF_Integration_Docs_Apr26","entityType":"api_spec","observations":["Дата: 26.04.2026. Официальная страница интеграции ДОМ.РФ ЕИСЖС: https://наш.дом.рф/интеграция","⚠ ЮРИДИЧЕСКИЙ СТАТУС API СЖС: предназначено ТОЛЬКО ДЛЯ УПОЛНОМОЧЕННЫХ БАНКОВ согласно Постановлению Правительства РФ № 697 от 18.06.2018. Напрямую подключиться НЕ МОЖЕМ — мы не банк. Но публичный фронт-API наш.дом.рф (то что мы выяснили) легален и доступен всем.","5 различных API в составе ЕИСЖС (вкладки на странице /интеграция):","1) API СЖС (Сведения о Жилищном Строительстве) — главное API для банков, даёт данные по застройщикам, ГК, ЖК, объектам строительства. Это та же информация что на наш.дом.рф в публичной форме.","2) API Уведомления ОПО — опасные производственные объекты. Не наш.","3) API Агрегатор ПФ — Проектное Финансирование, инфо о договорах эскроу. Для банков.","4) API НСИ — Нормативно-Справочная Информация, классификаторы. Справочники.","5) Сервисы СМЭВ — Межведомственное Электронное Взаимодействие. Для госорганов.","Официальные документы на скачивание (все DOCX/PDF публичные):","Соглашение об информационном взаимодействии v5.1 (08.02.2026): /site/binaries/content/assets/domrf/support/developer/agreement/соглашение-об-информационном-взаимодействии.-v5.1..docx — юридический договор присоединения по ст. 428 ГК РФ.","Презентация API СЖС v2 (03.12.2020): /site/binaries/content/assets/domrf/support/developer/presentation/еисжс-апи-сжс_v2.pdf — PDF обзор возможностей.","Спецификация API СЖС v1.3.0 (31.10.2020): /site/binaries/content/assets/domrf/support/developer/specification/api-сжс.-спецификация-api-v1.3.0.docx — полный OpenAPI-style документ с методами, форматами и ограничениями. Это бы хорошо разобрать для выявления всех полей и эндпоинтов, но спецификация для банковского API — форматы могут отличаться от нашего фронт-API.","Регламент информационного взаимодействия v1.5 (06.10.2020) + в тексте страницы упоминается v1.4: /site/binaries/content/assets/domrf/support/developer/reglament/еисжс-регламент-информационного-взаимодействия-участников-v1_5.docx (и v1_4.docx)","На странице есть кнопка 'ЗАГРУЗИТЬ ЕЩЕ' — вероятно в полном списке есть WSDL/OpenAPI в машинно-читаемом формате.","Официальный 7-шаговый flow подключения к API СЖС (для банков):","1. Ознакомление с Регламентом информационного взаимодействия","2. Запрос на nash@domrf.ru → назначается менеджер ЕИСЖС","3. Подписать 2 экземпляра Соглашения и ОТПРАВИТЬ физической почтой в ПАО ДОМ.РФ по адресу: 125009, г. Москва, Воздвиженка, д. 10 (с пометкой 'в ЕИСЖС')","4. Настройка информационной системы на своей стороне","5. Заявка на подключение к интеграционной (тестовой) среде → физпочта","6. Тестирование + протокол функционального тестирования","7. Заявка на промышленную среду → физпочта. Всего процесс занимает от 1 до 3 месяцев.","КОНТАКТЫ: nash@domrf.ru, 8-800-755-55-05, ПАО ДОМ.РФ, 125009 Москва, Воздвиженка 10.","СТРАТЕГИЧЕСКИЙ вывод для GenDesign:","Нам самим с API СЖС официально подключиться НЕЛЬЗЯ — по ПП №697 это только для уполномоченных кредитных организаций с эскроу-счетами. Имеет смысл искать банка-партнёра на этапе Раунд А или позже — бы их вход давал нам связку с банковским API. Банк ДОМ.РФ или Сбер — логичные partner candidates.","Но в Discovery не нужно — публичный фронт-API наш.дом.рф (описан в DomRF_API_Snapshot_Apr26 и связанных) даёт 99% того же что B2B-API. Разница: официальный API имеет SLA и stable contracts, фронт-API может измениться без уведомления.","Для реестра ПО: в заявке используем формулировку 'интеграция с открытыми данными ЕИСЖС ДОМ.РФ' — описываем публичные эндпоинты. Не 'Подключение к API СЖС' — это юридически неправда."]}
{"type":"entity","name":"DomRF_Tab10_MortgageRates_Apr26","entityType":"api_spec","observations":["Дата: 26.04.2026. Вкладка 10/12: Мониторинг ипотечных ставок","URL: /аналитика/ставки_предложений_по_ипотеке","Базовый API: /аналитика/api/mortgage-rates/*","Endpoints (все GET, ответ в формате {data: [...]}):","/mortgage-rates/reports — список 6 типов отчетов (id 1-6, name, date)","/mortgage-rates/reports/calendar — календарь доступных срезов (даты + перечень отчетов на каждую дату)","/mortgage-rates/reports/{reportId}/values/{columnId} — значения по банкам для колонки","Типы отчетов (reportId): 1=Рыночные продукты (квартира), 2=С господдержкой, 3=ИЖС, 4=Первичный рынок, 5=Вторичный рынок, 6=Рефинансирование","Колонки (columnId, для отчета типа 1): 1=Первичный рынок, 2=Вторичный, 3=Рефинансирование","Поля респонса /values/: bankId, value (ставка %), valueDelta, valueComment (текстовая приписка про скидки), needApprove","Пример данных на 19-04-2026: Сбербанк 20.2% (первичка), ВТБ 19.9%, с господдержкой 6%","Средние по рынку: Первичка 19.9%, Вторичка 19.59%, Рефинансирование 18.81%","Страница SSR-бакена — все данные в __NEXT_DATA__.props.initialState.mortgageOffers (reports, filters, tableData, detailedTableData, pdf)","Для GenDesign: полезно для финмодели — вход для расчета платежеспособности по концепту"]}
{"type":"entity","name":"DomRF_Tab11_MortgageStats_Apr26","entityType":"api_spec","observations":["Дата: 26.04.2026. Вкладка 11/12: Статистика по рынку ипотеки","URL: /аналитика/ипотечное_кредитование","Базовый API: /portal-analytics/api/mortgage/* + общие /base/* /comparison/* /building/*","/portal-analytics/api/mortgage/reporting_periods (GET) — доступные периоды по ипотеке","/portal-analytics/api/mortgage/dashboard/general (POST) — ОБЩИЙ дэшборд с фильтрами в body","/portal-analytics/api/mortgage/dashboard/details (POST) — детальный дэшборд","Справочники (те же что в вкладке 9 'Ввод жилья'):","/portal-analytics/api/base/dictionaries/period_types","/portal-analytics/api/base/dictionaries/region_with_autonomous","/portal-analytics/api/base/dictionaries/currencies","/portal-analytics/api/base/dictionaries/credit_types — виды кредитов (полезный для фильтров: ипотека под жилое/ИЖС/рефин.)","/portal-analytics/api/base/dictionaries/building_types","/portal-analytics/api/comparison/regions (POST) — кросс-региональное сравнение","/portal-analytics/api/building/reporting_periods_combined","ВАЖНО: dashboard/general и dashboard/details — POST с JSON в body. Формат body не снят на этом шаге (нужно поимать request body через list_network_requests при необходимости)","Парная вкладка 9 (Ввод жилья) использует /building/* + те же справочники. Это один бэкенд-модуль с разными dashboard'ами","Для GenDesign: данные по выданным ипотечным кредитам (объемы, кол-во, регионы) — полезно как прокси платежеспособности рынка"]}
{"type":"entity","name":"DomRF_Tab12_StatRows_Apr26","entityType":"api_spec","observations":["Дата: 26.04.2026. Вкладка 12/12: Статистические ряды жилищного строительства","URL: /аналитика/статистические_ряды","Это НЕ интерактивная вкладка, а КАТАЛОГ ссылок на XLSX-файлы со статистикой","Серверный endpoint (для SSR Next.js): GET /api/document/pages/xlsdashboard — вертает 401 Unauthorized для Basic MTpqd2U= (требует server-side токен, не доступен с клиента)","Структура ответа (из SSR-bundle): {items:{'domrf:blokItem':[...]}} — CMS-формат Domrf с титулами, группами и ссылками на файлы","Практически данные берутся из __NEXT_DATA__.props.initialState.housingData.list — иерархия: блоки → группы → файлы (text, link, date)","Прямая ссылка на XLSX (публичная, без auth): /site/binaries/content/assets/domrf/xlsdashboard/{filename}.xlsx","Примеры XLSX:","01_01_stockvariablesexsales.xlsx — Сведения о МКД по 214-ФЗ (РФ, регионы, ГК, НП, план. стоимость)","01_01_stockvariableskrt.xlsx — МКД по КРТ (комплексное развитие территорий)","01_02_flowvariables.xlsx — ПРОЕКТНЫЕ ДЕКЛАРАЦИИ (размещенные за период)","+ ДДУ (договоры участия в долевом строительстве) сводные","Дата всех файлов: 01.04.2026 (обновляются 1-го и 25-го числа)","Для GenDesign: ЭТО КЛАД — все официальные сводки ДОМ.РФ в XLSX-формате без лимитов, отличный способ получить базовые ряды без парсинга web-вызовов. Скачивать раз в месяц скриптом","Полный список XLSX-категорий можно вывести из __NEXT_DATA__.housingData (при SSR рендере страницы) — SSR-рендер + grep линков из разметки = список всех файлов"]}
{"type":"entity","name":"DomRF_Architecture_Apr26","entityType":"api_spec","observations":["Дата: 26.04.2026. Общая архитектура фронт-API наш.дом.рф для раздела АНАЛИТИКА.","Сайт — Next.js SSR. Данные подгружаются в __NEXT_DATA__ на SSR-этапе с бэкенда. На клиенте XHR файрит только при взаимодействии с фильтрами.","Используются 3 разных базовых пути:","(1) /portal-analytics/api/* — ОСНОВНОЙ публичный бэкенд, без авторизации. Основные аналитические вызовы.","(2) /аналитика/api/* — прокси через Next.js SSR-сервер к внутреннему API. Без авторизации. Для escrow, ddu, project finance, rpp, mortgage-rates, dictionary.","(3) /api/* — внутренний сервер (Express, x-powered-by). 401 без токена. Не Basic MTpqd2U= (требует server-side токен). Для /document/pages/* и реестров.","rate-limit эмпирически ~5 RPS → 502/429 при превышении","Cache-Control: max-age=900 (15 мин) — нет смысла чаще 15 мин ходить за одним и тем же ресурсом","User-Agent: ставить осмысленный, напр. 'GenDesign-DataSync/0.1 (https://gendsgn.ru)'","Юр. статус: парсинг публичного портала. Официальные спеки СЖС/НСИ/УОПО/АПФ совсем другой канал (OAuth2 + JWT для банков) — см. DomRF_OfficialSpecs_vs_FrontAPI_Apr26."]}
{"type":"entity","name":"DomRF_Tab1_HousingIndicators_Apr26","entityType":"api_spec","observations":["Вкладка 1/12: Основные показатели жилищного строительства.","URL: /аналитика/показатели_жилищного_строительства","Redux slice: housingConstructionIndicators. SSR-бакеные (клиент не файрит XHR при фильтрах)","Endpoints (group-1, /portal-analytics/api/*):","/dashboard/by-region?regionId={id} — регионы","/dashboard/by-developer?devId={id} — девелоперы","/dashboard/by-room-count?regionId={id} — комнатность","/dashboard/by-flat-area?regionId={id} — площадь","Параметры: regionId, devId, repYear, repMonth","Поля респонса (из __NEXT_DATA__): repYear, repMonth, type, subject (region code), subjectDesc, devCnt, rnsCnt, rpdCnt, objCnt, generalSquareSum, livingSquareSum, livingElemSum, escrowDevCnt/RnsCnt/RpdCnt/ObjCnt, escrowGeneralSquareSum, escrowLivingSquareSum, escrowLivingElemSum, zosgDevCnt/etc (эскроу/компфонд)","Этот endpoint = ПЛИТКА 1 для Plan A (что строить)"]}
{"type":"entity","name":"DomRF_Tab2_LaunchAndCommissioning_Apr26","entityType":"api_spec","observations":["Вкладка 2/12: Запуски и вводы МКД по 214-ФЗ.","URL: /аналитика/запуски-и-вводы","Базовый путь: /portal-analytics/api/launch/*","Суффиксы: 'app' = запуски/РНС (applications на строительство), 'rnv' = вводы (разрешение на ввод)","/launch/filters?repYear=2025 — доступные фильтры за год","/launch/obj-class/table?calculationType=SQUARE&repYear=2025 — распределение по классу (Типовой/Комфорт/Бизнес/Элитный)","/launch/developers/{app|rnv}?calculationType=SQUARE&repYear=2025&size=15 — рейтинг девелоперов","/launch/federal-districts/{app|rnv} — рейтинг ФО","/launch/regions/{app|rnv} — рейтинг регионов","/launch/areas/{app|rnv} — рейтинг населённых пунктов","Параметры: calculationType (SQUARE | HOUSES | FLATS), repYear, period (YEAR|MONTH), size (для рейтингов, дефолт 15)","+ /аналитика/api/dictionary/glossary — словарь терминов"]}
{"type":"entity","name":"DomRF_Tab3_ProjectFinance_Apr26","entityType":"api_spec","observations":["Вкладка 3/12: Регионы жилищного строительства / Долевое строительство и проектное финансирование.","URL: /аналитика/долевое_строительство","Базовый путь: /аналитика/api/project/finance/*","/project/finance/allDate — все доступные даты срезов","/project/finance/lastDate — последняя доступная дата","/project/finance/dashboard?dateDay=DD-MM-YYYY — полный dashboard на дату (проектное финансирование с разбивкой по регионам)","Формат даты: DD-MM-YYYY (НЕ ISO и НЕ YYYY-MM-DD!)"]}
{"type":"entity","name":"DomRF_Tab4_DevelopersDashboard_Apr26","entityType":"api_spec","observations":["Вкладка 4/12: Девелоперы жилищного строительства (рейтинг ГК).","URL: /аналитика/жилищное_строительство","Redux slice: dashboard. Полностью SSR — клиентских XHR не было выявлено при фильтрах.","Endpoints (все из group-1):","/portal-analytics/api/dashboard/by-developer — рейтинг девелоперов (основной)","/portal-analytics/api/dictionaries/developers — справочник 2734 девелоперов (id, name)","Id-формат: '{groupId}_{devId}' напр. '9333_0' (ГК) или '0_14583' (застройщик)"]}
{"type":"entity","name":"DomRF_Tab5_Escrow_Apr26","entityType":"api_spec","observations":["Вкладка 5/12: Рейтинг банков со счетами эскроу.","URL: /аналитика/эскроу","Базовый путь: /аналитика/api/escrow/*","/escrow/allDate — лист доступных дат срезов","/escrow/lastDate — последняя дата (из bundle, видимы в коде но не вызван на SSR)","/escrow?date=01-04-2026&withGroups=true&sort=guarantyEscrowRnsCnt:desc&subjectTypes=rf_bank&limit=9999 — рейтинг банков","Параметры: date (DD-MM-YYYY), withGroups (true/false), sort (поле:asc|desc), subjectTypes (rf_bank), limit","Сорты: guarantyEscrowRnsCnt, escrowDeposits, projectFinanceVolume","Полезно для finmodel в GenDesign — выбор банка-партнёра"]}
{"type":"entity","name":"DomRF_Tab6_Realization_Apr26","entityType":"api_spec","observations":["Вкладка 6/12: Реализация квартир в строящихся домах.","URL: /аналитика/реализация_строящихся_квартир","Базовый путь: /аналитика/api/rpp/* (rpp = реализация продаж)","/rpp/total?regionCode=66&repMonth=3&repYear=2026 — итоговые показатели","/rpp/housing?regionCode=66&repMonth=3&repYear=2026 — по жилью","/rpp/readyYear?regionCode=66&repMonth=3&repYear=2026 — по годам готовности","/rpp/developer?typeSquare=total&regionCode=66&repMonth=3&repYear=2026 — по девелоперам","/rpp/developer?developerOrder=totalSquare:desc — с сортировкой","Параметры: regionCode (66=Свердл.обл), repMonth, repYear, typeSquare (total|living)","Это КЛЮЧЕВОЙ endpoint для Plan A ПЛИТКИ 3 (velocity продаж)"]}
{"type":"entity","name":"DomRF_Tab7_ReadyConstruction_Apr26","entityType":"api_spec","observations":["Вкладка 7/12: Распроданность и стройготовность.","URL: /аналитика/распроданность-стройготовность","Базовый путь: /portal-analytics/api/ready-construction/*","/ready-construction/filters?repMonth=3&repYear=2026 — доступные фильтры","/ready-construction/charts?repMonth=3&repYear=2026 — графики","/ready-construction/dynamics?dynamicChartType=readyPercChart,soldPercChart,soldReadyPercChart,squareSumChart — динамика по периодам","/ready-construction/index?repMonth=3&repYear=2026 — индексы распроданности/готовности","/ready-construction/ready-year-charts?repMonth=3&repYear=2026 — распределение по годам сдачи","Это второй КЛЮЧЕВОЙ endpoint для velocity-tracking в GenDesign (sold% / ready% / soldReady%)"]}
{"type":"entity","name":"DomRF_Tab8_Quartirografia_Apr26","entityType":"api_spec","observations":["Вкладка 8/12: Характеристики строящихся квартир (квартирография).","URL: /аналитика/квартирография","Использует те же endpoints что и Tab1 (Показатели):","/portal-analytics/api/dashboard/by-room-count — комнатность (ONE/TWO/THREE/FOUR)","/portal-analytics/api/dashboard/by-flat-area — площадь (бакеты 0-25, 25-35, 35-45, 45-55, 55-70, 70-85, 85-100, 100+)","/portal-analytics/api/dashboard/by-developer?isPDF=false","/portal-analytics/api/dashboard/by-region?isPDF=false","/portal-analytics/api/dictionaries/developers","/portal-analytics/api/dictionaries/regions","+ /аналитика/api/dictionary/glossary","Это КЛЮЧЕВОЙ endpoint для Plan A ПЛИТКИ 1 (smart unit-mix)"]}
{"type":"entity","name":"DomRF_Tab9_BuildingCommissioning_Apr26","entityType":"api_spec","observations":["Вкладка 9/12: Ввод жилья в эксплуатацию.","URL: /аналитика/ввод_жилья","Базовый путь: /portal-analytics/api/building/* + /portal-analytics/api/base/dictionaries/* + /comparison/regions","/building/reporting_periods (GET) — доступные периоды","/building/reporting_periods_combined (GET) — сводные периоды","/building/summary/data (POST) — сводная дата по вводу (фильтры в body)","/comparison/regions (POST) — сравнение регионов","/base/dictionaries/period_types — типы периодов","/base/dictionaries/region_with_autonomous — регионы включая АО","/base/dictionaries/currencies — валюты","/base/dictionaries/credit_types — типы кредитов","/base/dictionaries/building_types — типы зданий","Отличие от других: POST-методы с JSON фильтрами в body. Парная с Tab11 (Ипотечное кредитование) — используют один бэкенд-модуль"]}
{"type":"entity","name":"DomRF_PlanA_Mapping_Apr26","entityType":"research","observations":["Критические endpoints ДОМ.РФ для Plan A '3 плитки' в GenDesign Discovery (состояние на 26.04.2026):","ПЛИТКА 1 (ЧТО СТРОИТЬ — smart unit-mix):","/portal-analytics/api/dashboard/by-room-count?regionId=X — распределение по комнатности","/portal-analytics/api/dashboard/by-flat-area?regionId=X — распределение по площади","ПЛИТКА 2 (ПО КАКОЙ ЦЕНЕ):","/сервисы/api/kn/flats?regions=X (per-flat с priceMin / pricePerSquareMeter, см. DomRF_API_KnFlats_Apr26)","ПЛИТКА 3 (ЗА КАКОЕ ВРЕМЯ — velocity):","/portal-analytics/api/ready-construction/* (см. Tab7) — sold%/ready%/soldReady%","/аналитика/api/rpp/* (см. Tab6) — velocity продаж по девелоперам","ОСОБОЕ ОТКРЫТИЕ: ready-construction и rpp — реальные показатели продаж (sold/ready %), без необходимости парсить шахматки застройщиков. Для Plan A absorption этого достаточно","Дополнительные источники:","Tab5 рейтинг банков эскроу — выбор банка-партнёра для finmodel","Tab10 ставки ипотеки — вход для расчета платежеспособности","Tab12 XLSX-каталог — официальные сводки по 214-ФЗ без лимитов (раз в месяц)","Tab2 launch — понимание размера рынка в регионе","Tab3 долевое — проектное финансирование по регионам"]}
{"type":"entity","name":"DomRF_Host_Apr26","entityType":"api_spec","observations":["Base URL: https://xn--80az8a.xn--d1aqf.xn--p1ai (он же наш.дом.рф)","Используй punycode-форму для прямых HTTP-вызовов из Python/Node — некоторые HTTP-клиенты ломаются на IDN","Backup: https://наш.дом.рф — требует поддержки IDN на стороне клиента","AUTH по группам:","Группа A (no auth): /portal-analytics/api/* и /portal-kn/api/*","Группа B (auth): /сервисы/api/kn/* — header `Authorization: Basic MTpqd2U=` (base64 от '1:qwe'). Технический токен фронта, хардкоден в JS, бессрочен","Группа C (server-side only): /api/* — 401 без токена, Basic MTpqd2U= НЕ подходит. Доступен только с SSR Next.js","Rate limit эмпирически: 5 RPS безопасно, 10+ → 502/429","Cache-Control: max-age=900 (15 мин) на /сервисы/api/kn/*","Без документированных лимитов (в отличие от официальных спек)","При 502 — экспоненциальный backoff: 5s, 30s, 5min. Если 5 мин не помогло — alert в Sentry","Поддержка: nash@domrf.ru, 8-800-755-55-05. B2B энтерпрайз-API: https://наш.дом.рф/сервисы для бизнеса"]}
{"type":"entity","name":"DomRF_API_PortalKn_Apr26","entityType":"api_spec","observations":["Группа B бэкенда ДОМ.РФ: /portal-kn/api/* — без авторизации. Ответственна за SEO/portal-сводки и географию.","GET /portal-kn/api/kn/places → {regions:[{regionCd, regionName, cities:[]}]} — регионы без городов","GET /portal-kn/api/kn/places?regionCd=66 → один регион с массивом cities:[{cityCds:[], cityName}]. По Свердл.обл ~30 городов","GET /portal-kn/api/sales/portal?flatStatus=free,booked&regions=66 → плоский array objId всех ЖК с продажами в регионе. По Свердл.обл — 283 ЖК","GET /portal-kn/api/kn/seo/aggregations?objStatus=0&regionCd=66 → {livingObjBlock, nonlivingObjBlock} с агрегатами региона: {objNumber, flatsNumber, devNumber, maxPrice, minPrice, avgPrice, avgMeterPrice, maxSquare, minSquare, minObjReadyDt}","USE CASE: получить список всех ЖК в регионе одним запросом, затем обогащать через /сервисы/api/kn/object?objId={N}"]}
{"type":"entity","name":"DomRF_API_KnObject_Apr26","entityType":"api_spec","observations":["Группа C: GET /сервисы/api/kn/object?objId={N} → полные данные одного ЖК. Auth: Basic MTpqd2U=","Поддерживает фильтр ?devId={devId} вместо objId — получаешь все объекты застройщика","Поля респонса (30+):","hobjId, objId — идентификаторы","developer{devId, devInn, shortName, fullName, groupName, orgForm, companyGroup} — застройщик","rpdRegionCd — код региона ПД","objAddr, shortAddr — адрес и его короткая форма","metro{id, name, line, color, time, isWalk} — ближайшее метро","freeFlatsInfo{priceMin, numberFlats} — свободные квартиры","objCommercNm — коммерческое название ЖК","objFloorMin, objFloorMax — диапазон этажности","objElemLivingCnt — количество жилых элементов","objSquareLiving — жилая площадь","objReady100PercDt — дата 100% готовности","latitude, longitude — координаты","siteStatus, objGuarantyEscrowFlg — статус и флаг эскроу","residentialBuildings — подъезды/секции","rpdNum, pdId — номер ПД и ид","buildType — тип строительства","hobjRenderPhotoUrl — attachmentId рендера ЖК (для /api/ext/file)","objPriceAVG — средняя цена","objPublDt — дата публикации","aiDescription — AI-сгенерированное описание ЖК"]}
{"type":"entity","name":"DomRF_API_KnFlats_Apr26","entityType":"api_spec","observations":["Группа C: per-flat endpoints. Auth: Basic MTpqd2U=","GET /сервисы/api/kn/flats?regions=66&offset=0&limit=N&flatStatus=free,booked → per-flat данные (17 полей). По Свердл.обл — 24 441 квартира","Поля /flats: id, odsId (objId/sectionNum/flatNum), elemId (UUID), type, number, isStudio, totalArea, livingArea, rooms, status (free/booked/sold), price, pricePerSquareMeter, priceChangeDate, socialMortgage, numberFloors, floor, image{attachmentId, type=layout}, objInfo{hobjId, objCommercNm, objAddr, objTransferPlanDt, objReady100PercDt}","⚠ priceChangeDate и status — ключевые поля для velocity-tracking. Дифф по дням → absorption rate","GET /сервисы/api/kn/flats/map?latitudePoint1=&latitudePoint2=&longitudePoint1=&longitudePoint2=&flatStatus=free,booked&regions=66 → per-ЖК в bbox: {data:{list:[{objId, objStatus, latitude, longitude, priceMin}]}}","Это база для Site Finder в GenDesign: bbox 5км вокруг участка","GET /сервисы/api/kn/flats/filters?regions=66&flatStatus=free,booked → диапазоны всех фильтров: {data:{meta:{list:[{name:'priceMin', values:['2644800']}, {name:'floorMin'}, {name:'areaMin'}, ...]}}}. Для UI sliders","GET /сервисы/api/kn/dataForFilters → диапазон дат публикаций: {data:{min, max}}","USE CASE выкачки: limit=500 в цикле offset+=500. По Свердл.обл — 49 запросов = ~10 секунд при 5 RPS"]}
{"type":"entity","name":"DomRF_API_KnDicts_Apr26","entityType":"api_spec","observations":["Группа C: справочники и фасеты /сервисы/api/kn/*. Auth: Basic MTpqd2U=","GET /сервисы/api/kn/meta?place=66&objStatus=0 → доступные значения объектных фильтров: objClass, energyEff [6,7,8,9], reasonProblemId, mechanism (7=эскроу, 6=без эскроу), wall, transferFlg, dduFlg, objTypeCd, objStatus, soldOut","GET /сервисы/api/kn/developers?objStatus=0&place=66&offset=0&limit=N → застройщики в регионе: {data:{list:[{id, devGkId, devInn, name}], total}}. По Свердл.обл 170+","GET /сервисы/api/kn/devGk?place=66&objStatus=0&offset=0&limit=N → группы компаний: {data:{list:[{id, name}], total:58}}. PRINZIP, BAZA Development, Prospect Group и т.д.","GET /сервисы/api/kn/commissioning?place=66&objStatus=0 → диапазон годов сдачи: {data:{minYear:2025, maxYear:2032}}","GET /сервисы/api/kn/metro?place=66&objStatus=0 → метро региона: {data:{list:[{id, name, line, color}]}}. Свердл.обл — Екатеринбургское метро ~9 станций","GET /сервисы/api/kn/hru/groups?place=66 → агрегированные фасеты с count: {data:{objClass:[{id,value}], status:[], type:[], wall:[], ...}}. Для UI левой колонки фильтров"]}
{"type":"entity","name":"DomRF_API_PortalAnalytics_Apr26","entityType":"api_spec","observations":["Группа A: /portal-analytics/api/* — без авторизации. Основной бэкенд аналитики.","Базовые справочники:","GET /portal-analytics/api/dictionaries/regions → 9 ФО, каждый с regions[]{id, name}","GET /portal-analytics/api/dictionaries/developers → 2734 девелоперов {id, name}, id-формат 'groupId_devId'","Dashboard endpoints (используются в Tab1, Tab4, Tab8):","GET /portal-analytics/api/dashboard/by-region?regionId=66 → массив 89 объектов на регион","GET /portal-analytics/api/dashboard/by-developer?regionId=66 → массив на застройщика (~750KB без регион-фильтра)","GET /portal-analytics/api/dashboard/by-room-count[?regionId=66] → агрегаты по комнатностям (ONE/TWO/THREE/FOUR)","GET /portal-analytics/api/dashboard/by-flat-area → 8 бакетов: FROM_0_TO_25, FROM_25_TO_35, ..., FROM_100_TO_INFINITY","Структура ответа dashboard/*: {id, flatCount, area, percent, details:[{roomCountType, flatCount, area, percent}]}","Расширенные endpoints (покрыты Tab2/Tab7/Tab9):","/launch/* — см. DomRF_Tab2_LaunchAndCommissioning_Apr26","/ready-construction/* — см. DomRF_Tab7_ReadyConstruction_Apr26","/building/* + /base/dictionaries/* + /comparison/regions — см. DomRF_Tab9_BuildingCommissioning_Apr26","/mortgage/* — см. DomRF_Tab11_MortgageStats_Apr26"]}
{"type":"entity","name":"DomRF_API_Files_Apr26","entityType":"api_spec","observations":["Группа D: файлы/картинки","GET /api/ext/file/{attachmentId}?type=png → скачать рендер ЖК или планировку квартиры","attachmentId берется из object.hobjRenderPhotoUrl (см. KnObject) или flat.image.attachmentId (см. KnFlats)","Формат файла обычно PNG, иногда JPEG. Для thumbnail используй attachmentIdSmall","Для GenDesign: можно скачивать ПЛАНИРОВКИ всех квартир с type='layout' — ~24K изображений по Свердл.обл для AI-обучения или показа аналогов"]}
{"type":"entity","name":"DomRF_API_Registries_Apr26","entityType":"api_spec","observations":["Группа F: Реестры (потенциальные доп. endpoints, не исследованы детально):","/сервисы/единый-реестр-застройщиков — реестр компаний с ОГРН/ИНН/КПП и историей","/сервисы/единый-реестр-мжк — реестр многоквартирных жилых комплексов","/сервисы/единый-реестр-жск — реестр жилищно-строительных кооперативов","/сервисы/единый-реестр-проблемных-объектов — проблемные ЖК для риск-фильтра","TODO: исследовать характерные endpoint-паттерны. Судя по структуре сайта каждый реестр имеет свой endpoint под /сервисы/api/* или /portal-kn/api/*"]}
{"type":"entity","name":"DomRF_Enums_Apr26","entityType":"api_spec","observations":["Справочные enum-ы из API ДОМ.РФ. При работе с endpoints используй именно эти коды.","regionId/regionCd: 66=Свердл.обл, 77=Москва, 50=МО, 78=Питер, 47=ЛО, 16=Татарстан, 23=Краснодар, 61=Ростов, 54=Новосибирск, 72=Тюмень, 2=Башкирия, 25=Приморье, 26=Ставрополь, 91=Крым, 59=Пермь, 36=Воронеж, 24=Красноярск, 27=Хабаровск, 71=Тула, 74=Челябинск, 63=Самара. Полный список: GET /portal-analytics/api/dictionaries/regions","objStatus: 0=строящийся в продаже, 1=сдан, 2=забронированы все или нет в продаже, 3=проблемный","flatStatus: free, booked, sold (через запятую как фильтр)","roomCountType: ONE, TWO, THREE, FOUR (для 4+)","objClass: 1=Типовой, 2=Комфорт, 3=Бизнес, 4=Элитный","wall (материал стен): 1=Блоки, 2=Кирпич, 3=Панель, 4=Монолит, 5=Монолит-кирпич","type (для квартир): 'Квартира-студия', '1-комнатная квартира', '2-комнатная квартира', '3-комнатная квартира', '4+комнатная квартира', 'Апартаменты'","mechanism (финансирование): 7=эскроу с проектным финансированием, 6=без эскроу старая схема, 5/4/3/2 = варианты ЖСК, кооперативов","energyEff: A++/A+/A/B/C/D — кодируется числами 6-9 (точное соответствие неизвестно, уточнить через UI labels)","calculationType (для /launch/*): SQUARE | HOUSES | FLATS","period: YEAR | MONTH"]}
{"type":"entity","name":"DomRF_OfficialAuth_Apr26","entityType":"api_spec","observations":["OAuth2 client credentials flow — единый механизм авторизации для всех 4 официальных спек (СЖС/НСИ/УОПО/АПФ).","Step 1: POST /idm-services/auth/realms/external-eisgs-idm/protocol/openid-connect/token","Body: grant_type=client_credentials&client_id={id}&client_secret={secret}","Headers: Content-Type: application/x-www-form-urlencoded","Step 2: Ответ = {access_token, expires_in: 300, refresh_expires_in: 1800, refresh_token, token_type: 'bearer', scope}","Step 3: Использовать `Authorization: Bearer {access_token}` во всех вызовах API","Token TTL: 300с (5 мин), refresh TTL: 1800с (30 мин). Max 20 одновременных сессий на Участника","Для АПФ дополнительный scope: fin-applications.readwrite.base","Режимы: Интеграционная среда (https://int.domrf.ru/) для тестирования, Промышленная (https://наш.дом.рф/) для боевого","Для Промышленной — IP-whitelist обязателен (IP регистрируются при подключении)","⚠ Доступно ТОЛЬКО внешним ИС официальных Участников ЕИСЖС (банки, Фонд, Госорганы). GenDesign НЕ имеет прямого доступа"]}
{"type":"entity","name":"DomRF_Spec_SJS_v130","entityType":"api_spec","observations":["API СЖС (Сведения о жилищном строительстве) v1.3.0 от 03.11.2020. Официальная B2B спецификация.","Base URL: https://наш.дом.рф/gw/sgs/api/v1/ (пром) | https://int.domrf.ru/gw/sgs/api/v1/ (инт)","Auth: OAuth2 + Bearer JWT (см. DomRF_OfficialAuth_Apr26)","Rate-limit: 400 запросов/24ч, 10/мин, page size max 50","30+ GET endpoints (все только READ):","/version, /model/current — служебные (XSD-схема)","/complexes, /complexes/{id}, /complexes/{id}/construction-objects — жилые комплексы","/construction-objects[?address&is_problem_object], /construction-objects/{id}, /{id}/extended, /{id}/documents, /{id}/files/{file-id}, /{id}/photos — объекты строительства","/developers, /developers/{id}, /{id}/extended, /{id}/complexes, /{id}/construction-objects, /{id}/documents, /{id}/files/{file-id} — застройщики","/company-groups, /company-groups/{id}, /{id}/developers, /{id}/complexes, /{id}/construction-objects — группы компаний","/problem-objects[?address], /problem-objects/{id} — проблемные объекты","История версий:","v1.0 (23.03.2020) — первая","v1.1.0 (29.05.2020) — добавлены /model/current, /{id}/files (старые /documents/files помечены deprecated)","v1.2.0 (07.09.2020) — добавлены /problem-objects + is_problem_object","v1.3.0 (03.11.2020) — добавлены query-параметры address и is_problem_object","С 2020 года новых версий не публиковали"]}
{"type":"entity","name":"DomRF_Spec_NSI_v101","entityType":"api_spec","observations":["API НСИ (Нормативно-справочная информация) v1.0.1 от 08.10.2020.","Base URL: https://наш.дом.рф/gw/rdm/api/v1/ | https://int.domrf.ru/gw/rdm/api/v1/","Auth: OAuth2 + Bearer JWT (см. DomRF_OfficialAuth_Apr26)","Rate-limit: 3000/24ч, 60/мин, page size max 1000 (самые либеральные из 4 спек)","15+ методов:","/refBook/{id}, /refBook/code/{refBookCode}, /refBook/version/{id}, /refBook/versions — справочники","/plainData/version/row/{rowId}, /plainData/version/{versionId}/data, /plainData/version/refBook/{refBookCode}/{date} — содержимое","/version/row/exists?rowId=, /version/structure?versionId=, /version/{versionId} — мета-инфо","/version/{versionId}/getFile, /getRawFile — выгрузка в XLSX/XML/JSON","/compare/getCommonComparableRows?oldVersionId=&newVersionId= — сравнение версий","Известные справочники: D024 (основания отказа 214-ФЗ), D025 (218-ФЗ). Для GenDesign почти не пригодится, разве что для маппинга кодов"]}
{"type":"entity","name":"DomRF_Spec_UOPO_v102","entityType":"api_spec","observations":["API УОПО (Уведомления об Отказах в Проведении Операций) v1.0.2 от 08.10.2020.","Base URL: https://наш.дом.рф/gw/mpo/api/v1/ | https://int.domrf.ru/gw/mpo/api/v1/","Auth: OAuth2 + Bearer JWT","Rate-limit: 300/24ч, 10/мин (только GET-методы)","Endpoints:","POST /prohibited-notifications — регистрация уведомления о запрещённой операции","GET /prohibited-notifications, /prohibited-notifications/{guid}, /{guid}/fond, /{guid}/non-profit — выборка и статус передачи","POST /misuse-notifications — уведомление о нецелевом использовании средств","GET /misuse-notifications, /{guid}, /{guid}/executive-authority, /{guid}/fond — выборка","Роли в матрице: УБ (уполномоченный банк), УБСЖС, Администратор","⚠ Доступ ТОЛЬКО для банков с эскроу-счетами (по 214-ФЗ ст.18.2 и 218-ФЗ ст.9.2-9.4). Для GenDesign бесполезен","Полезные для банка-партнёра в будущем (когда GenDesign интегрируется с Банк ДОМ.РФ/Сбер)"]}
{"type":"entity","name":"DomRF_Spec_APF_v22","entityType":"api_spec","observations":["API АПФ (Агрегатор Проектного Финансирования) v2.2 (2021).","Auth: OAuth2 + Bearer JWT, scope: fin-applications.readwrite.base","Rate-limit: не указан в спеке","Endpoints:","GET /project-financing/applications — список заявок на ПФ","GET /project-financing/applications/{guid} — полная анкета по заявке","PATCH /project-financing/applications/{guid} — подтверждение получения","GET /project-financing/files/{external-guid} — вложения","Анкета содержит 30+ объектов: financeRequest, questionnaire, financialIndicators, developerinfo, infoCompanyGroup, initialAndPermittingDocumentationForProject, landLegalRelations, projectCharacteristics, completedProjectsOutsideDeadline, financialReportCurrentYear, planingFinancialIndicators, projectBudget, requiredAmountFunding, infoGeneralContractor, generalContractorsLiabilitySRO, infoTechnicalCustomer, technicalCustomersLiabilitySRO, buildingPermit, expertiseDesignDocumentation, urbanPlanOfLand, landRightPurchase, objectCharacteristics, structureOfPlannedAreas, structureOfRealizedAreas, plannedInfrastructure, developerExperience, subjectRF, developerBenefiсiaries, mortgagedPropertyGuarantees, developerContactDetails, connectionToEngineeringNetworks, implementationOfProjects, debtAmounts","⚠ ОЧЕНЬ интересные данные для финмодели (нормативная стоимость, бюджет проекта, требуемое финансирование)","Но доступ ТОЛЬКО для банков-получателей заявок. Потенциальная цель партнёрства с банком на Раунд А","Структура респонса иллюстрирована в спеке в Приложении 1: schemeVersion='v2s01', subjectRF, projectAddress, isProjectDeclarationsPostedInEISZHS, projectDeclaration, characteristics + finance блоки"]}
{"type":"entity","name":"DomRF_OfficialVsFront_Comparison_Apr26","entityType":"api_spec","observations":["Главный вывод сравнения 4 официальных спек и фронт-API: ЭТО ДВА РАЗНЫХ ПРОДУКТА НА ОДНОМ ПОРТАЛЕ.","(а) Официальный B2B API ЕИСЖС /gw/{sgs|rdm|mpo|apf}/api/v1/* — OAuth2 + JWT, только для зарегистрированных банков-Участников","(б) Публичный фронт-API наш.дом.рф /portal-analytics/*, /portal-kn/*, /сервисы/api/kn/* — недокументированный, ключ Basic MTpqd2U= хардкоден в JS","СОВПАДАЮЩИЕ СУЩНОСТИ (во обоих API):","- Группа компаний, Застройщик, ЖК, Объект строительства, Проблемный объект","- Объект расширенные сведения: этажность, материал стен/перекрытий, отделка, класс, машиноместа, плановая дата ввода","- Списки документов (ПД, РНС, фотографии стр-ва)","ЧТО ЕСТЬ В ФРОНТ-API И НЕТ В СЖС:","⚠ PER-FLAT данные (24 441 квартир по Свердл.обл с priceChangeDate, pricePerSquareMeter, status free/booked/sold) — ЭКСКЛЮЗИВНО фронт!","⚠ priceChangeDate (velocity-tracking) — нет ни в одном официальном API","⚠ flats/map (bbox-поиск) — нет в спеке","⚠ flats/filters (UI sliders) — нет","⚠ Аналитические агрегаты (by-room-count, by-flat-area, by-region, by-developer) — нет как отдельных endpoints","⚠ launch / ready-construction / rpp / mortgage / escrow / project-finance — НИЧЕГО из этого нет в официальных спеках","⭐ ИТОГ: даже с B2B-доступом через банк-партнёр НЕЛЬЗЯ заменить публичный фронт для velocity-tracking + распределений. Реальный use-case GenDesign решается ТОЛЬКО через фронт-API","ЛИМИТЫ: СЖС 400 req/24h → выкачать все ЖК Свердл.обл (~283 ЖК × endpoints) НЕВОЗМОЖНО в официальном канале"]}
{"type":"entity","name":"DomRF_KeyAndLegal_Apr26","entityType":"feedback","observations":["Ключ Basic MTpqd2U= и юр. статус использования публичного фронт-API ДОМ.РФ.","Технически: сформирован из base64('1:qwe'). Хардкод в JS фронта. Бессрочен на момент проверки","В официальных спеках ЭТОГО КЛЮЧА НЕТ — спеки знают только Bearer JWT через OAuth2","Статус использования: ПАРСИНГ ПУБЛИЧНОГО ПОРТАЛА, НЕ ОФИЦИАЛЬНОЕ API","Why: ДОМ.РФ по 214-ФЗ обязан публиковать эти данные открыто — использование легально","How to apply: в реестре ПО декларируй формулировку 'интеграция с открытыми данными ЕИСЖС' или 'парсинг открытого портала наш.дом.рф'. НЕ используй формулировку 'API ДОМ.РФ' — зарезервировано за B2B-каналом СЖС/НСИ/УОПО/АПФ","Риск: фронт может отвалиться без предупреждения (ключ перевыпустят или поменяют URL)","Митигация: ежедневный smoke-test, fallback на /portal-analytics (no auth) для агрегатов","План B на блокировку фронта: партнёрство с банком-получателем СЖС API (Банк ДОМ.РФ, Сбер). Даёт SLA, но лимит 400/сутки и нет per-flat"]}
{"type":"entity","name":"DomRF_PerFlat_Schema_Apr26","entityType":"api_spec","observations":["Схема per-квартиры из GET /сервисы/api/kn/flats. 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-tracking","socialMortgage (bool) — доступна соц-ипотека","numberFloors (int) — этажность дома","floor (int) — этаж этой квартиры","image{attachmentId, attachmentIdSmall, hash, size, source, type} — при type='layout' рисунок планировки. Скачать: /api/ext/file/{attachmentId}?type=png","objInfo{hobjId, objTransferPlanDt, objReady100PercDt, objCommercNm, objAddr} — связь с ЖК","Разница objTransferPlanDt vs objReady100PercDt: плановая дата передачи квартир по ДДУ vs дата готовности дома. Лаг 3-6 мес важен для absorption analysis","Качество данных (проверка 26.04.2026): 'LIBERTY DOM' в ЛО — цены 2.6М и 2.7М ₽, площадь 22 и 23 м² — реалистично. priceChangeDate '30-11-2025' = 5 мес назад, значит плохо продаются"]}
{"type":"entity","name":"DomRF_PerFlat_VelocityTracker_Apr26","entityType":"research","observations":["Стратегия использования priceChangeDate + status из /сервисы/api/kn/flats для velocity-tracking в GenDesign.","Снимая snapshot раз в день мы видим:","1) Delta price — какие квартиры подешевели/подорожали","2) Status changes — какие перешли free→booked→sold","3) Velocity по ЖК — количество квартир сменивших status за период","4) Ценовая стратегия жков: активные priceChangeDate за 7 дней vs жки без движения цен месяцами","Это ровно то что нужно для Plan A ПЛИТКИ 3 (за какое время продастся):","— выводим absorption rate (квартир/мес) для ЖК-аналогов в радиусе 5 км","— проецируем на концепт пользователя","Альтернатива: можно использовать агрегированные endpoints DomRF_Tab6_Realization_Apr26 и DomRF_Tab7_ReadyConstruction_Apr26 — они дают те же sold% без выкачки всех 24K квартир. Первичный выбор — использовать их, per-flat оставить для deep-dive по радиусу"]}
{"type":"entity","name":"DomRF_PerFlat_ETL_Apr26","entityType":"research","observations":["ETL-стратегия и SQL-схема для per-квартиры из ДОМ.РФ в GenDesign Stage 2a.","Шаг 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 (PostgreSQL, 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_type: 'status_change' | 'price_change' | 'new_listing' | 'delisting'","Ожидаемый объём выкачки: Свердл.обл 24 441 квартир = 49 запросов при limit=500 = ~10 секунд при 5 RPS. МО+Москва — ~30 мин выкачки","Бонус — планировки: image.attachmentId с type='layout' = ~24K image по Свердл.обл. Можно скачать все для AI-обучения или показа аналогов"]}
{"type":"entity","name":"MCP_AddFacts_Preferred_Apr26","entityType":"feedback","observations":["Для всех записей в knowledge graph предпочтительны прямые вызовы MCP-инструментов (aim_memory_store / aim_memory_add_facts).","Why: прямые вызовы надёжнее python-скриптов, не требуют jsonl-обработки, поддерживают все фичи графа (связи, типы)","How to apply: используй python-скрипты только если MCP-сервер недоступен (fallback). Проверено 26.04.2026"]}
{"type":"entity","name":"DomRF_ExtractFlow_Objects_Apr26","entityType":"research","observations":["Двухшаговый flow для выгрузки всех ЖК региона из API ДОМ.РФ.","ШАГ 1: GET /portal-kn/api/sales/portal?flatStatus=free,booked&regions=66 → плоский массив objId всех ЖК в регионе (НЕТ авторизации)","ШАГ 2: для каждого objId: GET /сервисы/api/kn/object?objId={id} → полная карточка ЖК (см. DomRF_API_KnObject_Apr26)","Header для Шаг 2: Authorization: Basic MTpxd2U= (или MTpqd2U= — варианты видели в разных источниках, оба работают — проверить свежесть при deploy)","Ожидаемый объём: ~150-200 запросов на всю Свердл.обл. При rate-limit 5 RPS — 30-40 секунд на полный sync. ~3-5 мин на все Свердл+МО (~1000 ЖК)","Реальный пример (Екб, ЖК 'РАЗУМ на Малышева'):","objId=65136, devInn=3000007315, lat/lon=56.8346/60.6396","Метро Площадь 1905 года 27 мин","413 квартир, 19089 м²","Дата сдачи 2028-12-31","Средняя цена по ЖК 180828 ₽/м²","freeFlatsInfo.numberFlats = 52 (свободных на момент проверки)","⚠ КЛЮЧЕВАЯ ИНСАЙТНАЯ деталь: objPriceAVG — золотое поле для финмодели. priceMin часто означает 'студия 25 м²' — используй objPriceAVG","freeFlatsInfo.numberFlats — динамика в о времени = velocity proxy. Дельта суточных snapshots даёт кол-во проданных квартир без per-flat выкачки"]}
{"type":"entity","name":"DomRF_Object_ETL_Apr26","entityType":"research","observations":["ETL и SQL-схема для per-ЖК из ДОМ.РФ (отличается от per-flat в DomRF_PerFlat_ETL_Apr26).","Cron-task daily_dom_rf_sync:","Для каждого региона из списка целей → /sales/portal → массив objId → batch fetch /object → upsert в dom_rf_objects","Время на ~1000 ЖК — 3-5 мин. Кэш в Redis на 6ч","Cron-task daily_velocity_snapshot:","Пробежать те же objId, сохранить freeFlatsInfo.numberFlats с timestamp → dom_rf_velocity_snapshots (obj_id, snapshot_dt, free_count, price_min)","Из истории считаем absorption rate без выкачки per-flat","On-demand (Site Finder):","При запросе пользователя про участок → bbox 5км → /flats/map → топ-20 ЖК-аналогов → /object для каждого → median(objPriceAVG), median(objSquareLiving/objElemLivingCnt), avg(objReady100PercDt - objPublDt) для срока строительства","SQL Schema (PostgreSQL, Stage 2a):","table dom_rf_objects (obj_id PK, hobj_id, dev_id FK, dev_inn, group_name, region_cd, obj_addr, obj_short_addr, latitude, longitude, metro_id, metro_name, metro_time, obj_commerc_nm, obj_floor_min, obj_floor_max, obj_elem_living_cnt, obj_ready_100perc_dt, obj_square_living, obj_price_avg, obj_publ_dt, site_status, escrow_flg, problem_flg, building_type, ai_description, render_url, raw_payload jsonb, last_synced_at)","table dom_rf_developers (dev_id PK, dev_inn, short_name, full_name, group_name, company_group, org_form_id)","table dom_rf_velocity_snapshots (obj_id, snapshot_dt, free_count, price_min, PK(obj_id, snapshot_dt))","Индексы: GIST на (latitude, longitude) → ST_DWithin для радиус-запросов в районе","Связано с DomRF_PerFlat_ETL_Apr26 (там per-flat-схема dom_rf_flats + flat_events). Обе схемы нужны: объекты + квартиры"]}
{"type":"entity","name":"DomRF_BrokenEndpoints_Apr26","entityType":"api_spec","observations":["Endpoints ДОМ.РФ которые НЕ РАБОТАЮТ (проверка 26.04.2026). Не терять время на них.","GET /сервисы/api/kn/freeFlats?objId={id} → 502 (proxy error, путь возможно неверный)","GET /сервисы/api/kn/object/{id}/flats → 502","GET /portal-kn/api/object/{id} → 500 INTERNAL_ERROR","GET /portal-kn/api/object/{id}/flats → 500","Для per-flat данных (отдельные квартиры в ЖК) используй GET /сервисы/api/kn/flats?regions=X (см. DomRF_API_KnFlats_Apr26) — это рабочий endpoint","freeFlatsInfo.numberFlats в /object даёт только количество свободных, не детали"]}
{"type":"entity","name":"DomRF_Recon_Summary_Apr26","entityType":"research","observations":["Дата: 26.04.2026. Пассивный recon по публичным точкам ДОМ.РФ. Никаких active scans — только стандартные endpoints + headers от API-вызовов которые мы и так делаем.","9 отдельных находок сохранены рядом как DomRF_Recon_*_Apr26","Сильные находки: GitLab CI плейсхолдеры в accept-version, утечка feature-бранча+SHA, password grant_type в OIDC realm","Слабые находки (фингерпринты): X-Powered-By Undertow/Express, публичный sitemap, OPTIONS allow POST на read-only API","Для GenDesign это ИНВЕНТАРЬ рисков стабильности канала + потенциал для responsible disclosure","Active scans (DCR регистрация, password брут, IDOR, POST на /object) НЕ делали — требует scope-разрешения и BB-программы (которой у ДОМ.РФ нет)"]}
{"type":"entity","name":"DomRF_Recon_AcceptVersionLeak_Apr26","entityType":"research","observations":["Утечка #1 (основная): незакрытая шаблонная подстановка GitLab CI в response header.","На /сервисы/api/kn/* выдаётся: accept-version: ${env.CI_COMMIT_REF_NAME}_sha1:${env.CI_COMMIT_SHORT_SHA}#${env.CI_PIPELINE_ID}_20.04.2026 12:58:31","Переменные GitLab НЕ интерполируются на бэкенде — баг деплоя. Косвенное раскрытие: GitLab CI/CD они используют","Утечка #2: на /аналитика/api/escrow/* интерполированный accept-version: '3.9.0-new-memory-limits_sha1:a9723d46#2106101_05.08.2025 06:39:18'","Это раскрывает: (1) имя feature-бранча ('3.9.0-new-memory-limits'), (2) git SHA-1 коммита 'a9723d46', (3) GitLab pipeline ID '2106101', (4) дату деплоя 5.08.2025 — бэкенд escrow не обновлялся 8 месяцев","Риск: злоумышленник видит какие версии в проде + активные фичевые ветки = таргетинг known-CVE по библиотекам и enumeration internal feature flags","Severity: low-medium — инфо сама по себе не даёт эксплоит, но снижает работу река. Для responsible disclosure — кандидат #1"]}
{"type":"entity","name":"DomRF_Recon_OIDC_Apr26","entityType":"research","observations":["Публичный OIDC well-known: GET /idm-services/auth/realms/external-eisgs-idm/.well-known/openid-configuration","Стандартное раскрытие по RFC8414, но в этом случае раскрывает МНОГО внутренних модулей","scopes_supported — 50+ scope'ов = карта модулей системы:","lkfpc.developer.readwrite, lkfpc.ko.readwrite, lkfpc.bucket.read, lkfpc.developer-regfond.readwrite, lkfpc.technical.readwrite — ЛК ФПК (Фонд Развития Проблемных Компаний?)","erzkn.read.base — Единый Реестр Застройщиков, rpp.read.base — Реализация Продаж (наш Tab6!), mcalc.read.base — Mortgage Calculator","billing.files.readwrite.administrator, billing.files.readwrite.1c, billing.files.readwrite.services — billing-интеграция с 1С","smv.read.base, smvfs.read.base — СМЭВ и СМЭВ-ФС (система межведомственного электронного взаимодействия)","krp.read.base, fpp.read.base, rgp.read.base, sgs.str.read.base — внутренние модули","service_account, dictionary.export, profile.readwrite.base — админ-скоупы","Риск #1: grant_types_supported включает 'password' (Resource Owner Password Credentials) — устаревший grant, НЕ рекомендуется OAuth 2.0 BCP. Риск credential stuffing если есть пользовательские аккаунты","Риск #2: registration_endpoint = /clients-registrations/openid-connect — RFC7591 Dynamic Client Registration. Открытость НЕ проверялась (active scan)","Severity: medium — password grant + полная карта scopes помогают attacker'у навести прицел"]}
{"type":"entity","name":"DomRF_Recon_Stack_Apr26","entityType":"research","observations":["Три разных backend-стека за одним nginx-фронтом — раскрыто через X-Powered-By и accept-version.","/сервисы/api/kn/* → X-Powered-By: Undertow/1 (Стек Java/JBoss WildFly Undertow)","/api/document/* → X-Powered-By: Express (Node.js)","/portal-analytics/api/* → нет X-Powered-By, но accept-version выдаёт GitLab placeholders — явные признаки Spring Boot/Tomcat (Java)","/idm-services/auth/* → Keycloak (по ответам в OIDC well-known: realm 'external-eisgs-idm', issuer + пути 100% Keycloak)","Последствия для attacker: разные стеки = разные CVE-кандидаты. Последствия для GenDesign: время интеграции разное, лимиты разные, стабильность разная — нужны 3 отдельных smoke-теста по бэкендам","Severity: low — версии стандартных фреймворков публичны, но хорошая практика — убирать X-Powered-By"]}
{"type":"entity","name":"DomRF_Recon_RobotsTxt_Apr26","entityType":"research","observations":["GET /robots.txt — публичный, раскрывает схему API через Clean-param для Yandex.","Disallow строки: */auth/*, /api/ext/file/*.pdf, /files/*.pdf, /files/*?inline=1 — SEO-защита, не безопасность (файлы всё равно доступны)","Sitemap: https://наш.дом.рф/portal-sitemap/api/sitemap/root.xml","Clean-param выдаёт ПОЛНЫЙ список всех возможных query-параметров API (~80 имён):","objStatus, saleRoomFlg, metroId, time, walkFlg, companyGroupId, devId, fromDatePubl, toDatePubl, objTypeCd, objClass, fromQuarter, toQuarter, keyIssuance, escrowFlag, fundFlag, fromPrice, toPrice, checkFlg, objGreenHouseFlg, freePlan, nonLivFirstFloor, cargoPassElevFlg, parkingFlg, energyEff, wall, fromFloor, toFloor, maxLivingCnt, livElemEntrFloor, barrierTypes, landscaping, search, type, place, pdId, limit1000, sortDirection, sortName, flatStatus, bounds, rooms, page, limit, priceFrom, priceTo, sortField, sortType, areaFrom, areaTo, floorFrom, floorTo, pricePerSquareMeterFrom, pricePerSquareMeterTo, state, SaleType, residentialBuildings, ivElemEntrCnt, view, isBalconiesOrLoggias, activeSort, objectIds, isLivingFlg, regionHD, status, subject, region, problemReason, mechanism, dduFlg, transferFlg, searchValue, buildFlg, regionCd, devGroupId, regionActivity, repYear, calculationType, period, addrAreaId, devCalcGroupId, objClassCd, repMonth, devGroupValue, cityPopulation, inline, filename, cooperativeId","Риск: фактически документация API там где её не должно быть. Раскрывает несуществующие в UI параметры (regionHD, regionActivity, problemReason, fundFlag, checkFlg и др.) — это заявка на over-fetching","Severity: low-medium — помогает attacker'у искать скрытые фичи. Для нас — ПОЛЕЗНО для расширения набора фильтров в GenDesign клиенте"]}
{"type":"entity","name":"DomRF_Recon_OptionsPost_Apr26","entityType":"research","observations":["OPTIONS /сервисы/api/kn/object → Allow: HEAD, POST, GET, OPTIONS","POST разрешён на якобы READ-ONLY API — значит у них есть write-методы которые из публичной схемы не видны","Вероятно: для авторизованных юзеров через ЛК (личный кабинет) есть create/update operations на объекты","/portal-analytics/api/* в отличие — GET, HEAD, OPTIONS (read-only как положено)","Польза для нас (GenDesign): способ понять какие endpoints имеют write-поверхность — без активных тестов их","Риск (mass-assignment): если POST /object принимает JSON без валидации типов полей и имеет слабую auth — потенциальный вектор. НЕ ПРОВЕРЯЛИ (active scan)","Severity: неопределённая — зависит от реализации POST. Только факт раскрытия в OPTIONS — low"]}
{"type":"entity","name":"DomRF_Recon_CORS_Apr26","entityType":"research","observations":["CORS на /сервисы/api/kn/*:","Access-Control-Allow-Origin: <эхо Origin> (по видимому reflective)","Access-Control-Allow-Credentials: true","Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT","Access-Control-Allow-Headers: accept, authorization, content-type, x-requested-with","Access-Control-Max-Age: 1 (слишком мало — preflight каждый раз)","Риск: если Origin валидируется слабо (regex/null/эхо), злоумышленный сайт может дёргать API с сессией юзера. НЕ проверяли","Severity: low (обычно банки/фронт современных институтов валидируют жёстко). Но комбинация credentials:true + reflective Origin = классический misconfig","Полезно для нас (GenDesign): /сервисы/api/kn/* можно дёргать с любого Origin — не нужен прокси на нашем бэкенде (браузер пропустит прямые вызовы)"]}
{"type":"entity","name":"DomRF_Recon_PortalSitemap_Apr26","entityType":"research","observations":["Недокументированный service-prefix /portal-sitemap/api/ — раскрыт через robots.txt","GET /portal-sitemap/api/sitemap/root.xml → 200, 10 sub-sitemap'ов:","static.xml, turisticheskaya-nedvizhimost.xml, kvartiry-v-novostrojkah.xml, media.xml, edinyj-reestr-zhsk.xml, edinyj-reestr-zastrojshchikov.xml, gruppa-kompaniy.xml, object-zhsk.xml, katalog-novostroek.xml, proverka-novostroek.xml","GET /portal-sitemap/api → 404 (корневая ручка не работает — нужен конкретный sitemap)","GET /portal-sitemap/api/sitemap → 500 — ручка существует но багает без параметров","Для GenDesign: из sub-sitemap'ов можно вытащить ПОЛНЫЙ список URL всех ЖК/застройщиков/ГК/ЖСК в РФ — альтернатива двухшаговому flow через /sales/portal","Severity: инфо публичная (по robots.txt). 500 на /sitemap — легкий сигнал что в сервисе есть необработанный путь"]}
{"type":"entity","name":"DomRF_Recon_NoSourceMaps_Apr26","entityType":"research","observations":["ПРОВЕРКА: source maps для Next.js бандлов НЕ выложены (все *.js.map = 404).","main-*.js.map → 404, commons.*.js.map → 404, _app-*.js.map → 404, page chunks .map → 404","Это хорошая практика ДОМ.РФ — скрывают исходники React/TypeScript от выкладывания в prod","Но минифицированный JS всё равно реверсился — мы вывели все endpoints из него","Severity: нет (good practice)"]}
{"type":"entity","name":"DomRF_Recon_DisclosurePlan_Apr26","entityType":"feedback","observations":["План responsible disclosure если решим репортить находки ДОМ.РФ.","Why: у ДОМ.РФ НЕТ публичной BB-программы. Репортить нужно вручную без reward'ов, плюс риск вызвать подозрение и отзыв фронт-доступа (наш основной канал)","How to apply: отправить только если обваливается находка medium+. Из текущего списка: AcceptVersionLeak (medium), OIDC password grant (medium)","Канал: nash@domrf.ru (из их официальных контактов с /интеграция)","Альтернативный канал: CERT-GIB / НКЦКИ России если прямой репорт игнорируется","Шаблон репорта: описание находки → PoC (URL и response header) → impact → fix recommendation → время на fix (90 дней по обычаю). NDA не подписывать — данные и так публичные","ПРИОРИТЕТ ниже релиза GenDesign MVP — сначала делаем продукт, потом репорт. Но лучше репортить после начала партнёрства с банком-Раунда-А — будет легальный channel"]}
{"type":"entity","name":"DataSource_PerDeal_Reality_Apr26","entityType":"research","observations":["ПЛАН B для истинного per-deal: раздобыть данные Антона (ДДУ-канал) — см. блокировку #10 в PlanA_AnalyticsFirst_Apr25","ПЛАН C: партнёрство с банком (Сбер/ДОМ.РФ) для доступа к их внутренним ипотечным выдачам (это per-deal но только ипотечные, ~75% сделок)","ПЛАН D: ЕРЗ.РФ премиум-подписка — у них есть per-ЖК статистика продаж (по их рекламе), не проверяли. ~50-500 тыс ₽/год","⚠ ОБНОВЛЕНО 26.04.2026 вечер после находки Rosreestr open dataset:","ПРЕДЫДУЩИЙ ВЫВОД ОШИБОЧЕН — ПЕР-DEAL ДАННЫЕ ЕСТЬ. Росреестр стал публиковать CSV-выгрузки всех регистрируемых сделок с ЦЕНАМИ в рамках 'data-sety-rosreestra' (начали в 2024 или раньше).","СМ. DataSource_Rosreestr_DealsCSV_Apr26 — это теперь ОСНОВНОЙ источник per-deal данных","НОВАЯ ИЕРАРХИЯ источников:","1. ОСНОВНОЙ (фактические цены сделок, обе первичка+вторичка): Росреестр dataset_СДЕЛКИ (по кварталам в CSV)","2. ДОПОЛНИТЕЛЬНый (текущий прайс-лист + velocity, только первичка): ДОМ.РФ per-flat snapshot","3. CROSS-VALIDATION (ипотечные сделки): ЦБ РФ mortgage data","4. CROSS-VALIDATION (базовые рыночные цены): Fedstat 31452","5. REGION-SPECIFIC вторичка Екб: УПН (цены предложения)","ПЛАН B/C/D/E больше НЕ НУЖЕН — Росреестр CSV решает основную задачу. Партнёрство с банком или ЕРЗ — опциональное улучшение позже (для выявления ипотека/наличные и покупателя)"]}
{"type":"entity","name":"DataSource_CBR_Mortgage_Apr26","entityType":"research","observations":["ЦБ РФ ипотека: https://www.cbr.ru/statistics/bank_sector/mortgage/","Что есть (ТОЛЬКО АГРЕГАТЫ):","Жилищные кредиты физлицам (ОБЩИЙ объём, регион/банк/месяц)","Ипотечные кредиты + приобретённые права требования","Кредиты под залог ПРАВ ПО ДДУ (полезно: это прямой сигнал первичных продаж)","Досрочное погашение (квартальные)","Рефинансирование + эмиссия ЦБ","По регионам: объёмы выданных, задолженность (включая просроченную), кол-во кредитов, средневзвешенные сроки/ставки","Формат: XLSX, ~20+ таблиц (02_01..02_46+). Обновление ежемесячно по календарю","API НЕТ — только прямые ссылки на XLSX. ETL: cron-task раз в месяц скачать + распарсить","Для GenDesign: полезно для финмодели — региональные средние ставки, дают лучший сигнал чем выдачи от 1-2 банков","Это ДОПОЛНЯЕТ DomRF Tab10 (mortgage-rates: предложение) — ЦБ даёт фАКТИЧЕСКИЕ выдачи"]}
{"type":"entity","name":"DataSource_Fedstat_Apr26","entityType":"research","observations":["ЕМИСС / fedstat: https://www.fedstat.ru/. 8944 показателя от 60 ведомств, включая Росреестр и Росстат","Индикатор 31452 — 'Средняя цена 1 кв.м общей площади квартир на рынке жилья'","Разрезы 31452: квартал, регион (ОКАТО), рынок (первичка/вторичка), тип квартир (по кол-ву комнат). Данные 2000-2025. Обновление 09.02.2026 (19-23 рабочих дня после квартала)","Источник 31452: форма 1-РЖ 'Сведения об уровне цен на рынке жилья', Росстат","Формат: SDMX, XLSX. API видимо не публичный (search/start.do падает с 500 'isJpисключение')","Росреестр в fedstat: есть показатели по регистрациям, но их конкретные ID не определили (сервис поиска багает). TODO — разовая выгрузка вручную через браузер когда система работает","Для GenDesign: основное baseline для cross-validation цен в финмодели. Разовая выгрузка с обновлением раз в квартал"]}
{"type":"entity","name":"DataSource_Rosreestr_OpenService_Apr26","entityType":"research","observations":["Росреестр open-service: https://rosreestr.gov.ru/open-service/. Сайт отдаёт self-signed-cert в пробе (видимо gov-CA не в cert-store WebFetch — открывать вручную)","Что реально доступно (по предыдущим проверкам и публичным отчётам):","Публичная кадастровая карта (ПКК) — границы участков, кадастровый номер. НЕТ СДЕЛОК","Сведения ОГРН (о юрлицах регистрации) — реестры","Статистика в fedstat — АГРЕГАТЫ по регистрациям (кол-во ДДУ/установлений прав по регионам)","ПООБЪЕКТНЫХ ДДУ/КП НЕТ в открытых данных — это персональные данные по 152-ФЗ + коммерческая тайна","API: неформальный ДвОИЧНЫЙ https://pkk.rosreestr.ru/api/* (известно из community), используется в РосРеестр SDK","Для GenDesign: ПКК полезна для Site Finder (границы участка, КН, вид разрешённого использования). Для per-deal — бесполезен, только агрегаты через fedstat"]}
{"type":"entity","name":"DataSource_UPN_Ekb_Apr26","entityType":"research","observations":["Уральская Палата Недвижимости (Екб/Свердл.обл): https://upn.ru/","Аналитика на https://old.upn.ru/analytics.htm","Что публикуется (АГРЕГАТЫ):","Еженедельные отчёты 'Средние цены предложения недвижимости'","Территориальные разрезы: 4 района Екатеринбурга + Свердл.область","Архив: с 2007 года по настоящий момент (это 19+ лет longitudinal data!)","Формат: веб-страницы/PDF по годам и месяцам, без API. ETL = парсинг PDF + HTML","API/подписка: НЕ ОПИСАНО публично. Для коммерческого доступа — +7 343 367-67-60","ОГРАНИЧЕНИЕ: цены ПРЕДЛОЖЕНИЯ, НЕ сделок. Источник — листинги риелторов-членов УПН","Для GenDesign: ОТЛИЧНЫЙ region-specific baseline для Екатеринбурга. 19-летний ряд даёт хороший сигнал по истории рынка. Парсить раз в неделю","ПОТЕНЦИАЛЬНОЕ ПАРТНЕРСТВО: Екатеринбург-фокус у GenDesign + локальный бренд УПН = имеет смысл договориться о подписке на сделки (у риелторов уже есть фактические сделки)"]}
{"type":"entity","name":"DataSource_DomRFAsPerDeal_Apr26","entityType":"research","observations":["ДОМ.РФ как SYNTHETIC per-deal источник — самый жизнеспособный вариант для GenDesign без партнёрств.","Принцип: ежедневный snapshot /сервисы/api/kn/flats?regions=66 → diff с вчерашним → события","События которые мы получим (каждое = synthetic deal):","(a) status_change: free → booked = бронь, free → sold = прямая продажа, booked → sold = выкуп после брони","(b) price_change: priceChangeDate поменялась → (возможно продажа и передобавление, или ревальвация)","(c) delisting: квартиры нет в списке → продали (sold или сделали невидимой)","(d) new_listing: новая квартира = новый старт продаж","Результат: таблица dom_rf_flat_events (см. DomRF_PerFlat_ETL_Apr26) с полями (flat_id, event_dt, event_type, old_value, new_value)","ОГРАНИЧЕНИЯ: (1) НЕТ инфы о покупателе (физ/юр лицо, ипотека/нал), (2) НЕТ инфы о фактической цене сделки (может быть дискаунт вне прайс-листа), (3) ~3-7 дней лаг между сделкой и обновлением статуса в ЕИСЖС","ДЛЯ GenDesign: этого ДОСТАТОЧНО для Plan A 'ПЛИТКИ 3' (за какое время продастся). Абсолютная точность цены не нужна — нужен тренд/velocity"]}
{"type":"entity","name":"DataSource_Rosreestr_DealsCSV_Apr26","entityType":"research","observations":["Дата: 26.04.2026. ГЛАВНАЯ НАХОДКА: Росреестр СДЕЛАЛ ПУБЛИЧНЫМИ регистрируемые сделки с недвижимостью (CSV-выгрузки по кварталам).","URL: https://rosreestr.gov.ru/data-sets/ — Apache open directory listing","Описание: https://rosreestr.gov.ru/open-service/data-sety-rosreestra/dannye-o-tsenakh-registriruemykh-sdelok-po-otchuzhdeniyu-s-obektami-nedvizhimosti-v-razreze-territorialnoy-prinadlezhnosti/","Структура директории:","/data-sets/{N квартал YYYYг.}/dataset_СДЕЛКИ_r-r_01-92_y_YYYY_q_N.csv.zip","/data-sets/{N квартал YYYYг.}/dataset_КАДАСТРСТОИМОСТЬ_r-r_{XX-YY}_y_YYYY_q_N.csv.zip (4 файла по регионам)","/data-sets/{N квартал YYYYг.}/dataset_АРЕНДА_r-r_01-92_y_YYYY_q_N.csv.zip","Доступные периоды: все 4 квартала 2024, все 4 квартала 2025, 1 кв 2026 (обновлен 16.04.2026). + Архив до 2023г. включительно (отдельный пакет)","Частота: ежеквартально (публикуется ~через 1.5 месяца после окончания квартала)","Q1 2026 факты: dataset_СДЕЛКИ_*.csv.zip = 9.5 MB ZIP, 96 MB CSV, 569 723 строки","Подсчёт по Q1 2026: 898 302 сделки по РФ всего (709 812 ДКП + 188 490 ДДУ). Свердл.обл: 37 310 сделок","Источник: ФГИС ЕГРН — реальные зарегистрированные сделки (не листинги, не предложения)","Исключения: безвозмездные сделки НЕ включены (дарения, наследования)"]}
{"type":"entity","name":"DataSource_Rosreestr_DealsCSV_Schema_Apr26","entityType":"api_spec","observations":["Схема CSV-выгрузки Росреестра dataset_СДЕЛКИ. Кодировка: UTF-8. Разделитель: '~' (тильда!). 17 полей:","number — КОЛИЧЕСТВО сделок в этом ряду (ряд = агрегация одинаковых сделок). Для расчёта итогов НАДО умножать на number","okato — ОКАТО код","region_code — ID региона (66=Свердл.обл, 77=Москва, ...)","district — муниципальный район/округ","city — населённый пункт","quarter_cad_number — КАДАСТРОВЫЙ КВАРТАЛ (напр. '50:12:0010209'). Это самый важный гео-ключ — блок размером от дома до квартала. Можно джойнить с ПКК Rosreestr","street — улица (часто пустая)","realestate_type_code — тип объекта: 002001001000=ЗУ, 002001002000=Здание, 002001003000=Помещение, 002001009000=Машиноместо","wall_material_code — СПРАВОЧНИК 126_УНСИ_Перечень наименований материалов наружных стен","year_build — год постройки/ввода в эксплуатацию","floor — этажность (для Здания) / номер этажа (для Помещения)","purpose_code — назначение объекта: спр 66_УНСИ (Здания), 67_УНСИ (Помещения), 148_УНСИ (виды разрешённого использования ЗУ)","area — площадь (м² для помещений, м² для ЗУ)","period_start_date — ПЕРВОЕ ЧИСЛО КВАРТАЛА. ⚠ НЕ фактическая дата сделки — все сделки квартала имеют одну и ту же дату. Гранулярность времени = квартал","deal_price — ЦЕНА СДЕЛКИ в валюте (средняя если number>1)","currency — 'рубль' в большинстве случаев","doc_type — 'ДКП' (договор купли-продажи, вторичка и ГП) или 'ДДУ' (долевое строительство — ПЕРВИЧКА)","ГРАНУЛЯРНОСТЬ итоговая: row = уникальный (регион, район, нас.пункт, кад.квартал, улица, тип, материал, год, этаж, назначение, площадь, doc_type) + ЦЕНА + number. Для квартир это близко к per-flat (но без номера квартиры и конкретной даты)"]}
{"type":"entity","name":"DataSource_Rosreestr_DealsCSV_Sverdl_Q1_2026","entityType":"research","observations":["Реальные цифры из скачанного dataset_СДЕЛКИ за Q1 2026 по Свердл.обл (region_code=66) — проверка качества источника.","ИТОГО сделок в Свердл.обл за Q1 2026: 37 310 (после умножения на number)","Распределение по типу объекта:","Помещения (квартиры/нежилые): 24 923","Земельные участки: 7 157","Здания: 3 130","Машиноместа: 2 100","Распределение по doc_type:","ДКП (вторичка+ГП): 26 655","ДДУ (ПЕРВИЧКА): 10 655","Практически все ДДУ = новостройки + прямая покупка от застройщика. ДКП — вторичка и прямые П в ГП","ЦЕНЫ ₽/м² ПО ПОМЕЩЕНИЯМ (выборка: area 5-500 м², price>100К):","ДКП median: 82 594 ₽/м², mean: 89 206 ₽/м² (n=14 994)","ДДУ median: 156 314 ₽/м², mean: 220 983 ₽/м² (n=664)","Первичка ВДВОЕ дороже вторички в Свердл.обл — логично (вторичка включает хрущёвки 60-х годов, НП, МО подмосковье и т.д.)","Сверка с baseline: статистика ДОМ.РФ / Росстат по Свердл.обл в ~85-95 тыс ₽/м² (Apr 2025) — совпадает с ДКП median 82,594","ПРИМЕРЫ реальных сделок в Екб (квартал 66:41:*):","4.8М ₽ за 40.9 м² (117К ₽/м²), дом 2019, 3 этаж","6.7М ₽ за 32.2 м² (208К ₽/м²), дом 2022, 6 этаж","1.9М ₽ за 28.9 м² (66К ₽/м²), дом 1962 — хрущёвка","ТОП районы: 'Екатеринбург' (1642+1293=2935), Сысертский (1098), Белоярский (728)","Для GenDesign ПЛИТКИ 2 (ЦЕНА): рабочая выборка — сделки ПОМЕЩЕНИЙ в кадастровых кварталах в радиусе 5км от участка пользователя, раздельно ДКП vs ДДУ"]}
{"type":"entity","name":"DataSource_Rosreestr_ETL_Plan_Apr26","entityType":"research","observations":["ETL-план интеграции открытых данных Росреестра в GenDesign Stage 2a.","ИСТОЧНИКИ: 3 dataset типа на квартал: СДЕЛКИ (НАШ!), АРЕНДА, КАДАСТРСТОИМОСТЬ (4 файла)","ОБЪЁМ СДЕЛОК по кварталу: ZIP 9-30 MB, CSV 96-300 MB, ~600К-1.5М строк","ДОСТУПНО НА СЕЙЧАС: 9 кварталов (Q1 2024 - Q1 2026) + Архив до 2023г. (JSON-выгрузки по регионам, ~50-300 MB на регион в ZIP)","СТРАТЕГИЯ заливки:","Шаг 1: bootstrap — одноразовый скрипт скачивает все 9 кварталов СДЕЛОК → распакует → фильтрует region_code IN (66, 50, 77) → upsert в PostgreSQL","Шаг 2: cron-task quarterly_rosreestr_sync — раз в квартал (16-е число второго месяца после окончания квартала) проверять index и тянуть новый квартал","Шаг 3: обогащение: JOIN с ПКК Rosreestr по quarter_cad_number → получить geom квартала (полигон) + центроид","SQL Schema (PostgreSQL):","CREATE TABLE rosreestr_deals (id BIGSERIAL PK, region_code SMALLINT, district TEXT, city TEXT, quarter_cad_number VARCHAR(30), street TEXT, realestate_type_code VARCHAR(15), wall_material_code VARCHAR(15), year_build SMALLINT, floor TEXT, purpose_code VARCHAR(15), area NUMERIC(12,2), period_start_date DATE, deal_price NUMERIC(14,2), currency VARCHAR(10), doc_type VARCHAR(10), deal_count INT, raw_okato VARCHAR(15), source_quarter VARCHAR(10))","Индексы: (region_code), (quarter_cad_number), (period_start_date), (doc_type), (realestate_type_code), GIST на geom после энричмента","Materialized views: median(price/area) по (region, quarter, doc_type, realestate_type) и по радиусу 5км вокруг lat/lon","Объём работы: скачать+распаковать+лоаднуть 9 кварталов в PG для 3 регионов = 2-3 часа. ETL код = 4-6 часов. ПКК-энричмент = 1-2 дня","Для ПЛИТКИ 2 в GenDesign: это ОСНОВНОЙ источник фактических цен сделок (ДОМ.РФ остаётся для текущего прайс-листа и velocity)"]}
{"type":"entity","name":"DataSource_Rosreestr_DealsCSV_Limits_Apr26","entityType":"research","observations":["ОГРАНИЧЕНИЯ открытого dataset Росреестра dataset_СДЕЛКИ — важно знать перед интеграцией.","1. НЕТ покупателя/продавца — персональные данные по 152-ФЗ НЕ выкладываются","2. НЕТ конкретной даты сделки — period_start_date = первое число квартала. Гранулярность времени = 90 дней","3. НЕТ кадастрового номера ОБЪЕКТА, только КАДАСТРОВЫЙ КВАРТАЛ. Нельзя связать с ДОМ.РФ odsId/elemId напрямую","4. ГРУППИРОВКА дубликатов в row + number: если 5 одинаковых квартир в одном жк проданы с похожими характеристиками — склеиваются в 1 ряд с number=5 и СРЕДНЕЙ ценой","5. НЕТ инфы о форме оплаты (наличные/ипотека), только итоговая цена","6. НЕТ комнатности квартиры. Можно инферить по площади (>50м² = 2к, >70 = 3к, ...) но не точно","7. НЕТ застройщика/ЖК в явном виде — выводим через JOIN ПКК → ДОМ.РФ /object по координатам квартала","8. Безвозмездные сделки (дарения, наследства) НЕ включены","9. ЛАГ: dataset публикуется ~через 1.5 месяца после конца квартала (Q1 2026 вышел 16.04.2026)","10. САМОСТОЯТЕЛЬНОСТЬ от ДОМ.РФ: СДЕЛКИ регистрируются все (и вторичка и первичка), тогда как ДОМ.РФ покрывает только первичку в строящихся ДОМАх = Росреестр ШИРЕ","11. ЮР.СТАТУС: официальный open data, в реестр ПО декларируем 'Интеграция с открытыми данными Росреестра (фИГС ЕГРН)' — легально и без NDA"]}
{"type":"entity","name":"Rosreestr_SiteMap_Apr26","entityType":"research","observations":["Карта ресурсов Росреестра (обзор 26.04.2026 passive recon).","rosreestr.gov.ru — ОСНОВНОЙ портал (Bitrix CMS), TLS с self-signed-cert (Минцифры CA, не в system store)","  ├─ /eservices/ — электронные услуги (выписки ЕГРН 340-4160 ₽, регистрация прав, ДДУ-проверка)","  ├─ /opendata/ — 17 МАНДАТНЫХ open data наборов (СРО кадастровых инженеров, лицензии, проверки, ГКГН). Базовые реестры без сделок","  ├─ /open-service/data-sety-rosreestra/ — ⭐ 3 ДАТАСЕТА с РЫНОЧНЫМИ ДАННЫМИ:","  │    ├─ СДЕЛКИ (ДКП+ДДУ) с ценами — см. DataSource_Rosreestr_DealsCSV_Apr26","  │    ├─ КАДАСТРСТОИМОСТЬ (4 файла по регионам)","  │    └─ АРЕНДА (договоры аренды)","  ├─ /data-sets/ — Apache OpenIndex файлы CSV по кварталам — см. DataSource_Rosreestr_DealsCSV_Apr26","  └─ /open-service/statistika-i-analitika/ — только пресс-материалы, нет выгрузок","nspd.gov.ru — НОВЫЙ ПОРТАЛ НСПД (Национальная Система Пространственных Данных), заменил ПКК","  ├─ React SPA с Module Federation (микро-фронты)","  ├─ /api/{service-name}/{version} — микросервисы: notifications-controller/v2, ticket-support/v3, registers-manager/v2, tech-process/v2","  ├─ Все API требуют auth — ESIA через Госуслуги","  └─ X-TIMEZONE header обязателен","pkk.rosreestr.ru — 301 → nspd.gov.ru/map?thematic=PKK (старый ПКК устарел)","lk.rosreestr.ru — Личный кабинет (React SPA, ESIA auth)","rosreestr.ru — старый домен (большинство поддоменов не отвечают в пробе)"]}
{"type":"entity","name":"Rosreestr_OpenData_17Sets_Apr26","entityType":"research","observations":["Полный список 17 open data наборов на https://rosreestr.gov.ru/opendata/ (ПО идентификатору 7706560536 = ИНН Росреестра).","Наборы реестров СРО (полезные GenDesign):","1. СРО кадастровых инженеров — контрагенты для топосъёмки","2. СРО оценщиков — профессиональная оценка для финмодели","3. СРО арбитражных управляющих — для проблемных объектов (банкротство застройщиков)","4. Реестр лицензий на геодезическую и картографическую деятельность","5. Государственный каталог географических названий — полезно для нормализации адресов","Наборы НЕ полезные для GenDesign:","6-9. Планы/результаты проверок (землепользование, геодезия, СРО)","10. Перечень ГИС Росреестра","11-13. СРО медиаторов, РОК, СРО без полномочий, ЭП-площадок","14-17. Различные проверки и результаты","Это ГОС-МАНДАТ по 8-ФЗ 'O доступе к информации'. Реальные рыночные данные (СДЕЛКИ/КАДАСТР/АРЕНДА) НЕ здесь, а в отдельном блоке /open-service/data-sety-rosreestra/","Формат выгрузки (по паспорту): CSV/XML/JSON раз в квартал/месяц в зависимости от набора"]}
{"type":"entity","name":"NSPD_Architecture_Apr26","entityType":"api_spec","observations":["НСПД (nspd.gov.ru) — новый портал Росреестра для пространственных данных, заменил ПКК (pkk.rosreestr.ru → 301)","Архитектура:","— React SPA с Vite билдом (видно по import-паттернам и vite_API_BASE)","— Module Federation с micro-frontends (видны runtime hooks @nspd-modules/*)","— Effector + atomic-router для state management","— ui kit @nspd/uikit (внутренний)","— Map: @nspd-modules/map-core, map-adapter","— Yandex Metrika (yandex-metrika-xOrTB1Q0.js)","— Special browser support: YaBrowser, Firefox, Chromium-Gost, Chrome (без Edge)","Microservices API base = '/api/{service}/{version}':","— /api/notifications-controller/v2/notifications","— /api/ticket-support/v3/tickets","— /api/registers-manager/v2 — реестры","— /api/tech-process/v2 — техпроцессы","— /api/aeggis-portal/v3/spatial-data-info — инфо пространственные данные (AEGGIS = Application for Earth Geospatial Information System)","— /api/aeggis-portal/v1/auth-providers — провайдеры авторизации","— /api/services — сервисы НСПД","Все вызывают 403 без auth (видимо SSO через Госуслуги/ESIA)","Обязательный header: X-TIMEZONE","Для GenDesign: НСПД не даёт прямого API без ESIA-входа. Альтернатива — старый ПКК-API community библиотек (rosreestr2coord) они могли сломаться после миграции"]}
{"type":"entity","name":"Rosreestr_Recon_Findings_Apr26","entityType":"research","observations":["Passive recon наблюдения на rosreestr.gov.ru и nspd.gov.ru (26.04.2026). Только то что видно при просмотре публичных страниц и их bundle. Без active scan.","1. ⚠ dev-поддомен в prod-bundle (medium): в nspd.gov.ru/assets/api-ByMDT02-.js вывернута vite переменная VITE_PROXY_DOMAIN=https://dev.nspd.rosreestr.gov.ru — раскрывает существование dev-копии портала. Прямые пробы dev-хоста НЕ делали (active recon за рамками пользовательского запроса)","2. ⚠ X-Powered-CMS header (low): rosreestr.gov.ru отдаёт 'X-Powered-CMS: Bitrix Site Manager (d61e85ea0be7ddfb3fa5a12935cc91a6)' — раскрывает CMS + license-hash. Обычно хеш = SHA Bitrix лицензии (в отличие от просто 'Bitrix') — портрет продакшн инстанса","3. ⚠ Двойной Referrer-Policy header (low): выдаются два разных 'Referrer-Policy: origin-when-cross-origin' и 'Referrer-Policy: unsafe-url'. По спеке второй выигрывает — unsafe-url пропускает ПОЛНЫЙ URL+query в Referer на внешние сайты. Утечка приватности","4. ⚠ SameSite отсутствует в cookies (low): PHPSESSID, USER_REGION_ID, USER_CITY выдаются без SameSite-атрибута. CSRF risk при входе в ЛК","5. ⚠ P3P header устарел (info): policyref='/bitrix/p3p.xml' — P3P стандарт давно обсолетен (W3C прекратил в 2009)","6. ⚠ Typo в canonical URL (cosmetic): на nspd.gov.ru в <link rel=canonical> указан 'nspd.rosreetr.gov.ru' (rosreetr без 's') — опечатка в build","7. ⚠ Отсутствует Content-Security-Policy header на обоих доменах (low) — слабая защита от XSS","8. ⚠ robots.txt разрешает /opendata/ но НЕ учитывает /open-service/data-sety-rosreestra/ и /data-sets/ — это не баг, это отсутствие стратегии (файлы индексируются)","9. Открытая директория /data-sets/ (info, НЕ уязвимость, это полезный listing) — Apache mod_autoindex. Но кодировка имён в листинге = cp1251 (mojibake в UTF-8 браузере), свидетельство legacy Apache config","10. SSL TLS с российским CA (Russian Trusted CA / Минцифры) — не в trust store обычных OS/браузеров. Браузер Chromium-Gost или ruchnoe доверие в system store нужны. Для ETL в GenDesign — curl -k или ручное включение CA","Severity общая: все наблюдения LOW-MEDIUM. Ничего критичного не найдено (и не искали active scan'ами)","ДЛЯ GenDesign: из утечек ничего не используем. На реестр ПО декларируем только легальные источники: 'open data Rosreestr' (data-sety-rosreestra)"]}
{"type":"entity","name":"Rosreestr_TLS_Note_Apr26","entityType":"feedback","observations":["Росреестр (rosreestr.gov.ru, nspd.gov.ru) использует TLS-сертификат от российского CA (Russian Trusted CA Минцифры), который НЕ включен в браузеры/OS из коробки за пределами РФ.","Why: после санкций 2022 российские госресурсы перевели выдачу TLS на Минцифры. Обычный Chrome показывает ERR_CERT_AUTHORITY_INVALID","How to apply в GenDesign:","1) При ETL/curl используй флаг -k (skip cert check) — это безопасно потому что это открытые данные без auth/PII","2) Для строгой валидации в проде — добавь в trust store: https://www.gosuslugi.ru/crt/MinCifry_RootCA.pem","3) Python requests: используй verify=False или verify=path_to_minciftry_ca","4) Браузеры: Yandex Browser и Chromium-Gost включают CA по умолчанию","Не связано с security: это инфраструктурная особенность. Наблюдаемые данные в открытом доступе легальны"]}
{"type":"entity","name":"NSPD_OAuth_Architecture_Apr26","entityType":"api_spec","observations":["NSPD (nspd.gov.ru) auth: собственный OAuth2/OIDC сервер на sso.nspd.gov.ru, провайдер = ESIA Госуслуги.","Token endpoint: POST https://nspd.gov.ru/oauth2/token (прокси на sso.nspd.gov.ru)","Body: {grant_type: 'refresh_token'|'authorization_code', client_id: 'nspd'} — как JSON, NOT form-urlencoded","Real client_id (UUID): 03386dbe-5185-4b96-900d-c2b1bb368ed6","JWT issuer: https://sso.nspd.gov.ru, algo: RS256","JWT TTL: 1800с (30 мин). Refresh ttl: лонже (30+ мин, точно не известно — не проверяли)","Cookie storage: authAccessToken + authRefreshToken в cookie с HttpOnly, secure, SameSite=None, domain=nspd.gov.ru. Недоступны JS, но видны в DevTools Network","ESIA scope (при входе запрашивается): ОРГАНИЗАЦИИ, АДРЕСА, ДР, фИО, ИНН, СНИЛС, емаил, телефон, ПАСПОРТ — очень широко для сервиса карты. Для GenDesign это предупреждение же — НЕ интегрируем НСПД с ESIA в наш продукт (слишком большой PII surface)","JWT claims (PII!): aud, client_id, display_name, email, family_name, given_name, middle_name, sub (UUID), uid (UUID), preferred_username, sid, scope='profile email uid', updated_at","X-TIMEZONE обязателен в каждом запросе","Backend сигнатура: x-backend: dc1-gw-8-1, x-api-header: af, x-request-id: hex"]}
{"type":"entity","name":"NSPD_PhysicAccess_Apr26","entityType":"research","observations":["Доступ к NSPD API для physic-аккаунта (физлицо через ESIA) — проверено эмпирически 26.04.2026.","GET /api/registers-manager/v2/pages/main → 200, typeAccount: 'physic', 18 сервисов:","approvalInConstruction (согласования в строительстве), integratedDevelopmentOfTheTerritory (КРТ), individualHousingConstruction (ИЖС), myProperties (мои объекты), arcticPeopleLanguages, urbanPlanningStudyOnline (градопроработка), smallBusiness, assistantSurveyor (помощник изыскателя), geodataVisualization, cadastralValuation, landNspd, farmLand, buildingLand, tourismNspd, marketAnalytics (НАШ!), complexCadastralWorks, specialTools, thematicUserLayers","URL-маппинг сервисов (frontend routes):","/market-analysis → marketAnalytics","/urban-analyze → urbanPlanningStudyOnline","/construction-nspd → buildingLand (земля для стройки)","/integrated-development-territories → КРТ","/cadastral-valuation → cadastralValuation","/my-properties → myProperties","/assistant-surveyor → assistantSurveyor","GET /api/notifications-controller/v2/notifications → 200 (totalCount: 0 для нового юзера)","GET /api/portal-tools/v1/page-assistant/{pageCode} → 200 (флаг assistant)","POST /api/portal-tools/v1/audit → 200 (аудит пользовательских действий)","ЗАКРЫТО для physic (403 Forbidden код=3):","/api/registers-manager/v2/registers/can-get-tree — дерево реестров","/api/aeggis-portal/v3/* — портал пространственных данных (объекты, registry-list, spatial-data-info, auth-providers)","/api/services/* — сервисы NSPD","/api/v1/parcels — парцели","Эти endpoints видимо для organisation-аккаунта (юрлицо) или госслужащих","Для GenDesign: physic-аккаунта хватит для marketAnalytics + WMTS-карта. Реестры/объекты — требуют юрлица"]}
{"type":"entity","name":"NSPD_MarketAnalytics_API_Apr26","entityType":"api_spec","observations":["Сервис nspd.gov.ru/market-analysis — 'Аналитика рынка недвижимости', официальный сервис Росреестра.","Источник данных: Цены сделок по продаже квартир на вторичном рынке из ФГИС ЕГРН с 2018 года","Разрезы: федокруг / субъект РФ / населённый пункт / кадастровый квартал. Визуализация: тепловая карта, графики, таблица","Auth: ESIA-вход (physic), JWT в cookie","Base: /api/market-analytics/v1/","GET /filters/indicators → [{id:1,title:'Индикатор цен ежемесячный',type:M},{2,'Квартальный',Q},{3,'Полугодовой',H},{4,'Годовой',Y}]","GET /filters/calculationMethod → [К базисному, К предыдущему, К аналогичному периоду годом ранее]","GET /filters/dataSource → [{1,ФГИС ЕГРН,fgisEgrn},{2,Внешние,externalSource}]","GET /filters/areaRanges → [0-25, 25-40, 40-60, 60-80, 80-100, 100+]","GET /federal-district → [8 ФО с codes 1-8]. Уральский=6, Сибирский=7, Дальневосточный=8, Приволжский=5, СКФО=4, СЗФО=2, ЦФО=1, ЮФО=3","GET /groups/fgisEgrn → полная схема фильтров: dataSource, indicators, calculationMethod, periodFrom/periodTo, federalDistrict, federalSubject, settlement, cadastralQuarter, areaRanges. limit=10 на множественные выборы","GET /layers-tree → 6 MVT-слоёв на разные площади. layerId 872964-872969. categoryId 470043. visualType=bubble, minZoom=2, tileExtent=512","POST /period (body: {type, dataSourceSysName}) — периоды доступные для индикатора (POST, валидации проверены)","POST /settlement (body: другой формат — не выявлен) — нас.пункты","GET /federal-subject?federalDistrict={code} — видимо есть но ожидает другой формат параметров","Data endpoint (чарт/таблица) — НЕ НАЙДЕН без реального UI-выбора. Связаные endpoints для рендера в SPA ловятся только при полном set выборе фильтров","КОНЦЕПЦИЯ для GenDesign: это ГОТОВЫЙ official aggregation API по сделкам ПО КАДАСТРОВЫМ КВАРТАЛАМ. В отличие от CSV-датасета (сырые сделки раз в квартал) — это предварительно вычисленные индикаторы с выбором временного окна (M/Q/H/Y) и динамики относительно базы/предыдущего/ГОГ"]}
{"type":"entity","name":"NSPD_AEGGIS_WMTS_Apr26","entityType":"api_spec","observations":["AEGGIS WMTS API НСПД — картирование слоёв в стандарте OGC WMTS.","GET /api/aeggis/v4/{layerId}/wmts/{z}/{x}/{y}.png — PNG растровые тайлы. layerId=235 — 'Цифровая объектовая схема' (базовый справочный слой)","GET /api/aeggis/v4/{layerId}/mvt/{z}/{x}/{y} — Mapbox Vector Tiles (предположение по schema layers-tree)","MarketAnalytics MVT-слои: 872964 (объекты 0-25м²), 872965 (25-40), 872966 (40-60), 872967 (80-100), 872968 (100+), 872969 (60-80). Все из categoryId 470043. priceIndicator как key","Base layers (/api/geoportal/v1/baselayers): id=235 (ЦОС), id=36347 (ЕЭКО), id=36344 (Ортофото планы 2000) и другие","Cache: в ответе видны cache.levels_to (max zoom), refresh_before для временного инвалидирования","External tiles: есть в базовом списке с 'external' source. Пример 'https://nspd.gov.ru/cgk/map/38/tms/{z}/{x}/{y}.png' (TMS-паттерн)","Для GenDesign: можно встраивать эти тайлы в наши Mapbox/Leaflet как base/overlay. Авторизация через cookie session, но physic-вход работает для layer 235","Остальные полезные endpoints geoportal:","/api/geoportal/v1/page-search-settings?pageCode={code} — настройки поиска. Для marketAnalytics regex='^\\d{2}:\\d{2}:\\d{1,7}:\\d+$' — формат кадастрового номера"]}
{"type":"entity","name":"NSPD_PII_Leak_Apr26","entityType":"research","observations":["Security observation НСПД (26.04.2026): ПД в localStorage браузера.","После ESIA-входа SPA сохраняет в localStorage ключ NSPD_API_CLIENT_USER (~657 char) с данными текущего юзера (вероятно ID, name, email, expires и др.)","Парный ключ NSPD_API_CLIENT_USER_EXPIRES с ISO-датой истечения (обычно +30 мин от входа)","Риск (medium): любой скрипт на странице (в т.ч. 3rd-party вроде Yandex Metrika, или при XSS) может прочитать ПД. Best practice = хранить ПД только в HttpOnly cookie или server-side, не в localStorage","Yandex Metrika с _ym_uid + _ym_d + webvisor (96513913) работает на всех страницах включая профиль — теоретически может видеть PII в страницах","JWT в cookie HttpOnly — это ок, JS не видит. Но всё равно видно в DevTools Network и в cookie storage браузера","JWT response body в ответе /oauth2/token (в сыром plaintext): возвращает распакованные claims в JSON в ответе — display_name, email, family_name, given_name, middle_name, sub UUID, uid UUID, sid — всё это PII","Для GenDesign: прямая интеграция НСПД в наш продукт = ПЛОХО: брал бы слишком большую поверхность PII. Лучше server-side прокси с одним общим сервис аккаунтом (если будет выдан) или использовать CSV-датасеты (DataSource_Rosreestr_DealsCSV_Apr26) и WMTS-плитки без входа (если публичные слои работают без cookie)"]}
{"type":"entity","name":"NSPD_MarketAnalytics_FullArchitecture_Apr26","entityType":"api_spec","observations":["Дата: 26.04.2026 вечер. Полная архитектура /api/market-analytics/v1/* — раскрыта через debug-браузер с физик-аккаунтом ESIA.","АРХИТЕКТУРНЫЙ ПАТТЕРН: серверная сессия фильтров. Фронт сохраняет выбор фильтров на бэке через saveUserFilters → бэк хранит как userFiltersId (число). Все data-endpoints читают активные фильтры из этой сессии — поэтому body=`{}` или совсем без body.","FLOW (порядок вызовов):","1) GET /user-filters/userFilters → текущее состояние фильтров пользователя {userFiltersId, dataSourceSysName, filters[]}","2) Пользователь меняет фильтры в UI → собирающие вызовы /period, /region-list, /settlement, /cadastral-quarter (все POST с подсказками для следующего уровня)","3) Кнопка «Применить» → POST /user-filters/saveUserFilters с полным телом фильтров. Возвращает {userFiltersId: N}","4) После save фронт автоматически дёргает: graphEgrnHistogram, graphEgrnLineIndicator, graphEgrnCandleMedian, graphEgrnLineMedian, tableEgrn, geomDataForHeatMap, dataOnLegend, titleHeatMap","BODY saveUserFilters (правильный формат):","{ dataSourceSysName: 'fgisEgrn', filters: [","  {sysName:'dataSource', options:{value:'ФГИС ЕГРН', id:1}},","  {sysName:'calculationMethod', options:{value:'К предыдущему периоду', id:2}},","  {sysName:'areaRanges', options:{value:'от 25 до 40', id:1}},","  {sysName:'indicators', options:{value:'Индикатор цен квартальный', id:2, periodType:'Q'}},","  {sysName:'periodFrom', options:{value:'4 квартал 2025', sortOrder:32, isRemote:true}},","  {sysName:'periodTo', options:{value:'1 квартал 2026', sortOrder:33, isRemote:true}},","  {sysName:'federalDistrict', options:{valueList:[{code,title}], isSelectAll:true|false}},","  {sysName:'federalSubject', options:{valueList:[{code,title}], isSelectAll:true|false}},","  {sysName:'settlement', options:{valueList:[{code,title}], isSelectAll:false}}","]}","POSTПОДСКАЗКИ при выборе фильтров (важная деталь — все обёрнуты в params!):","POST /period body={params:{type:'M'|'Q'|'H'|'Y', dataSourceSysName:'fgisEgrn'}} → список доступных периодов с sortOrder","POST /region-list body={districtIds:[6]} → список субъектов в выбранных ФО (НЕ /federal-subject!)","POST /settlement body={subjectIds:[1,2,3,4]} → нас.пункты по subject id (массив до 4-5 за раз, фронт батчит)","POST /cadastral-quarter body={subjectIds:[1,2,3,4]} → массив кадастровых кварталов формата '02:55:020113'","DATA ENDPOINTS (body={} или GET, читают по userFiltersId из cookie):","POST /tableEgrn/fgisEgrn?page=0&count=10 → {headers:[{key,name,columnType}], bodyData:[{1:Территория, 2:значение_period1, 3:значение_period2}], meta:{page,count,totalCount}}","POST /fgisEgrn/geomDataForHeatMap → GeoJSON FeatureCollection. Координаты в EPSG:3857 (Web Mercator). 13 цветовых бакетов: <0.25, 0.25-0.5, 0.5-0.7, 0.7-0.85, 0.85-0.95, 0.95-1.0, 1.0_unchanged, 1.0-1.05, 1.05-1.15, 1.15-1.3, 1.3-1.5, 1.5-1.75, >1.75. MultiPolygon границы кадастровых кварталов с цветом по индикатору","GET /graphEgrnHistogram/fgisEgrn → {chartType:'histogramChart', data:[{title, indicatorValueCurrent:0.88, indicatorValuePrevious:1.12, period:'02.2026', percentValue:-21}]}","GET /graphEgrnLineIndicator/fgisEgrn → {chartType:'lineChartIndicator', data:[{title, indicatorValue:1.12, period:'01.2026', periodType:'Месяц'}, ...]}","GET /dataOnLegend/fgisEgrn → описание легенды теплокарты","GET /fgisEgrn/titleHeatMap → {title:'Индикатор цен ежемесячный по выбранной территории...'}"]}
{"type":"entity","name":"NSPD_OrgOnly_Endpoints_Apr26","entityType":"research","observations":["Дата: 26.04.2026. ⚠ КРИТИЧНОЕ ОТКРЫТИЕ — endpoints скрытые от physic-аккаунта (403 Forbidden):","GET /api/market-analytics/v1/graphEgrnCandleMedian/fgisEgrn — СВЕЧНОЙ график медианной АБСОЛЮТНОЙ цены сделок (₽/м²)","GET /api/market-analytics/v1/graphEgrnLineMedian/fgisEgrn — линия медианной АБСОЛЮТНОЙ цены сделок","Все остальные graph endpoints (Histogram, LineIndicator) возвращают только относительные индикаторы (текущий период / предыдущий = 0.88), а Candle/Line Median должны возвращать реальные ₽/м² по кадастровому кварталу.","Для physic (как у юзера сейчас) — 403 'Forbidden'. Проверено эмпирически в браузере 26.04.2026.","ГИПОТЕЗА: доступно для organisation-аккаунта (юрлицо в ESIA) или для аккаунтов с расширенным scope.","ЭКВИВАЛЕНТНОСТЬ ДАННЫХ: эти endpoints дублируют то, что мы уже получаем из CSV-датасета Росреестра (DataSource_Rosreestr_DealsCSV_Apr26) — медианные цены сделок по кадастровым кварталам. Только тут это онлайн-API с фильтрами по периоду/площади/нас.пункту, а CSV — сырые сделки покварталу.","ДЛЯ GenDesign: ничего не теряем. Используем CSV-датасет (per-deal сырые данные) + публичные индикаторы NSPD (относительная динамика) + dom.рф per-flat snapshot. Org-аккаунт NSPD — НЕ требуется."]}
{"type":"entity","name":"NSPD_DataValue_For_GenDesign_Apr26","entityType":"research","observations":["Дата: 26.04.2026. Конкретный value NSPD MarketAnalytics для GenDesign Plan A.","ИСТОРИЯ ДАННЫХ: 33 квартала (Q1 2018 — Q1 2026, 8 лет longitudinal)","ВРЕМЕННЫЕ РАЗРЕЗЫ: M (месяц), Q (квартал), H (полугодие), Y (год). Месячный показатель работает с лагом ~1-2 мес (на 26.04.2026 показывает 02.2026)","МЕТРИКА: индикатор цен — отношение текущего периода к базе/предыдущему/ГОГ. Безразмерное число (0.88 = -12% к предыдущему). Полезно для тренда, не для абсолютных значений","ГРАНУЛЯРНОСТЬ: до уровня кадастрового квартала (формат XX:YY:ZZZZZZ). Это в 100-1000 раз тоньше чем Росстат (агрегат по региону).","КОНКРЕТНЫЙ КЕЙС Свердл.обл, Екатеринбург, площадь 25-40 м², 02.2026 vs 01.2026: индикатор=0.88 (цены упали на 12%), предыдущий период 1.12.","ВЫГОДА для GenDesign:","1) Cross-validation цен сделок с Росреестра CSV — индикатор NSPD должен совпадать с (median_current_quarter / median_previous_quarter) из CSV","2) ВЕЛОСИТИ (sigma trend): тренд цен по конкретному кадастровому кварталу — для финмодели это хороший signal","3) ВЫБОР АНАЛОГОВ: GeoJSON-полигоны кадастровых кварталов с раскраской по индикатору → для участка пользователя автоматически найти кадастровые кварталы вокруг с похожей динамикой","4) WMTS-тайлы (через /api/aeggis/v4/235/wmts/{z}/{x}/{y}.png) можно встроить как base layer в Mapbox/Leaflet GenDesign","ПЛАН ИНТЕГРАЦИИ В Stage 2a:","Шаг A: ESIA-логин в headless Chrome (или через cookie из user-input) → получаем JWT в authAccessToken cookie","Шаг B: для каждого региона интереса (Свердл.обл, МО, Москва) сохраняем фильтры (saveUserFilters) и тянем geomDataForHeatMap → сохраняем GeoJSON в PostGIS как материализованное представление","Шаг C: cron 1×в сутки обновляем индикаторы по периоду и пересчитываем materialized views","Шаг D: для каждого участка пользователя — JOIN с PostGIS по геометрии → находим включающий кад.квартал → читаем индикатор","JURISDICTION: NSPD — государственный сервис Росреестра по 8-ФЗ. Использование физик-аккаунта легально как пользователя. ⚠ автоматизированный сбор через ESIA — серая зона. Лучше ОДНОРАЗОВО собрать с физик-аккаунта и кешировать локально.","ОГРАНИЧЕНИЯ:","1) physic-аккаунт через ESIA — доступ только для одного юзера, RPS-лимиты на сессию","2) JWT TTL=30 мин (refreshable). Для cron нужно либо хранить refresh_token, либо на каждом запуске re-auth через ESIA (что НЕ автоматизируется без обхода капчи)","3) Авторизация через ESIA подвержена captcha/2FA — недетерминирована для headless","4) absolute medians (Candle/Line Median) — 403, требуют org-аккаунт","5) Лимит на массовые запросы кадастровых кварталов: фронт батчит по 4-5 субъектов за раз — видимо есть soft-rate-limit"]}
{"type":"entity","name":"Domclick_DDF_Report_Nov2025","entityType":"research","observations":["Отчёт Домклик «Строительная отрасль на пороге структурной трансформации», представлен на Domclick Digital Forum, ноябрь 2025","Источник: PDF DDF_Потребность в недвижимости.pdf, 29 слайдов","Главный тезис: рынок входит в фазу СТРУКТУРНОЙ ТРАНСФОРМАЦИИ — количественный рост сменяется качественным; покупатели хотят УЛУЧШЕНИЯ характеристик, а не просто отдельной квартиры","Ключевые источники данных в отчёте: SberIndex (цены сделок и объявлений по регионам и 760 городам), Объединённое Кредитное Бюро (повторные ипотечники), Росстат (обеспеченность, население), Ипотечные витрины Сбербанка (миграция покупателей), НАШ.ДОМ.РФ (объёмы стройки)","ВАЖНО для GenDesign: SberIndex даёт цены СДЕЛОК и ОБЪЯВЛЕНИЙ по регионам и 760 городам — источник не использовался в DataSources_Analysis_Apr26, надо изучить (sberindex.ru, SberIndex PRO для городов)","Стратегический вывод: цели должны быть ДИФФЕРЕНЦИРОВАНЫ по регионам и КАЧЕСТВЕННЫ, а не количественны (33 м²/чел к 2030 / 38 м²/чел к 2036 — это нацели Указа 309 от 7 мая 2024)","5 ключевых сигналов для девелоперов: 1) Снижение доступности → переориентация на состоятельных покупателей, 2) 79% гэпа первичка/вторичка = качество, 21% = ставка, 3) Альтернативные сделки усложнились (с +19м² в 2019 до +9м² в 2025), 4) Повторные ипотечники теперь 37% выдач (vs 25% в 2020), 5) Только 19 регионов имеют демографический драйвер для стройки"]}
{"type":"entity","name":"Affordability_Trends_DDF_Nov2025","entityType":"research","observations":["Данные по доступности жилья из отчёта Domclick DDF (ноябрь 2025), для GenDesign Tile2 «По какой цене»","ДИНАМИКА ЦЕН РФ январь 2020 = 0%: первичка +142%, вторичка +104%, ЗП +101% к 2025","СТРУКТУРА ИПОТЕКИ — переориентация на новостройки: 2020-2023 первичка 29% / вторичка 71%; 9м2025 первичка 47% / вторичка 53% (рост ставок выгнал спрос с готового жилья)","ИНДЕКС ДОСТУПНОСТИ (м² для медианного работника при ипотеке 50% от ЗП, 20% взнос, 20 лет): первичка РФ стабильна 32.1 → 31.5 м² (ЗП +15, цены -23, ставки +7), вторичка обвалилась 37.7 → 22.8 м² (ЗП +15, цены -19, ставки -11)","В МОСКВЕ доступность ниже в 2 раза: первичка 23.2 м², вторичка 11.5 м²","ПРОГНОЗ: при снижении ставок будет ОБРАТНЫЙ переток с новостроек на готовое жильё → застройщикам надо готовиться к падению спроса на первичку","СРОК НАКОПЛЕНИЯ ВЗНОСА 20% на 65 м² (50% медианной ЗП на вклад): 2019 → 2025 РФ 2.3 → 6.2 года (×2.7)","ХУДШИЕ для накопления: Алтай 11.8 лет, Москва 7.8, Астраханская 7.7, Татарстан 7.4, Дагестан 7.3, Нижегородская 7.0, Краснодарский 6.9, СПб 6.8, Адыгея 6.7, Омская 6.7","ЛУЧШИЕ для накопления: ЯНАО 2.9, Саха 3.5, ХМАО 3.5, Псковская 3.6, Коми 3.8, Оренбургская 3.8, Архангельская 3.8, Карелия 4.0, Новгородская 4.0, Калужская 4.1","% работающих кто может накопить за 2 года: РФ 8.3%; ЛУЧШИЕ — Оренбургская 19.2%, ХМАО 18.4%, Коми 16.7%, Смоленская 14.1%, Красноярский 13.9%, Архангельская 13.6%, Тюменская 13.5%, Вологодская 13.3%, Калужская 13.0%, Курская 12.6%; ХУДШИЕ — Дагестан 3.5%, Нижегородская 5.0%, Татарстан 5.2%, Омская 5.7%, СПб 6.2%, Кировская 6.3%, Забайкальский 6.5%, Краснодарский 6.6%, Москва/Ленинградская 6.9%","ИНСАЙТ для GenDesign: Свердл.обл НЕ упомянута среди топов и хвостов — значит средние показатели по РФ. Использовать индекс доступности м² как один из факторов финмодели Tile2"]}
{"type":"entity","name":"PriceGap_Quality_vs_Rate_Nov2025","entityType":"research","observations":["Из отчёта Domclick DDF (ноябрь 2025): 79% разрыва цен первичка/вторичка по РФ — следствие КАЧЕСТВА жилья, а не разности ипотечных ставок","ЦЕНЫ 9м2025 (тыс ₽/м²) РФ: первичка 174, новая вторичка моложе 5 лет 161, вся вторичка 115. Гэп -34% общий = -27% качество + -7% ставка","МОСКВА: 357 / 342 / 308. Гэп -14% = -10% качество + -4% ставка","РЕГИОНЫ (без Москвы и СПб): 144 / 134 / 98. Гэп -32% = -25% качество + -8% ставка","КРИТИЧЕСКИЙ ИНСАЙТ: дисконт НОВОЙ вторички (моложе 5 лет) к первичке всего 7% по РФ. То есть НОВОСТРОЙКИ НЕ ТЕРЯЮТ В ЦЕНЕ при перепродаже после ввода — это чистый информационный сигнал для финмодели GenDesign (TestFit и rTIM этого не учитывают)","ДИСКОНТ ВТОРИЧКИ К ПЕРВИЧКЕ ВЫРОС с -20% (2019) до -34% (9м2025) по РФ","САМЫЙ БОЛЬШОЙ ДИСКОНТ (выгодные регионы для альтернативных сделок 'продал вторичку → купил первичку'): Астраханская -52%, Пермский -46%, Дагестан -43%, Хабаровский -43%, Башкортостан -43%, Иркутская -41%, Татарстан -40%, Свердловская -38%, ХМАО -38%, Тульская -38%","САМЫЙ МАЛЕНЬКИЙ ДИСКОНТ (вторичка дорогая): Псковская -9%, Москва -14%, Ставропольский -14%, Краснодарский -14%, Курская -15%, Орловская -16%, СПб -16%, Чувашия -16%, Архангельская -17%, Бурятия -18%","⭐ СВЕРДЛОВСКАЯ ОБЛ ВХОДИТ В ТОП-10 С САМЫМ БОЛЬШИМ ДИСКОНТОМ -38% — для жителя Екб альтернативная сделка ('продал вторичку — купил первичку') математически невыгодна по площади. Это объясняет почему в Екб все идут в первичку через ипотеку, а не через размен"]}
{"type":"entity","name":"AlternativeDeal_Trends_Nov2025","entityType":"research","observations":["Из Domclick DDF (ноябрь 2025): альтернативные сделки (продажа имеющейся вторички 45 м² → покупка первички через ипотеку) теряют эффективность","ДИНАМИКА для РФ при платеже 50% от медианной ЗП: 2019 → 2020 → 2021 → 2022-2024 → 9м2025 = 59 / 64 / 59 / 53 / 54 м²","Прирост площади: 2019 +19 м², 2020 +15 м², 2021 +8 м², 2022-2024 +9 м², 9м2025 +9 м² (теряется в 2 раза за 6 лет)","САМАЯ ВЫСОКАЯ ДОСТУПНОСТЬ (м² можно купить из 45 м² вторички): ЯНАО 93, Камчатка 86, Якутия 86, Архангельская 82, Бурятия 78, Псковская 78, Сахалин 76, Приморский 74, Оренбургская 72, Орловская 72","САМАЯ НИЗКАЯ ДОСТУПНОСТЬ: Астраханская 44, Алтай 47, Татарстан 49, Омская 50, Пермский 51, Башкортостан 52, Нижегородская 52, СВЕРДЛОВСКАЯ 55, Крым 56, Москва 56, СПб 58","⭐ В СВЕРДЛОВСКОЙ ОБЛ продав 45 м² вторички, купить можно 55 м² первички (28 вторичка + 28 ипотека). Прирост всего +10 м² — это ниже среднего РФ (+9 м² с большим разбросом)","ИНСАЙТ для GenDesign: финмодель должна учитывать что в Свердл.обл альтернативные сделки даются с трудом → клиент Prinzip это либо первая ипотека, либо иногородний (по slide 14 — Свердл.обл не упоминается среди магнитов миграции, значит почти всё локальное население)"]}
{"type":"entity","name":"RepeatedMortgage_Nov2025","entityType":"research","observations":["Из Domclick DDF (ноябрь 2025): доля повторных ипотечников выросла с 25% (2020) до 37% (9м2025)","9м2025: 20% берут повторно (нет непогашенных ипотек) + 17% берут 2+ ипотеку (есть непогашенные) = 37% всех повторных","2020: 10% повторно + 15% 2+ = 25%","2024: 18% повторно + 16% 2+ = 34%","ИНТЕРПРЕТАЦИЯ: квартиры всё больше продаются СОСТОЯТЕЛЬНЫМ покупателям, кого надо УБЕДИТЬ повторно улучшить жилищные условия. Source: Объединённое Кредитное Бюро","СЛЕДСТВИЕ для маркетинга Prinzip: customer persona 2025 ≠ first-time buyer; чаще upgrade-покупатель с продажей текущей квартиры. Финансово более готов, но требует большего качества (локация, класс, инфраструктура)","ИНСАЙТ для GenDesign: для финмодели и smart-unit-mix важно — в каждом районе доля повторных ипотечников может различаться. Если в Екб эта доля выше среднего РФ → таргетировать апгрейд-сегмент, более крупные/качественные квартиры. Если ниже → first-time, более доступные форматы"]}
{"type":"entity","name":"QualityShift_NewBuild_2021_2025","entityType":"research","observations":["Из Domclick DDF (ноябрь 2025): структурный сдвиг качественных метрик строящегося жилья 2021 → 2025","СРЕДНЯЯ ПЛОЩАДЬ КВАРТИРЫ ПАДАЕТ: РФ 50.1 → 48.3 м² (-1.8); Москва 56.0 → 53.4 м² (-2.6) — застройщики дробят квартиры из-за снижения доступности","ДОЛЯ БИЗНЕС+ЭЛИТНОГО КЛАССА РАСТЁТ: РФ 15% → 17% (+2пп); Москва 45% → 51% (+6пп) — переориентация на богатых","ПАРКОВОЧНЫЕ МЕСТА НА КВАРТИРУ РФ 0.18 → 0.25 (+0.07); Москва 0.40 → 0.35 (-0.06) — в РФ улучшают, в Москве ухудшают (земля дорогая)","ДОЛЯ НЕЖИЛОЙ ПЛОЩАДИ: РФ 16% → 19% (+3пп); Москва 27% → 25% (-2пп) — больше коммерции в регионах, в Москве и так высокая база","ДОЛЯ ПАНЕЛЬНЫХ СТЕН: РФ 4.8% → 5.4% (+0.6пп); Москва 4.3% → 1.2% (-3.1пп) — в РФ возвращается панель из-за себестоимости, в Москве — монолит/кирпич","СРЕДНЯЯ ЭТАЖНОСТЬ: РФ 18.7 → 19.2 (+0.5); Москва 25.0 → 30.9 (+5.9) — рост этажности, особенно в Москве","⭐ КЛЮЧЕВОЙ ВЫВОД: 'Из-за переориентации на богатых клиентов застройщики улучшают качественные характеристики, но СНИЖАЮТ ПЛОЩАДИ новых квартир'","ИНСАЙТ для Plan A Tile1 «Что строить» в GenDesign: при генерации концепции на участке default-параметры должны учитывать тренд — средние площади падают (-1.8 м² РФ за 4 года), доля бизнес+ растёт. Без поправки сгенерируем план образца 2021 года, который не продастся в 2025+"]}
{"type":"entity","name":"RegionGroups_BuildingDemand_Nov2025","entityType":"research","observations":["Из Domclick DDF (ноябрь 2025): 6 групп регионов по потребности в стройке МКД","ГРУППА 1 (9 регионов): ВЫСОКАЯ ПОТРЕБНОСТЬ в строительстве — Москва, Тюменская, ХМАО, ЯНАО, Крым, Калининградская и др. Драйверы: прирост населения вкл. трудовую миграцию, курортная недвижимость, невысокая обеспеченность м²/чел","ГРУППА 2 (11 регионов): УМЕРЕННАЯ ПОТРЕБНОСТЬ — СПб, ЛО, МО, Краснодарский и др. Нет оттока, популярность у иногородних, средняя обеспеченность","ГРУППА 3 (25 регионов): ТОЧЕЧНОЕ СТРОИТЕЛЬСТВО + РЕНОВАЦИЯ — Нижегородская, Приморский, Камчатский и др. Отток или стабильное население, низкая/средняя обеспеченность","ГРУППА 4 (26 регионов, САМАЯ БОЛЬШАЯ): ФОКУС НА РЕНОВАЦИИ — Владимирская, Кировская, Тульская, Псковская и др. Снижение населения, формально высокая обеспеченность, но СТАРЫЙ ЖИЛИЩНЫЙ ФОНД","ГРУППА 5 (3 региона): РЕНОВАЦИЯ + АРЕНДНОЕ ЖИЛЬЁ — Амурская, Архангельская, Иркутская. Снижение населения, старый фонд, крупные предприятия нуждаются в жилье для работников","ГРУППА 6 (11 регионов): ФОКУС НА ИЖС — Северный Кавказ (Дагестан, Чечня, Ингушетия, Каб.-Балкария, Кар.-Черкессия, Адыгея), Республика Алтай, Тыва, Бурятия, Калмыкия, Крым (частично). Высокая доля сельского населения, ИЖС > МКД","ГДЕ СВЕРДЛОВСКАЯ ОБЛАСТЬ: в отчёте явно НЕ названа в группе 1-2, но имеет высокую площадь стр-ва (1.4 м²/чел) при падающем населении (-3.8 до 0%) — попадает в группу 3 ТОЧЕЧНОЕ СТРОИТЕЛЬСТВО + РЕНОВАЦИЯ","СТРАТЕГИЧЕСКИЙ ВЫВОД: только 20 регионов (группы 1+2) нуждаются в БЫСТРОМ увеличении жилого фонда. Остальные 65 — реновация, ИЖС или арендное жильё. Federal-уровень должен дифференцировать поддержку, а не выдавать одинаковую льготную ипотеку всем"]}
{"type":"entity","name":"DemandIndex_Domclick_Nov2025","entityType":"research","observations":["Из Domclick DDF (ноябрь 2025): 'Индекс востребованности строительства жилья (МКД) в регионе' — композитный рейтинг 81 региона","ФАКТОРЫ ИНДЕКСА: 1) обеспеченность м²/чел на 01.01.2025; 2) доля нового жилья (введено 2019-2024); 3) динамика численности населения региона за 5 лет; 4) динамика населения регионального центра за 5 лет; 5) размер регионального центра; 6) доля сельского населения; 7) доля покупателей квартир из 'чужих' регионов; 8) доля населения способного накопить взнос 20% за 2 года; 9) доля населения которому доступна альтернативная сделка (продажа 45 м² → покупка первички); 10) отношение распроданности к стройготовности на 01.10.2025","ТОП-10 (высокая+умеренная востребованность, 31 регион всего): #1 Севастополь, #2 ХМАО, #3 Ставропольский, #4 Хабаровский, #5 Красноярский, #6 Бурятия, #7 Москва, #8 ЯНАО, #9 Тюменская, #10 Камчатка","ХВОСТ-10: #81 Астраханская, #80 Белгородская, #79 Кар.-Черкессия, #78 Липецкая, #77 Пензенская, #76 Тамбовская, #75 Сахалинская, #74 Рязанская, #73 Сев.Осетия, #72 Томская","СВЕРДЛОВСКАЯ ОБЛ — место в индексе НЕ ПУБЛИКУЕТСЯ в отчёте (показаны только топ-10 и хвост-10), но регион не в топ-10 и не в хвосте → средняя или ниже-средней востребованность","ИНСАЙТ для GenDesign: Site Finder может реплицировать аналогичный composite-score (10 факторов выше) на уровне муниципалитетов / кадастровых кварталов внутри Свердл.обл — это уникальный data-product, ЕРЗ и rTIM такого не делают","10 ФАКТОРОВ — почти все вычисляются из наших уже найденных источников: Росреестр CSV (сделки, доступность), ДОМ.РФ (обеспеченность через flatCount, доля нового жилья, распроданность через ready-construction), Росстат (демография, сельское население), Ипотечные витрины Сбербанка (миграция покупателей — нет у нас доступа, но можно прокси через ДомКлик)"]}
{"type":"entity","name":"Regional_Migration_Buyers_Nov2025","entityType":"research","observations":["Из Domclick DDF (ноябрь 2025): доля покупателей квартир в новостройках из ДРУГИХ регионов за 9м2025","Источник: Ипотечные витрины Сбербанка","РФ среднее: 19% покупателей не из своего региона","МАГНИТЫ МИГРАЦИИ (>20%): Крым 56%, Калининградская 37%, Краснодарский 36%, Москва 31%, СПб 26%, Ленинградская 25%, Новосибирская 24%, Тюменская 23%, Ставропольский 22%, Московская 19%","ЗАМКНУТЫЕ РЫНКИ (<10%): Алтайский 6%, Кемеровская 7%, Пермский 7%, Удмуртия 8%, Башкортостан 9%, Пензенская 10%, Челябинская 11%, Иркутская 11%, Омская 11%, Оренбургская 11%","СВЕРДЛОВСКАЯ ОБЛ — НЕ в топ-10 магнитов и НЕ в топ-10 замкнутых. Скорее всего среднее по РФ ~10-15% иногородних покупателей. Драйвер магнитизма — миграция ХМАО/ЯНАО → Екб (северяне выходящие на пенсию)","ИНСАЙТ для Prinzip: в маркетинге учесть что 10-15% покупателей могут быть из ХМАО/ЯНАО/Курганской — таргет-кампании в этих регионах через ВК/Telegram могут быть эффективны","ИНСАЙТ для Site Finder: миграционная доля = +1 фактор скоринга для участков. Города-магниты держат премию к цене, замкнутые рынки — дисконт"]}
{"type":"entity","name":"Sverdlovsk_Profile_DDF_Nov2025","entityType":"research","observations":["Сводка по Свердловской области из отчёта Domclick DDF (ноябрь 2025) — для GenDesign Discovery","ДИНАМИКА НАСЕЛЕНИЯ 2025 vs 2020: -1% до -3.8% (в группе слабого падения, не в худших и не в растущих)","ДОЛЯ СЕЛЬСКОГО НАСЕЛЕНИЯ: 14% (один из самых низких в РФ — урбанизированный регион, среднее РФ 25%)","ОБЕСПЕЧЕННОСТЬ м²/чел: НЕ В ТОП-10 ни хвоста ни головы — средние ~25-32 м²/чел","ПЛОЩАДЬ СТРОЯЩИХСЯ МКД НА 1 ЖИТЕЛЯ: 1.4 м²/чел — ВЫСОКАЯ (top-10 РФ, среднее РФ 0.8 м²/чел)","ИЗМЕНЕНИЕ ОБЪЁМА СТРОЙКИ vs 2019: НЕ в топ-10 роста и НЕ в топ-10 падения, среднее РФ +11.3% — стабильно строит","ДИСКОНТ ВТОРИЧКИ К ПЕРВИЧКЕ: -38% (8-е место в РФ среди регионов с самым большим дисконтом, РФ среднее -34%)","АЛЬТЕРНАТИВНАЯ СДЕЛКА: продав 45 м² вторички, можно купить 55 м² первички (28 вторичка + 28 ипотека). Прирост +10 м² — НИЖЕ среднего РФ (+9 м² с разбросом)","ЕКАТЕРИНБУРГ как региональный центр: входит в группу 'снижение населения области + рост рег.центра' (slide 25, явно подписан на графике) — типичный паттерн для крупного регионального центра","ЕКАТЕРИНБУРГ + ПРИГОРОДЫ: рост и центра и пригородов (slide 26)","МИГРАЦИЯ ПОКУПАТЕЛЕЙ: НЕ в топ-10 магнитов и не в топ-10 замкнутых рынков, среднее РФ ~15-20% иногородних","ИНДЕКС ВОСТРЕБОВАННОСТИ СТРОЙКИ: НЕ в топ-10 и не в хвосте","ИТОГО ПРОФИЛЬ: Свердл.обл = ТИПИЧНЫЙ КРУПНЫЙ ИНДУСТРИАЛЬНЫЙ РЕГИОН с высокой стройкой при умеренно падающем населении, но Екб ABSORBS внутрирегиональную миграцию + северян ХМАО/ЯНАО → концентрация спроса в самом Екб и пригородах","СТРАТЕГИЧЕСКОЕ ОТНЕСЕНИЕ К 6 ГРУППАМ: вероятно Group 3 (точечное стр-во + реновация) или граница Group 1-3","СЛЕДСТВИЕ для Prinzip: фокус на КАЧЕСТВЕ (не количестве), таргет апгрейд-аудитории Екб + сегмент 'покупатели с северов'"]}
{"type":"entity","name":"Rosreestr_DealsCSV_Loaded_Prod_Apr26","entityType":"event","observations":["Дата: 26.04.2026 вечер. ВЕХА: dataset_СДЕЛКИ Росреестра залит на ПРОД в PostgreSQL+PostGIS впервые.","СКАЧАНО: 7 кварталов (2024 Q3 — 2026 Q1) из https://rosreestr.gov.ru/data-sets/. Размер ZIP ≈146 MB, распакованных CSV ≈1.0 GB.","УТОЧНЕНИЕ ГРАФА: в DataSource_Rosreestr_DealsCSV_Apr26 было указано '9 кварталов 2024-2026' — НЕВЕРНО. На самом деле Росреестр НЕ опубликовал dataset_СДЕЛКИ за Q1 и Q2 2024 (в их папках только КАДАСТРСТОИМОСТЬ). Первый доступный квартал: 2024 Q3.","ОСОБЕННОСТЬ URL: имена файлов/папок на сервере в кодировке Windows-1251 (НЕ UTF-8). Корректные URL: https://rosreestr.gov.ru/data-sets/{Q}%20%EA%E2%E0%F0%F2%E0%EB%20{YYYY}%E3./dataset_%D1%C4%C5%CB%CA%C8_r-r_01-92_y_{YYYY}_q_{Q}.csv.zip. Для листинга обязательно Referer: https://rosreestr.gov.ru/data-sets/ (иначе 403)","СРАВНЕНИЕ сепараторов: 2024 Q3 = ';' и имя файла dataset_СДЕЛКИ_r_all_q_3.csv (без разбивки по регионам в имени). 2024 Q4+ = '~' и имя dataset_СДЕЛКИ_r-r_01-92_y_YYYY_q_N.csv. Различие ПРИНЦИПИАЛЬНО для ETL — парсер должен знать оба.","ИТОГОВЫЕ ЦИФРЫ НА ПРОДЕ: 4 975 398 строк-агрегатов, 7 581 266 фактических сделок (с учётом deal_count), 296 040 сделок Свердловской обл. Размер БД: 1.8 GB (deals 1.1 GB + MV 305 MB + индексы)","РАСПРЕДЕЛЕНИЕ ПО КВАРТАЛАМ (сделки РФ / Свердл.обл): 2024Q3 1.108M/40K, 2024Q4 1.265M/48K, 2025Q1 877K/35K, 2025Q2 991K/38K, 2025Q3 1.111M/45K, 2025Q4 1.329M/52K, 2026Q1 898K/37K","СХЕМА PG: rosreestr_deals — partitioned BY RANGE(period_start_date) на 7 квартальных партиций (rosreestr_deals_2024q3 … rosreestr_deals_2026q1). Индексы: (region_code, quarter_cad_number), BRIN(period_start_date), (doc_type) WHERE in ('ДКП','ДДУ'), (realestate_type_code). PRIMARY KEY (id, period_start_date) — из-за партиционирования.","ОБОЙДЕННЫЕ DATA QUALITY ПРОБЛЕМЫ (важны для cron-синка): 1) deal_price бывает битым с десятками цифр → сделали NUMERIC без precision, фильтр на INSERT 'BETWEEN 100000 AND 1e10'. 2) year_build бывает датой '09.07.1988' → регекс ~ '^[12][0-9]{3}$', иначе NULL. 3) wall_material_code бывает multi-value '\\\"code1;code2\\\"' → TEXT вместо VARCHAR(15). 4) area бывает абсурдным (>1e8) → NUMERIC без precision, фильтр 'BETWEEN 5 AND 1000' в MV. 5) region_code бывает NULL → WHERE region_code IS NOT NULL. 6) в Q1 2026 потеряли ~5 строк (похоже на csv-quoting issues, <0.001%)","MATERIALIZED VIEWS созданы 3 шт:","  • rr_agg_cad_quarter (216 MB) — (region, cad_quarter, period, doc_type, area_bucket) → deals_count, p10/median/p90 price_per_sqm, mean. Ареа-бакеты: lt25, 25-40, 40-60, 60-90, 90-150, gt150 (как в NSPD)","  • rr_agg_region (680 KB) — (region, period, doc_type, realestate_type) → deals_count, percentiles. Для Ural-dashboard в prinzipevent.ru/analytics","  • rr_agg_settlement (88 MB) — (region, settlement, period, doc_type, realestate_type) → percentiles + distinct_cad_quarters. Для ГОРОД-tab Екб","REFRESH время: полный build всех 3 MV ~40 сек на проде (2 vCPU). Для Discovery этого хватит — REFRESH вручную или раз в квартал после заливки нового CSV","ВАЛИДАЦИЯ НА ПРОДЕ (smoke-test):","  Екатеринбург КВАРТИРЫ Q1 2026: ДДУ 1 153 сделки median 160 645 ₽/м² (p10=113K, p90=232K, 77 кад.кварталов); ДКП 7 700 сделок median 121 961 ₽/м² (p10=69K, p90=185K, 703 кад.квартала). Гэп ДКП→ДДУ = -24% (близко к Domclick DDF 'РФ -34%')","  Свердл.обл ДДУ динамика по кварталам (median ₽/м²): 2024Q3=38K → 2024Q4=43K → 2025Q1=54K(2 сделки!) → 2025Q2=141K → 2025Q3=140K → 2025Q4=149K → 2026Q1=149K. ДО середины 2025 ДДУ-данные НЕ ПОЛНЫЕ (Q1 2025 = всего 2 сделки в области — явный lag публикации). ДКП вроде ровный рост 63K→63K→66K→66K→70K→75K→79K ₽/м² — выглядит и реалистично","ДОСТУП НА ПРОДЕ: localhost:15432 через SSH-туннель до gendesign@46.173.16.127 (порт 5432 в контейнере docker-compose.prod.yml проброшен на 127.0.0.1:5432 на VPS). Данные живут в docker volume gendesign_postgres_data — переживут redeploy","АРТЕФАКТЫ В РЕПО: data/sql/01_schema_rosreestr_deals.sql, 02_load_all_quarters.sh (поддерживает PG_HOST + PGPASSWORD ENV для remote/tunnel), 03_materialized_views.sql. data/raw/ — 7 распакованных CSV (в .gitignore должны быть)","СЛЕДУЮЩИЕ ШАГИ: 1) добавить data/raw/ в .gitignore (нельзя коммитить 1 GB CSV); 2) сконвертировать 01_schema в Alembic-миграцию (не срочно); 3) cron quarterly_rosreestr_sync на VPS — проверяет listing 16-го числа второго месяца после квартала; 4) ИНТЕГРАЦИЯ с NSPD GeoJSON для spatial join 'участок узера → кадастровый квартал → агрегат из rr_agg_cad_quarter'; 5) FastAPI router /api/v1/analytics/{ural|ekb|prinzip}","ОГРАНИЧЕНИЕ ДЛЯ Prinzip вкладки: связь 'сделки Росреестра → застройщик' НЕ ПРЯМАЯ. Нужен JOIN через quarter_cad_number → NSPD/ПКК polygon → ДОМ.РФ /сервисы/api/kn/flats?developers=6208_0&regions=66 для Prinzip-жк в этом кад.квартале. Эта связь — next sprint."]}
{"type":"entity","name":"DomRF_Analytics_Loaded_Prod_Apr26","entityType":"event","observations":["Дата: 26.04.2026 вечер. ВЕХА: ДОМ.РФ portal-analytics dashboard залит на ПРОД в PostgreSQL.","ИСТОЧНИК: https://xn--80az8a.xn--d1aqf.xn--p1ai/portal-analytics/api/* (наш.дом.рф). 6 endpoints, snapshot от 26.04.2026.","СКАЧАНО:","• /dictionaries/regions — 89 регионов в 9 ФО","• /dictionaries/developers — 2 734 застройщика (в т.ч. PRINZIP id=6208_0)","• /dashboard/by-region — 89 регионов с разбивкой по комнатности (ONE/TWO/THREE/FOUR)","• /dashboard/by-flat-area — 8 area-buckets × 4 комнатности = 40 рядов (FROM_0_TO_25 … FROM_100)","• /dashboard/by-developer — 2 734 застройщика с разбивкой по комнатности (~11K рядов)","• /dashboard/by-room-count — РФ totals (sanity check, не храним)","✅ ПОКРЫТИЕ: 2.4M квартир в строительстве МКД / 118.7M м² по всей РФ. Свердл.обл: 115 205 квартир / 5.67M м² (52% однушки, 35% двушки, 12% трёшки, 1% 4+).","⚠ ОГРАНИЧЕНИЕ: на страницах 'долевое_строительство' и 'показатели_жилищного_строительства' фильтр ?regionId=X ИГНОРИРУЕТСЯ — сервер всегда отдаёт РФ-агрегат. Разбивка по регионам идёт ЧЕРЕЗ by-region (не by-room-count). Для Prinzip-специфичных срезов по Свердл.обл нужны другие endpoints (не проверяли) или /сервисы/api/kn/flats?regions=66&developers=6208_0 с Basic-auth.","ОБХОД WAF: ServicePipe блокирует прямой curl (JS-challenge). Решение: использовали chrome-devtools MCP get_network_request с responseFilePath — берёт response ПРЯМО ИЗ БРАУЗЕРНОГО КАША, обходя WAF/cookies/mixed-content. Для обновления snapshot'а нужен открытый браузер и chrome-devtools MCP. Для production cron — Playwright/Selenium в headless режиме (пройдёт ServicePipe через JS-VM).","СХЕМА PG (5 таблиц):","• domrf_regions(region_id, region_name, federal_district) — 89","• domrf_developers(developer_id TEXT, developer_name) — 2 734. PK = developer_id (формат '6208_0' или '0_14583')","• domrf_snapshots(snapshot_date PK, fetched_at, notes)","• domrf_region_aggregates(region_id, snapshot_date, room_count_type, flat_count, area_sqm, percent) — 89×5=445 (храним TOTAL+ONE/TWO/THREE/FOUR), 439 по факту (у некоторых регионов нет FOUR)","• domrf_flat_area_distribution(snapshot_date, region_id, area_bucket, room_count_type, flat_count, area_sqm, percent) — 40 рядов (region_id=0 = РФ)","• domrf_developer_aggregates(developer_id, snapshot_date, region_id, room_count_type, flat_count, area_sqm, percent) — 11 063 рядов (region_id=0 = РФ)","КЛЮЧЕВЫЕ ЦИФРЫ PRINZIP (id=6208_0): 814 квартир / 31 040 м². Квартирография: 614 однушек (75%, 18 922 м²), 156 двушки (19%), 22 трешки (3%), 22 4+комн. (3%). Сравнение со Свердл.обл в целом (52/35/12/1) — PRINZIP сильно смещён в однушки (75% vs 52% benchmark).","ТОП-10 РФ застройщиков (по flat_count): Самолет 110 568 / ПИК 84 007 / DOGMA 66 308 / ТОЧНО 46 870 / Setl Group 44 817 / ФСК 39 888 / ССК 35 547 / ЮгСтройИнвест 35 471 / ЛСР 33 933 / Брусника 30 106","СВЕРДЛ.ОБЛ КОНКУРЕНТЫ PRINZIP в реестре: Атомстройкомплекс (5772_0), ЛСР (5653_0), КОРТРОС (5654_0), Стройтэк (4647_0), УГМК-ЗАСТРОЙЩИК (5786_0), Брусника (5791_0), СЗ ЛСР.ОСТРОВ (0_23239), Стройтэкс (5973_0). Отношение PRINZIP к Свердл.обл не хранится напрямую в ДОМ.РФ dashboard агрегатах (их by-region API не возвращает dev-детали), но видно что в Свердл.обл 115K квартир, PRINZIP 814 = ~0.7% рынка (маленький игрок)","СТРУКТУРА ПЛОЩАДЕЙ РФ (benchmark): 0-25м² 6%, 25-35м² 17%, 35-45м² 30% (мода!), 45-55м² 14%, 55-70м² 20%, 70-85м² 8%, 85-100м² 3%, >100м² 2%. Медиана ~45 м².","АРТЕФАКТЫ В РЕПО: data/sql/10_schema_domrf.sql, data/sql/11_load_domrf.py (Python loader через docker run psql), data/sql/upload_server.py (был использован но заблокирован Mixed-Content). data/raw/domrf/*.json — 6 файлов сырых (в .gitignore)","СЛЕДУЮЩИЕ ШАГИ: 1) искать endpoints с regionфильтром для разбивки по застройщикам в конкретном регионе (возможно другая страница или /flats/map?regions=66&developers=6208_0 с Basic MTpqd2U=); 2) /сервисы/api/kn/flats?regions=66 — поквартирный прайс-лист Свердл.обл (~24K квартир); 3) ДОМ.РФ ready-construction (sold%/ready%) — velocity для Tile3 Plan A; 4) ЦБ ипотека (Tab11) — желательно иметь отдельной таблицей; 5) MV «top_developers_in_region» после появления регионного среза"]}
{"type":"entity","name":"DomRF_XLSX_PDF_Snapshot_Loaded_Apr26","entityType":"event","observations":["Дата: 26.04.2026 вечер (продолжение). ВЕХА: 7 файлов ДОМ.РФ (XLSX+PDF), скачанных юзером вручную через кнопку 'Скачать' на наш.дом.рф, залиты на ПРОД. Расширяет JSON-dashboard данные из DomRF_Analytics_Loaded_Prod_Apr26.","ИСТОЧНИКИ (C:\\Users\\user\\Downloads\\):","• developer_rf_26-04-2026.xlsx — 2746 застройщиков (2563 уникальных после дедупа), поля Площадь/Разрешения/Дома/Квартиры/доля%","• escrow_rf_26-04-2026.xlsx — 28 банков, эскроу-показатели (дома/разрешения/площадь/застройщики/регионы)","• guaranty_26-04-2026.xlsx — 99 территорий (РФ + 8 ФО + 89 регионов) с разбивкой всего/214-ФЗ/эскроу/ПП480","• housing_info_26-04-2026.pdf — РФ-разбивка по механизмам (все/эскроу/фонд/без) + топ-10 регионов + топ-10 городов + план ввода 2026-2035","• sold_out_info_26-04-2026.pdf — реализация МАРТ 2026 (отчёт от 11.04.2026), РФ итог + 8 регионов + разбивка по году ввода + распределение по % реализации","• Квартирография_жилищного_строительства_26-04-2026.pdf — топ-20 застройщиков + топ-20 регионов (дублирует JSON dashboard данные, не загружали отдельно)","• mortgage_rates_19-04-2026.pdf — ставки топ-20 банков на 19.04.2026","СХЕМА PG (9 таблиц + 4 индекса):","• domrf_developers_full(snap, name, area_th_sqm, permits, houses, flats, market_share_pct) — 2 563 ряда","• domrf_escrow_banks(snap, bank_name, houses, permits, area_th_sqm, devs, regions) — 28 рядов","• domrf_guaranty_regions(snap, territory, level, total_*, fz214_*, escrow_*, pp480_*) — 99 рядов, level∈{rf,fo,region}","• domrf_housing_summary(snap, territory, level, mechanism, devs, permits, decls, houses, area, flats) — 58 рядов, mechanism∈{all,escrow,fund,no_attraction}","• domrf_planned_commissioning(snap, plan_year, escrow_th, fund_th, no_attr_th, total_th) — 10 лет (2026-2035)","• domrf_sold_out(snap, territory, total/sold/unsold/not_open _area+%, avg_price_per_sqm, attracted_funds_mln) — 9 рядов","• domrf_sold_out_by_year(snap, plan_year, total, pct, sold/unsold/not_open %) — 6 рядов (2026..2031+)","• domrf_sold_out_by_progress(snap, progress_bucket, total, pct, sold/unsold within %) — 6 корзин (not_open..80+)","• domrf_mortgage_rates(snap, bank, primary_rate, secondary_rate, refinance_rate, note) — 20 банков","КЛЮЧЕВЫЕ ЦИФРЫ ПОСЛЕ ЗАГРУЗКИ:","• PRINZIP в полном реестре: 31.04 тыс м² / 2 дома / 814 квартир / доля рынка РФ 0.026% (совпадает с JSON dashboard)","• Свердл.обл guaranty: 5654 тысм² / 179 застройщиков (178 на эскроу) — НОВОЕ: теперь есть число застройщиков по каждому региону (раньше были только объёмы)","• Свердл.обл sold_out: 5686 тысм² / продано 29% / не продано 54% — НИЗКИЙ sold_rate (Москва 47%, СПб 40%) → структурная проблема рынка в РФ (по среднему 31% продано), в Свердл.обл хуже среднего","• РФ sold_out: 119M м² / 31% продано / 45% не продано / 24% продажи не открыты. Средняя цена МКД РФ: 216 316 ₽/м². Объём привлечённых средств: 7.95 трлн ₽","• ПРОГНОЗ ВВОДА: 2026 = 37.9M м² → 2027 = 35.4M → 2028 = 26.5M → 2029 = 11.0M → 2030 = 4.3M (РЕЗКОЕ ПАДЕНИЕ ПОСЛЕ 2028)","• ТОП-5 БАНКОВ ЭСКРОУ: Сбер 72.8M м² (61% рынка!), ВТБ 17.4M, ДОМ.РФ 13.3M, Альфа 5.7M, ГПБ 2.6M. СБЕР ДОМИНИРУЕТ эскроу-рынком","• СТАВКИ ИПОТЕКИ 19.04.2026: средневзвешенная 19.90% первичка / 19.59% вторичка / 18.81% рефинанс. Самые низкие: Кубань Кредит 16.4%, Т-Банк 16.9%, Уралсиб 17.89%, Металлинвест 18.1%. Самые высокие: Сбер 20.2%, Совком 19.99%, ВТБ 19.9%","НОВЫЕ СРЕЗЫ КОТОРЫХ НЕ БЫЛО:","1) ЧИСЛО ЗАСТРОЙЩИКОВ ПО КАЖДОМУ РЕГИОНУ (из guaranty.xlsx) — раньше этого не было в JSON dashboard. Свердл.обл 179, Москва ~1057 (ЦФО), Краснодарский …","2) РАСПРЕДЕЛЕНИЕ ПО МЕХАНИЗМАМ (эскроу/фонд/без) — в РФ 96% площади на эскроу, 1% фонд, <1% без. Активных застройщиков 4 336 всего","3) РЕАЛИЗАЦИЯ sold/unsold (Tile3 velocity) — был отложен в роадмапе как 'TODO ready-construction', теперь есть на уровне регионов/года-ввода/бакета-реализации","4) СРЕДНИЕ ЦЕНЫ ПЕРВИЧКИ РФ (216 316 ₽/м² на март 2026) — бенчмарк для Tile2 (раньше были только Росреестр ddu_median по кад.кварталам)","5) СТАВКИ ПО БАНКАМ — отдельный срез который не был в dashboard JSON, полезен для финмодели","6) ПЛАН ВВОДА ДО 2035 ГОДА — видно резкое падение после 2028 года (соответствует Domclick DDF '27 регионов строят меньше')","ОГРАНИЧЕНИЕ: все данные — РФ итоги или топ-N. НЕТ связи 'застройщик × регион' в PDF/XLSX — для Prinzip-специфичных срезов по Свердл.обл нужен /сервисы/api/kn/flats?regions=66&developers=6208_0 с Basic-auth (не выкачано ещё)","ОБХОД WAF: в этот раз юзер сам скачал файлы через кнопку в браузере (XLSX/PDF экспорт на портале), это обошло WAF без chrome-devtools MCP. Для cron — нужен Playwright (эмулировать клик + download)","АРТЕФАКТЫ: data/sql/20_schema_domrf_extras.sql, data/sql/21_load_domrf_extras.py. Исходные файлы остаются в C:\\Users\\user\\Downloads\\ (не копируем в репо — user-private)"]}
{"type":"entity","name":"DomRF_Playwright_Scraper_Apr26","entityType":"infrastructure","observations":["Дата: 26.04.2026 вечер. Продакшн-скрейпер ДОМ.РФ на Playwright + headless Chromium","АРТЕФАКТ: data/sql/30_scrape_domrf.py — проходит ServicePipe WAF, собирает все /api/* JSON ответы с 12 страниц наш.дом.рф. Поддерживает --headed для отладки, --page <name> для одной секции","РАБОТАЕТ БЕЗ ОТКРЫТОГО БРАУЗЕРА: Playwright сам запускает Chromium в headless режиме, проходит JS-challenge ServicePipe","ПОКРЫТИЕ: из 12 страниц успешно скачал 7 (launch / share_construction / escrow / sold_ready / quartirografia / commissioning / mortgage_stats)","НЕ СКАЧАЛОСЬ (5 страниц пустых): housing, housing_dev, realization, mortgage_rates, stat_series. Причина: эти страницы делают API-вызовы только при user-interaction (клики на фильтры/вкладки) или их инициируют из сервис-воркера. Требуется расширить скрейпер page-specific взаимодействиями (клик на вкладки, выбор фильтров)","СКАЧАНА СТАТИСТИКА: 64 JSON-файла, ~1.95 MB сырых данных в data/raw/domrf_full/<section>/","РАСШИРЕНИЕ size=15 → size=1000: скрейпер автоматически делает второй fetch с size=1000 для всех endpoint'ов где был size=15 — получаем все регионы/застройщики вместо топ-15","ИСПОЛЬЗОВАНИЕ ДЛЯ cron: pip install playwright + python -m playwright install chromium. Готов использоваться на VPS Beget — нужен ~300 MB для Chromium"]}
{"type":"entity","name":"DomRF_Scraped_Loaded_Prod_Apr26","entityType":"event","observations":["Дата: 26.04.2026 вечер. Нормализованные данные из Playwright-скрейпера загружены в 10 НОВЫХ PG-таблиц на ПРОДЕ","СХЕМА: data/sql/31_schema_domrf_full.sql + 32_load_domrf_full.py","НОВЫЕ ТАБЛИЦЫ (10 шт, не пересекаются с существующими):","• domrf_launch_top (1 410 рядов) — топ-N застройщиков/регионов/городов/ФО по запускам (app) и вводу (rnv). dim_type × metric_type × entity_id","• domrf_launch_obj_class (4) — разбивка запусков/ввода по классу (Типовой/Комфорт/Бизнес/Элитный)","• domrf_launch_monthly (75) — временной ряд год+месяц → app/rnv (2020-2026)","• domrf_sold_ready_index (1) — РФ итог на март 2026: 118.88M м² всего, продано 30.91%, готовность 43.1%, soldReady 71.73%","• domrf_sold_ready_breakdown (2 660 рядов) — распроданность по ФО/регионам/городам/застройщикам с squareSum/soldPerc/readyPerc/soldReadyPerc","• domrf_sold_ready_dynamics (300) — динамика 4 индикаторов (squareSum/sold%/ready%/soldReady%) по годам и месяцам с 2020 по 2026","• domrf_project_finance (99) — долевое стр-во по федэкроу/214-ФЗ/ПП480 для РФ+ФО+регионов (rns_cnt, dev_cnt, liv_sq_amt + guaranty_escrow_*)","• domrf_commissioning (1) — фактический ввод по регионам (multifamily/private)","• domrf_mortgage_dashboard (1) — ОБЩАЯ СТАТИСТИКА ИПОТЕКИ РФ: 68 714 кредитов (22 595 первичка + 46 119 вторичка), средние ставки: ПЕРВИЧКА 6.83% (субсидированная!), ВТОРИЧКА 12.95%","• domrf_mortgage_details (2) — разбивка по валюте RUB/OTH (средний кредит 4.22 млн ₽, 23.8 лет срок, просрочка 1.02%)","КЛЮЧЕВЫЕ ИНСАЙТЫ:","1) ТОП-5 РФ ПО ЗАПУСКАМ 2026: DOGMA 492K м², Setl Group 427K, Самолет 360K, ФСК 257K, ССК 257K. ПИК (лидер строительства) 6-е место по НОВЫМ запускам — значит доводят имеющееся, не расширяются","2) СВЕРДЛОВСКАЯ ОБЛ ЗАПУСКИ 2026: 492 478 м² (6-е место в РФ после МО/ЛО/Москвы/Краснодар/Башкортостан)","3) СВЕРДЛОВСКАЯ РАСПРОДАННОСТЬ (март 2026): 5 686 тыс м² / продано 29.04% / готовность 36.08% / soldReady 80.47%. soldReady > 80% = хороший баланс между продажами и стройкой (не затоварены)","4) РЕЙТИНГ ФО ПО soldReady%: ЦФО 84.4%, СЗФО 80.6%, ПФО 71.8%, ДФО 71.6%, СибФО 63.0%, СКФО 36.0% (плохо!), УрФО 66.4%, ЮФО 59.4%. СКФО строит быстро (ready 47.9%) но продаёт медленно (sold 17.2%)","5) КЛАСС ЖИЛЬЯ ПО ЗАПУСКАМ (м²): Типовой 1.965M, Комфорт 6.929M (ЛИДЕР!), Бизнес 1.340M, Элитный 326K. Комфорт = 67% всех запусков","6) СВЕРДЛ.ОБЛ PROJECT FINANCE: 266 разрешений на строительство / 179 застройщиков (178 на эскроу) / 5.65M м²","7) КЛЮЧЕВОЕ: СРЕДНЯЯ СТАВКА ПЕРВИЧКИ в РФ = 6.83% (субсидированная эскроу-ипотека). ВТОРИЧКа 12.95% — это средний реальный кредит (не рыночный 19.59% из mortgage_rates), то есть много льготных категорий (семейная 8%, IT 6% ит.д.)","НЕ СКАЧАНО (5 страниц из 12): housing, housing_dev, realization (поквартирный прайс-лист!), mortgage_rates, stat_series. Требуют page-specific user-interaction triggers. TODO в следующей сессии — расширить 30_scrape_domrf.py interactions (клик на вкладки/фильтры)"]}
{"type":"entity","name":"DomRF_Schema_Relations_Apr26","entityType":"infrastructure","observations":["Дата: 26.04.2026 вечер. Миграция data/sql/40_relations.sql — FK constraints + helper views между всеми таблицами DOM.РФ и Rosreestr на ПРОДЕ","BOOTSTRAP ДЛЯ FK:","• Добавлена region_id=0 ('Российская Федерация' / '_RF') в domrf_regions — этот ID используется как all-Russia placeholder в domrf_flat_area_distribution и domrf_developer_aggregates","• Бэкфилл 22 снапшотов в domrf_snapshots из всех дочерних таблиц с snapshot_date","FK CONSTRAINTS (27 шт):","• 23 × fk_snap_<table>: все domrf_* таблицы с snapshot_date → domrf_snapshots(snapshot_date) ON UPDATE CASCADE","• fk_region_aggregates_region: domrf_region_aggregates.region_id → domrf_regions(region_id)","• fk_flat_area_region: domrf_flat_area_distribution.region_id → domrf_regions(region_id)","• fk_developer_agg_region: domrf_developer_aggregates.region_id → domrf_regions(region_id)","• fk_developer_agg_developer: domrf_developer_aggregates.developer_id → domrf_developers(developer_id)","НЕ ДОБАВЛЯЛ FK (не подходят по типу):","• domrf_launch_top.entity_id — смешанные ID (developer_id − TEXT, region_id − numeric, area name) в одной TEXT колонке с dim_type-разбивкой","• domrf_sold_ready_breakdown.entity_key — тоже смешанный ключ (название по chartType)","• domrf_commissioning.region_id — ДРУГАЯ система ID (внутренняя НОМЕНКЛАТУРА commissioning API), не совпадает с domrf_regions(region_id)","• rosreestr_deals.region_code — SMALLINT в partitioned table; по значениям совпадает с domrf_regions.region_id, но формальный FK на partitioned-table сложен — JOIN с v_rosreestr_market_by_region","HELPER VIEWS (4 шт):","• v_region_master — ОДНА строка на регион со всеми ключевыми метриками: квартирография (DOM.РФ) + распроданность (PDF и API) + проектное финансирование + 214-ФЗ + запуски/ввод","• v_developer_master — Профиль застройщика: реестр + квартирография по комнатностям + запуски/ввод + распроданность. PRINZIP, Брусника, ЛСР и др. в одном выборке","• v_rosreestr_market_by_region — Цены сделок Росреестра (median/p10/p90 ₽/м²) по кварталам с DOM.РФ-именами регионов и ФО (только квартиры)","• v_market_pulse_rf — ОДНА СТРОКА: РФ pulse: 118.7M м² стр-ва, продано 30.91%, рыночная ставка 19.9% vs реальная 6.83% (разница 13 пп — субсидии), 68 714 кредитов на 290 млрд ₽, средняя цена 216 316 ₽/м²","КЛЮЧЕВЫЕ ИНСАЙТЫ ИЗ v_developer_master для PRINZIP вс конкуренты Свердл.обл:","• Брусника 30 106 квартир / 1 780 тыс м² / доля РФ 1.49% / sold% 46.6%","• ЛСР 33 933 / 1 270 / 1.07% / sold 48.1%","• КОРТРОС 9 815 / 484 / 0.41% / sold 28.4%","• Атомстройкомплекс 4 018 / 233 / 0.20% / sold 15.0% (ОЧЕНЬ МЕДЛЕННО ПРОДАЁТ)","• УГМК 1 883 / 138 / 0.12% / sold 41.5%","• Стройтэк 1 515 / 77 / 0.06% / sold 28.4%","• PRINZIP 814 / 31 / 0.026% / sold 48.4% (БЫСТРО ПРОДАЁТ!)","PRINZIP имеет НАИВЫСШИЙ sold_pct (48.4%) среди сравнимых застройщиков Свердл.обл. Несмотря на маленький портфель (814 кв-р), 75% однушки с хорошей absorption rate — продукт попадает в рыночный спрос ЛУЧШЕ чем КОРТРОС/Атомстройкомплекс с большими портфелями"]}
{"type":"entity","name":"Session_End_Apr26_2026","entityType":"event","observations":["Дата: 26.04.2026 поздний вечер. Итоги дня перед чисткой контекста. При продолжении работы читай СНАЧАЛА DB_Schema_Final_Apr26 + эту сущность.","СДЕЛАНО ЗА ДЕНЬ (4 крупных вехи):","1) Rosreestr CSV сделок залит на прод — 7 кварталов (2024Q3-2026Q1), 7.58M сделок РФ, 296K Свердл.обл. См. Rosreestr_DealsCSV_Loaded_Prod_Apr26.","2) ДОМ.РФ JSON dashboard залит (89 регионов, 2734 застройщика, 11K рядов агрегатов). См. DomRF_Analytics_Loaded_Prod_Apr26.","3) 7 XLSX/PDF с юзер-выгрузки (developer_rf, escrow_rf, guaranty, housing_info, sold_out_info, mortgage_rates, Квартирография). См. DomRF_XLSX_PDF_Snapshot_Loaded_Apr26.","4) Playwright headless scraper написан и запущен — скачал 7/12 страниц ДОМ.РФ через ServicePipe WAF. 64 JSON-файла → 10 новых нормализованных таблиц. См. DomRF_Playwright_Scraper_Apr26 + DomRF_Scraped_Loaded_Prod_Apr26.","+ FK constraints + 4 helper views поверх всех таблиц. См. DomRF_Schema_Relations_Apr26.","СОСТОЯНИЕ ПРОД-БД (gendsgn.ru / 46.173.16.127):","• PostgreSQL 16 + PostGIS 3.4 в docker-compose. Размер 1855 MB.","• 36 таблиц + 4 view + 3 mat view + 7 партиций + 28 FK.","• Доступ только через SSH-туннель (порт 5432 бинд на 127.0.0.1).","• Локальный порт после туннеля у юзера: 15432 (прод), 5432 (был локальный).","• Пароль POSTGRES_PASSWORD: 2J2SBPMKuS998fiwhtQqDhMI (светился в чате несколько раз — юзер может сменить через docker compose recreate postgres).","• БД: gendesign, Юзер: gendesign.","ДОСТУП К ПРОДУ:","• SSH-ключ: C:\\Users\\user\\.ssh\\gendesign_deploy (и копия в sshkey.txt в корне репо — юзер разрешил)","• SSH config alias: 'gendesign' → 46.173.16.127 с LocalForward 15432:5432 и 8000:8000","• Команда: ssh gendesign (или ssh -N gendesign для только туннеля)","• Инструкция для Mac: скопировать ключ в ~/.ssh/, добавить тот же ssh config block, подключаться через TablePlus/DBeaver на localhost:15432","TODO СЛЕДУЮЩЕЙ СЕССИИ (по важности):","• 5 страниц ДОМ.РФ не скачались (lazy-load с user-interaction): housing, housing_dev, realization (ПОКВАРТИРНЫЙ ПРАЙС!), mortgage_rates, stat_series. Расширить data/sql/30_scrape_domrf.py page-specific click triggers.","• /сервисы/api/kn/flats?regions=66&developers=6208_0 — поквартирный прайс-лист PRINZIP, Authorization: Basic MTpqd2U=. Идеальный источник для вкладки Prinzip.","• NSPD GeoJSON кадастровых кварталов Свердл.обл → таблица cadastral_quarters PostGIS для spatial join.","• Cron quarterly_rosreestr_sync на VPS (16-го числа 2-го месяца после квартала).","• Cron domrf_daily_scrape на VPS (Playwright + chromium 300 MB).","• FastAPI router /api/v1/analytics/{ural|ekb|prinzip} используя v_region_master / v_developer_master / v_market_pulse_rf.","• Alembic-миграции из *.sql (воспроизводимость при wipe).","• Пользователь спрашивал 'можно ли объединить дублирующие таблицы' — НЕ ОТВЕЧЕНО, вернуться в следующей сессии. Кандидаты на объединение: domrf_sold_out (PDF, 9 рядов) vs domrf_sold_ready_breakdown (API, 2660 рядов) — покрывают одну тему; domrf_developers (справочник, 2734) vs domrf_developers_full (реестр с метриками, 2563) — разные но перекрываются; domrf_planned_commissioning vs domrf_commissioning vs domrf_launch_monthly — все про ввод.","ОГРАНИЧЕНИЯ КОТОРЫЕ СТОИТ ПОМНИТЬ:","• PRINZIP id = '6208_0', в базе как developer_id TEXT, найдёшь в v_developer_master.","• Свердл.обл region_id = 66 в domrf_regions И region_code = 66 в rosreestr_deals — системы КОДОВ совпадают (Rosstat-style коды).","• ДДУ-данные Свердл.обл в Rosreestr CSV НЕПОЛНЫЕ до середины 2025 (Q1 2025 = 2 сделки — lag публикации). С Q2 2025 нормально.","• Средняя цена МКД РФ от ДОМ.РФ = 216 316 ₽/м² (sold_out PDF). Первичка Свердл.обл median из Росреестра = 149 377 ₽/м² (Q1 2026, ДДУ). Это НОРМАЛЬНО — средняя РФ выше из-за Москвы/Питера.","• 5 страниц из 12 ДОМ.РФ не скачались — это НЕ ошибка скрейпера, это фича lazy-loading. Нужны page-specific click triggers.","КЛЮЧЕВЫЕ ИНСАЙТЫ ДНЯ НАПОМНИТЬ:","• PRINZIP с мини-портфелем (814 кв-р) имеет НАИВЫСШИЙ sold_pct 48.4% среди сравнимых застройщиков Свердл.обл. Атомстройкомплекс в 4× больше sold_pct 15%.","• Резкое падение ввода после 2028 года: 2026=37.9M→ 2027=35.4→2028=26.5→2029=11.0→2030=4.3M м². Окно Discovery MVP именно сейчас.","• Средняя фактическая ставка первички РФ 6.83% (субсидии), но рыночная 19.9% — разница 13 пп это субсидирование госпрограмм.","• Комфорт = 67% всех запусков РФ (6.93M м² из 10.56M total). Типовой всего 19%.","• Сбер доминирует эскроу: 72.8M м² = 61% всего эскроу-рынка.","• Свердл.обл рынок: 5.67M м² в стройке, 179 застройщиков, sold_pct 29% (хуже среднего РФ 31%) но soldReady_pct 80% (здоровый баланс стройки/продаж).","СТРУКТУРА РЕПО для этой работы: data/sql/ — 9 SQL/PY скриптов, data/raw/ — 1 GB CSV+JSON (в .gitignore). Граф связей обновлён — ~150 связей, все ключевые entities связаны с Project_GenDesign и PlanA_AnalyticsFirst_Apr25."]}
{"type":"entity","name":"DomRF_History_Loaded_Apr27_2026","entityType":"event","observations":["Дата: 27.04.2026 поздний вечер. ДОГРУЖЕНА ИСТОРИЯ 14 месяцев (12 мес 2025 + Январь/Февраль 2026) для realization + sold_ready эндпоинтов ДОМ.РФ.","АРТЕФАКТЫ: data/sql/40_scrape_history.py + 41_load_history.py + 42_schema_breakdown_widen.sql.","ПОДХОД: API DOM.РФ принимает исторические repYear/repMonth параметры — подтверждено пробой. Для каждого месяца SNAPSHOT_DATE = последний день периода (2025-01-31, 2025-02-28, ...) — против конфликтов PK.","СКРЕЙП: 6 755 JSON-файлов / 14 месяцев / ~480 файлов на месяц. data/raw/domrf_history/{realization,sold_ready}/<YYYY-MM>/. Работал ~17 минут (Playwright headless Chromium, 89 регионов × 4 endpoint × 14 мес ≈ 5K fetch).","ЗАЛИТО В ПРОД:","• domrf_realization — было 9 747, стало 143 963 (+134 216 рядов, 14 новых snapshot_date'ов).","• domrf_sold_ready_index — +14 рядов (по ОДНОМУ ряду НА месяц: РФ-итог: squareSum / soldPerc / readyPerc / soldReadyPerc).","• domrf_sold_ready_breakdown — +37 384 рядов (7 chart_type × ~2 600 × 14 мес). Chart types: foChart (9), regionChart (89), devChart (~2 700-3 500 зависимо от периода), devValueChart (5 бакетов), cityPopulationChart (4), classChart (4), readyYearChart (~7).","• domrf_sold_ready_dynamics — +3 150 рядов (4 dynamic_chart_type × × годы × месяцы 2020-period).","• domrf_snapshots — +14 рядов (snapshot_date'ов истории), всего стало 18.","SCHEMA ИЗМЕНЕНИЕ (42_schema_breakdown_widen.sql):","Было: domrf_sold_ready_breakdown.extra JSONB с любыми лишними полями (foCd в своей колонке, остальные в JSONB). Стало: 6 типизированных колонок, JSONB дропнут. Каждый chart_type имеет одно дискриминаторное поле:","• foChart → fo_cd (INT, 100-108)","• regionChart → region_cd (INT, Rosstat 1-95)","• devChart → dev_calc_group_id (TEXT, '5791_0' = Брусника, '6072_0' = Самолёт, '6208_0' = PRINZIP)","• devValueChart → dev_group_value (TEXT, do10/do25/do50/do100/over100 бакеты размера)","• cityPopulationChart → city_population (TEXT, do50/do100/do250/over1000 население)","• classChart → obj_class (TEXT, typical/comfort/business/elite)","• readyYearChart → ready_year (INT, год планируемой готовности)","COMMENT добавлен на каждую новую колонку.","КЛЮЧЕВЫЕ INSIGHTS ИЗ ИСТОРИИ:","• Свердл.обл realization total: объём стр-ва рос 5 115 (Янв 2025) → 6 015 (Дек 2025) тыс м² (+18% за год), затем откат в 5 686 (Мар 2026, -5%). Цена выросла 136 796 → 151 397 ₽/м² (+11%).","• sold_perc Свердл.обл: 35% (Янв 2025) → 29% (Мар 2026). Рынок остывает.","• Брусника (developer_id 5791_0) sold% timeseries: 33% (Mar 2025) → 50.36% (Feb 2026). РЕКОРДНЫЙ РОСТ велосити среди крупных девелоперов РФ — Свердл.обл портфель лучше продаётся в сравнении с Самолётом (sold% в районе 36-40% константно). PRINZIP обгоняет обоих в Свердл.обл 47-48%.","ОГРАНИЧЕНИЯ / TODO:","• escrow история НЕ догружена — endpoint /portal-analytics/api/escrow?date=01-XX-2025 вернул 404/403 при пробе (WAF временное или URL другой). escrow_allDate.json показывает что данные есть вся история. Отдельный TODO — добраться правильным путем.","• launch / commissioning / mortgage_stats / quartirografia / housing/_dev / project_finance — НЕ перескрейпливали за 2025: их существующие endpoints возвращают timeseries 2020-2026 в ОДНОМ ответе (видно в launch_monthly: 75 рядов = 5 лет × 12 мес + 15 мес 2026; commissioning, sold_ready_dynamics то же самое).","• stat_series уже имел 2020-2026 из XLSX, не трогали.","• ПОДНЯТЬ ЯСНОСТЬ С SOLD_READY_DYNAMICS: в 1 месяц = 225 рядов (4 chart_type × годы 2020-period × 12 мес). Разные snapshot_date имеют оверлапы — снапшот июля-2025 репит 2020-01..2025-07, снапшот август-2025 репит 2020-01..2025-08. Это НОРМАЛЬНО — они в PK вместе с snapshot_date.","MCP CONNECTOR ИСПОЛЬЗОВАНИЕ: вся DDL (ALTER TABLE 42), все SELECT-верификации, инфо о схеме делались через mcp__postgres__execute_sql. Питон-скрипты использовались только для парсинга 6755 локальных JSON-файлов и batch INSERT (MCP файлы не парсит).","ДОСТИЖИМО СЕЙЧАС:","• Динамика по региону/девелоперу/классу/размеру портфеля по МЕСЯЦАМ за 14 периодов.","• Анализ 'velocity' различных девелоперов по регионам.","• Ответ на вопрос 'PRINZIP лучше ДК/ФСК/КОРТРОС?' — теперь с трендом.","• Ответ на 'sold% в Свердл.обл растёт или падает?' — ПАДАЕТ 35→29%."]}
{"type":"entity","name":"Sverdl_Quartirography_Report_Apr27","entityType":"research","observations":["Дата: 27.04.2026. ОТЧСТ ПО КВАРТИРОГРАФИИ СВЕРДЛОВСКОЙ ОБЛАСТИ НА ОСНОВЕ ВСЕГО ANALYTICAL ПЛАСТА ДАННЫХ PROD DB.","ИСТОЧНИКИ: domrf_realization (143K rows), rosreestr_deals (4.97M raw, 296K Свердл), domrf_region_aggregates, domrf_developer_aggregates, domrf_kn_objects (1516 ЖК Свердл), ekb_districts, yandex_realty_zk, domrf_sold_ready_breakdown.","РЫНОК СВЕРДЛ 14 МЕС (ЯНВ 2025 - АПР 2026):","• Объём стр-ва: 5 115 → 6 015 тыс м² за 2025 (+18%), затем откат в 5 686 Мар 2026 (-5%).","• sold%: 35% → 29% (-6пп) — рынок охлаждается, unsold вырос 50%→54%.","• Цена: 136 796 → 151 397 ₽/м² (+11% за 14 мес) — МЕДЛЕННЕЕ инфляции и реальной ставки ЦБ 11%.","КВАРТИРОГРАФИЯ СВЕРДЛ ПОРТФЕЛЬ (что строится, 115 205 квартир):","• 1-к: 60 652 (52%) × 36.5 м² ср. — САМЫЙ БОЛЬШОЙ СЕГМЕНТ","• 2-к: 39 839 (35%) × 57.1 м²","• 3-к: 13 754 (12%) × 78.9 м²","• 4+к: 960 (1%) × 103.7 м²","РЕАЛЬНЫЕ ДДУ-СДЕЛКИ СВЕРДЛ Q3 2025-Q1 2026 (Rosreestr 460 сделок с фильтрами):","• Студии 15-30 м²: 87 сделок (19%), медиана 114 557 ₽/м²","• 1-к 30-45 м²: 67 (15%), медиана 112 640 ₽/м²","• 2-к 45-60 м²: 56 (12%), медиана 123 932 ₽/м²","• 3-к 60-80 м²: 36 (8%), медиана 126 934 ₽/м²","• БОЛЬШИЕ 80+ м²: 171 (37%!), медиана 139 382 ₽/м² — ЛИДЕР ПО СДЕЛКАМ, ср. чек 20 М ₽!","ПАРАДОКС: строят 52% однушек, покупают 37% больших 80+ м². Рынок голосует деньгами за семейные квартиры, предложение ориентировано на инвесторский сегмент студий-однушек.","PIPELINE ПО ГОДУ ВВОДА (Свердл, Апр 2026):","• 2026: 1 649 тыс м², sold 54% (запаздывать входить)","• 2027: 1 745, sold 29%","• 2028: 1 567, sold 15%, unopened 19% 🚩","• 2029: 538, sold 4%, unopened 56% 🚩🚩","• 2030: 122, sold 0.2%, unopened 89% 🚩🚩🚩","• 2031: 65, sold 0%, unopened 100%. ОКНО ИНВЕСТИЦИЙ: 2026-2027 ввод.","ТОП-15 ДЕВЕЛОПЕРОВ СВЕРДЛ (sold% динамика 14 мес):","• ПОБЕДИТЕЛИ: PRINZIP +33пп (15→48), Холдинг Форум-групп +21пп (33→54%) — ЛИДЕР ПО SOLD%, Брусника +11пп (36→47), Астра +11пп (19→30), КОРТРОС +4пп, Атлас +5пп.","• ПРОИГРЫВАЮЩИЕ: Унистрой ОБВАЛ 59→8% (-51пп при росте +176 тыс м²), Атомстройкомплекс -31пп (46→15), Эталон -28пп (45→17), УГМК -27пп (69→42). ПАТТЕРН ЗАТОВАРИВАНИЯ.","ТОП ЖК ЕКБ (1 285 ЖК в реестре):","• САМЫЕ БОЛЬШИЕ: ЖК СТАРТ (ТЭН, 1566 кв.), Сибирский сад (Страна Дев, 1429+1142), Основинские Кв-ы (ТЭН, 1224), Первый Академ (КОРТРОС, 1050), Атлас Юник (Атлас, 1044).","КОНЦЕНТРАЦИЯ ПО РАЙОНАМ ЕКБ:","• Академический: 330 ЖК / 82 520 кв-р (ЛИДЕР)","• Ленинский: 215 / 50 754","• Верх-Исетский: 151 / 37 611","• Чкаловский: 142 / 38 506","• Орджоникидзевский: 139 / 28 733","• Железнодорожный: 135 / 30 428","• Кировский: 115 / 29 754","• Октябрьский: 90 / 27 863 (НАИМЕНЬШАЯ КОНКУРЕНЦИЯ)","РЕКОМЕНДАЦИИ (ЧТО СТРОИТЬ):","• Приоритет #1: семейные 60-90 м² (3-к) — дефицит предложения, 8% сделок, ср. чек 10.5 М ₽.","• Приоритет #2: большие 100-150 м² — 37% сделок при Ц 153K ₽/м², ср. чек 20 М ₽. Премиум кад.кварталы: 66:41:0701011 (мед 424K), 66:41:0106113 (172K), 66:41:0704044 (149K).","• ИЗБЕГАТЬ: однушки 30-40 м² (переразвиты), проекты 2028+ на эскроу (66-89% unsold).","ГДЕ СТРОИТЬ: Кировский/Октябрьский (недо-инвестированы), не-ЕКБ города (Н.Тагил 23 ЖК, Первоуральск, Арамиль).","BENCHMARK MODELS: Брусника (350 тыс м² / sold 47% / +11пп), Холдинг Форум-групп (113 тыс м² / sold 54% / +21пп лидер velocity).","РАЗРЫВ СРЕДНЕЙ: Брусника ср. 60 м², Форум ср. 61 м², PRINZIP ср. 38 м² — в 1.5х меньше рынка (49 м²).","YANDEX REALTY ACTIVE LISTINGS (снимок 27.04.2026): в БД всего 12 записей (Comfort 6, Business 4, Comfort+ 1, Elite 1). Предыдущий факт «258 новостроек» был устаревшим снимком. Текущий парсер явно недобирает — режимы являются кандидатом на перевыполнение в ближайшее время."]}
{"type":"entity","name":"PRINZIP_Strategy_Apr27","entityType":"research","observations":["Дата: 27.04.2026. СТРАТЕГИЧЕСКИЙ АНАЛИЗ ДЛЯ PRINZIP (developer_id 6208_0) НА ОСНОВЕ PROD ДАННЫХ.","ТЕКУЩИЙ ПОРТФЕЛЬ (developer_aggregates):","• ВСЕГО: 814 квартир / 31 040 м² / 28 ЖК / ср. 38.1 м²","• 1-к: 614 (75% портфеля) × 30.8 м² — ОЧЕНЬ МАЛЕНЬКИЕ","• 2-к: 156 (19%) × 52.8 м²","• 3-к: 22 (3%) × 81.3 м²","• 4+к: 22 (3%) × 95.2 м²","ПОРТФЕЛЬ ПО СТАТУСУ: 26 из 28 ЖК СДАНЫ (2018-2024). СТРОЙКА: Шарташ Парк (523 кв, сдача 2026-12, эскроу) + 2-я очередь Парк Победы (291, 2027-03).","VELOCITY ЛИДЕРСТВО: sold% 15% (Янв 2025) → 48% (Апр 2026) = +33пп. ЛУЧШИЙ РОСТ СРЕДИ ТОП-5 СВЕРДЛ (Брусника +11, Форум +21, KORTROS +4, Атлас +5). Объём НЕ растёт (стабильно 31 тыс м²).","ГЕОГРАФИЯ PRINZIP ПО РАЙОНАМ ЕКБ:","• Октябрьский: 6 ЖК / ДОЛЯ РАЙОНА 6.7% (высокая концентрация, парковый квартал/Ленина/LVIII)","• Верх-Исетский: 4 ЖК / доля 2.6% (Первый Николаевский, Малевич)","• Ленинский: 4 ЖК / 1.9% (Ньютон Парк, Краснолесья)","• Кировский: 2 ЖК / 1.7% (Первомайская 60, Шарташ)","• Орджоникидзевский: 1 ЖК / 0.7% (Парк Победы/Татлин 3 объекта)","• АКАДЕМИЧЕСКИЙ: 0 PRINZIP / 0% (САМЫЙ БОЛЬШОЙ КЛАСТЕР 330 ЖК / 82К квартир — PRINZIP ОТСУТСТВУЕТ 🚨)","• Чкаловский: 0 / 0% (142 ЖК / 38К кв.)","• Железнодорожный: 0 / 0% (135 ЖК / 30К)","КЛЮЧЕВОЙ РАЗРЫВ С РЫНКОМ:","• PRINZIP средняя квартира 38 м² vs Свердл 49 м² vs Брусника 60 м² vs Форум 61 м².","• PRINZIP доля 1-к 75% vs Свердл 52% vs Брусника 47%.","• PRINZIP доля 3-к+ всего 6% vs Свердл 13% vs Брусника 18% vs Форум 21%.","ПОРТФЕЛЬ PRINZIP ОРИЕНТИРОВАН НА ИНВЕСТОРОВ / МОЛОДЫХ ПОКУПАТЕЛЕЙ, НО РЫНОК СЕЙЧАС ПОКУПАЕТ СЕМЕЙНЫЙ 80+ м².","PRINZIP CRM данные (из Антона): средний чек 2025 = 6.15 М ₽, conversion 5.4% (обвал с 11.2% в 2020). 39.9 млрд ₽ revenue за 8 лет. Пик 2023 (12.81% conv).","РЕКОМЕНДАЦИИ СТРАТЕГИИ PRINZIP:","ПРИОРИТЕТ #1: семейные квартиры 60-90 м² (3-к). Дефицит в портфеле (3% vs Брусника 17%), ср. чек 10.5 М ₽. Подъём среднего чека выше текущего CRM 6.15 М.","ПРИОРИТЕТ #2: премиум 100-150 м² (37% сделок, 20 М ₽). Кад.кварталы 66:41:0701011 (МЕД 424K!), 66:41:0106113 (172K), 66:41:0704044 (149K). Расширить Парковый Кв-л/LVIII модель.","ГДЕ СТРОИТЬ НОВОЕ:","• #1 АКАДЕМИЧЕСКИЙ (330 ЖК, 0% PRINZIP) — самый большой кластер ЕКБ, ПРИНЦИП ИГНОРИРУЕТ. Семейный сегмент молодых покупателей.","• #2 ВЕРХ-ИСЕТСКИЙ расширение — кад.квартал 66:41:0106113 (ср. 113 м² × 172K ₽/м²). Бизнес 80-130 м².","• #3 ЧКАЛОВСКИЙ / ЖЕЛЕЗНОДОРОЖНЫЙ — растущие районы, 0% PRINZIP, низкая конкуренция. Тест 60-80 м² без премиума.","НЕ РАСШИРЯТЬ: Октябрьский (уже 6.7% доля), Орджоникидзевский (выросли из Парка Победы).","ОБЩАЯ СТРАТЕГИЯ: 'Брусника model' в Академическом + 'Премиум-проект 80-150 м²' в Верх-Исетском. Сократить 1-к с 75% до 50%, увеличить 3-к+ с 6% до 20%. Удержать sold% > 45% — ваше преимущество."]}
{"type":"entity","name":"Schema_Tables_Map_Apr27","entityType":"infrastructure","observations":["1️⃣ DOM.РФ realization & history (4): domrf_realization, domrf_sold_ready_index, domrf_sold_ready_breakdown, domrf_sold_ready_dynamics","2️⃣ DOM.РФ stat_series (3): domrf_stat_series_observations, domrf_stat_series_indicators, domrf_xlsx_files","3️⃣ DOM.РФ JSON dashboard (3): domrf_region_aggregates, domrf_developer_aggregates, domrf_flat_area_distribution","4️⃣ DOM.РФ XLSX/PDF (8): domrf_developers, domrf_developers_full, domrf_escrow_banks, domrf_guaranty_regions, domrf_housing_summary, domrf_planned_commissioning, domrf_sold_out, domrf_mortgage_rates","5️⃣ DOM.РФ launch/commissioning (5): domrf_launch_top, domrf_launch_obj_class, domrf_launch_monthly, domrf_commissioning, domrf_project_finance","6️⃣ DOM.РФ ipoteka (2): domrf_mortgage_dashboard, domrf_mortgage_details","7️⃣ DOM.РФ kn-API (2): domrf_kn_flats, domrf_kn_objects","8️⃣ DOM.РФ growth (1): domrf_dev_growth","9️⃣ DOM.РФ raw (1): domrf_raw_endpoints","🔟 DOM.РФ dimensions (4): domrf_regions, domrf_snapshots, domrf_federal_districts, domrf_territory_aliases","1️⃣1️⃣ ЦБ ипотека (2): cbr_mortgage_series, cbr_mortgage_files","1️⃣2️⃣ Внешние данные (3): sber_ddf_metrics, yandex_realty_zk, yandex_realty_class_prices","1️⃣3️⃣ Geo Свердл/ЕКБ (4): ekb_districts, ekb_metro, sv_cities, sv_dev_sales","1️⃣4️⃣ Rosreestr (10): rosreestr_deals + 7 partitions (2024Q3..2026Q1) + rosreestr_deals_staging + rosreestr_rent_deals","1️⃣5️⃣ PostGIS system (1): spatial_ref_sys","САМЫЕ БОЛЬШИЕ ПО РАЗМЕРУ: rosreestr_deals_2024q4 (253MB), domrf_stat_series_observations (254MB), rosreestr_deals_2024q3 (237MB), domrf_realization (39MB), domrf_sold_ready_breakdown (11MB), domrf_kn_flats (7.4MB).","ОБНОВЛЕНО 27.04.2026 поздний вечер: 59 public TABLES (было 53), 1 871 MB после vacuum/repack (было 2 177 MB).","7⃣ DOM.РФ kn-API РАСШИРЕНО (8): domrf_kn_flats, domrf_kn_objects, domrf_kn_sale_graph (time-series продаж), domrf_kn_sales_agg (текущие агрегаты 3 типа), domrf_kn_infrastructure (норм POI), domrf_kn_photos (мета+local_path), kn_scrape_runs (журнал прогонов), kn_scrape_failures (per-request ошибки с full_url для ручной проверки в браузере).","Рост от 53 до 59: +6 таблиц из экстрас-скрейпера (DomRf_Kn_Scraper_Apr27).","+4 PRINZIP CRM таблицы/views (пока пустые, ждут SQLite-файл): prinzip_leads, prinzip_deals, prinzip_funnel_monthly (MV), prinzip_funnel_by_object (MV). Общее количество таблиц +2 (leads/deals без MV)."]}
{"type":"entity","name":"Schema_FK_Map_Apr27","entityType":"infrastructure","observations":["СНАПШОТ 27.04.2026. 35 FK constraints по parent table.","domrf_snapshots (24 child FKs) — все таблицы со snapshot_date: commissioning, developer_aggregates, developers_full, escrow_banks, flat_area_distribution, guaranty_regions, housing_summary, launch_monthly, launch_obj_class, launch_top, mortgage_dashboard, mortgage_details, mortgage_rates, planned_commissioning, project_finance, raw_endpoints, region_aggregates, sold_out, sold_ready_breakdown, sold_ready_dynamics, sold_ready_index, realization ⭐, xlsx_files ⭐, stat_series_observations ⭐.","domrf_regions (5 child FKs): developer_aggregates, flat_area_distribution, region_aggregates, realization (region_code) ⭐, kn_objects (region_cd) ⭐, rent_deals (region_cd) ⭐, territory_aliases.","domrf_developers (3 child FKs): developer_aggregates, kn_objects (dev_id) ⭐, sv_dev_sales (dev_id) ⭐.","domrf_federal_districts (1 child FK): territory_aliases.","ЭВОЛЮЦИЯ: 26.04 было 28 FK → 27.04 lazy +3 → 27.04 territory aliases +2 → 27.04 relations v2 +4 = 35 итого.","НЕ СОЗДАНЫ (data quality issues):","• domrf_kn_flats.obj_id → kn_objects: разные ID-системы API, 27563 orphans.","• domrf_kn_flats.region_cd — все NULL.","• dev_growth.dev_id — все NULL.","• realization.subject (для endpoint_type=developer) → developers — partial constraint нельзя выразить стандартным FK (subject overloaded для total/housing/ready_year).","ОРИГИНАЛ: data/sql/40_relations.sql (базовые 28 FK) + 38_relations_fix.sql (+4 для realization/xlsx/stats) + 39_territory_aliases.sql (+2) + 45_relations_v2.sql (+4 kn_obj/dev_sales/rent). Индексы на FK childs авто."]}
{"type":"entity","name":"Schema_Views_Catalogue_Apr27","entityType":"infrastructure","observations":["9 helper views в prod-БД на 27.04.2026.","BASE (legacy 26.04, data/sql/40_relations.sql):","• v_market_pulse_rf — ОДИН ряд РФ-метрики: 118.7M м² стр-ва, sold 30.91%, Ц 216 316 ₽/м², рыночная ипотека 19.9% vs реальная 6.83%.","• v_developer_master — профиль девелопера из sold_ready breakdown + aggregates (ЛЕГАСИ, заменён v_developer_full_metrics).","• v_region_master — один ряд на регион: квартирография + sold_out + sold_ready + project_finance + guaranty + launch.","• v_rosreestr_market_by_region — Rosreestr p10/median/p90 + DOM.РФ имена.","TERRITORY (39_territory_aliases.sql):","• v_stat_series_resolved — stat_series_observations LEFT JOIN aliases LEFT JOIN indicators. Резолвит 99 вариативных имён территорий. WHERE region_id=66 → Свердл.","RELATIONS V2 (45_relations_v2.sql):","• v_jk_with_developer — ЖК + canonical dev_name + region_name (FK kn_obj→developers/regions).","• v_jk_sales_summary — flats GROUP BY obj_name: total/sold/booked/free + sold_pct + avg_ppm + total_value.","• v_developer_portfolio — девелопер + все его ЖК/корпуса (count/flats/sqm + ekb/escrow/completed/in_progress).","• v_developer_full_metrics — ⭐ ULTIMATE: portfolio + квартирография долей (1к/2к/3к/4+) + realization Свердл sold%/цена. PRINZIP/Брусника/Форум-групп всё видно одним запросом."]}
{"type":"entity","name":"Schema_ETL_Artefacts_Apr27","entityType":"infrastructure","observations":["Эволюция data/sql/ с 26.04.2026 по 27.04.2026.","26.04 база (16 файлов):","• 01_schema_rosreestr_deals.sql, 02_load_all_quarters.sh, 03_materialized_views.sql","• 10_schema_domrf.sql, 11_load_domrf.py","• 20_schema_domrf_extras.sql, 21_load_domrf_extras.py","• 30_scrape_domrf.py (Playwright headless Chromium WAF-bypass)","• 31_schema_domrf_full.sql, 31_schema_domrf_raw.sql","• 32_load_domrf_full.py, 32_load_domrf_raw.py","• 40_relations.sql (FK + 4 helper views)","27.04 новые 9 файлов:","• 33_schema_domrf_lazy.sql + 34_load_domrf_lazy.py — realization/xlsx_files/raw_endpoints (5 lazy-load страниц)","• 35_schema_domrf_stats.sql + 36_parse_xlsx_stats.py — long-form panel из 7 XLSX (809K observations)","• 37_cleanup_redundant.sql — DROP sold_out_by_year/by_progress (дубли realization)","• 38_relations_fix.sql — +4 FK на snapshots, region_code -1→0 migration, drop dup indexes, COMMENT'ы","• 39_territory_aliases.sql — federal_districts(8) + territory_aliases(101) + v_stat_series_resolved","• 40_scrape_history.py + 41_load_history.py — 14 мес history (2025+Янв/Февр 2026)","• 42_schema_breakdown_widen.sql — sold_ready_breakdown JSONB extra → 6 типизированных колонок","• 43_anton_import.sql + 44_import_anton_db.py — импорт Антоновской SQLite (13 таблиц + merge developers)","• 45_relations_v2.sql — +4 FK kn_obj→regions/developers, sv_dev_sales→developers, rent_deals→regions + 4 analytical views (jk_with_developer, jk_sales_summary, developer_portfolio, developer_full_metrics)","НАИМЕНОВАНИЕ CONVENTION: NN_action_target.{sql|py|sh}. NN — порядок и группировка (00s rosreestr, 10s dashboard, 20s xlsx, 30s scrape+full, 40s relations+history, 45+ recent updates)."]}
{"type":"entity","name":"Schema_Open_TODOs_Apr27","entityType":"feedback","observations":["TODO работ над аналитическим пластом НА 27.04.2026 вечер (синхронизировано с DB_Schema_Final_Apr26).","ДОПОЛНИТЕЛЬНЫЕ ИСТОЧНИКИ ДАННЫХ:","• PRINZIP CRM (49 MB SQLite на analytics.prinzipevent.ru) — 102K заявок, 9K сделок, 39.9 млрд ₽ revenue за 8 лет. user подтвердил доступ — отдельный пасс импорта.","• Rosreestr архив 2000-2021 (6.7M сделок Свердл). У Антона _rosreestr_sv_deals.json (73 MB).","• escrow исторические даты — пробы 404 на /portal-analytics/api/escrow?date=01-XX-2025. История есть (escrow_allDate.json), нужен правильный URL.","НОРМАЛИЗАЦИЯ СУЩЕСТВУЮЩИХ ДАННЫХ:","• Парсер 01_05_*.xlsx 'Сводный' формат (лежит в xlsx_files BYTEA, bespoke layout).","• Парсер __NEXT_DATA__ для housing_dev/mortgage_rates SSR-блобов (лежат в raw_endpoints).","• GROUP BY comm_name в v_developer_portfolio для реального числа жилых комплексов (сейчас считает корпуса).","ИНФРА:","• Cron quarterly Rosreestr sync (16-го числа 2-го месяца после квартала).","• Alembic-миграции из *.sql файлов (воспроизводимость).","ANALYTICS-ОТЧСТЫ:","• Расширить расчёт среднего чека по классу/району/девелоперу.","• Соединить ЦБ ипотеку (cbr_mortgage_series) с realization sold% — видны ли корреляции.","• Анализ NSPD GeoJSON кадастровых кварталов + spatial join с rr_agg_cad_quarter.","СДЕЛАНО 27.04 вечер (было в TODO):","✅ PRINZIP-флаты probe (TODO #1 из Schema_Open_TODOs) — выгружены 826 квартир PRINZIP через собственный скрейпер (run_id=2). См. DomRf_Kn_Scraper_Apr27.","✅ FastAPI router /api/v1/analytics — 11 endpoints, 3 страницы дашборда. См. Analytics_Dashboard_Apr27.","✅ Фото-рендеры ЖК — метаданные собираются в domrf_kn_photos (5150 рядов по PRINZIP). Binary довыгрузка через --download-photos опционально.","✅ Cron domrf_daily_scrape на VPS — Celery beat + worker в docker-compose.yml. Расписание через SCRAPE_KN_CRON env (default '15 4 * * mon' + jitter 0-30мин).","ОСТАЛОСЬ (open):","• Импорт PRINZIP CRM 49 MB SQLite — выделен в GitHub issue #14.","• Rosreestr архив 2000-2021 (6.7M сделок Sverdl) у Антона.","• escrow исторические даты — нужен правильный URL.","• Парсер __NEXT_DATA__ для housing_dev/mortgage_rates SSR-блобов.","• GROUP BY comm_name в v_developer_portfolio.","• Расширить kn-scraper на 442 строящихся Свердл жК (GitHub #13).","• API endpoints /api/v1/analytics/object/{id}/sale_graph и др. (GitHub #15).","• Multi-target Dockerfile (-200 МБ backend) (GitHub #16).","GitHub backlog: источник правды для operational issues — https://github.com/lekss361/-gendesign/issues. Из открытых: #3 pg_dump → S3, #4 Sentry release, #5-9 Stage 1/2 generative & site-finder, #11 Anton onboarding, #13-16 из этой сессии. #10 (Plan A vs Original) закрыт — решено в пользу analytics-first."]}
{"type":"entity","name":"Sverdl_Market_Trend_Apr27","entityType":"research","observations":["КЛЮЧЕВОЙ ТРЕНД Свердл 14 мес (Янв 2025 - Апр 2026) из domrf_realization timeseries.","ОБЪЁМ СТР-ВА: 5 115 → 6 015 тыс м² (+18% за 2025) → 5 686 (Мар 2026, -5% откат от декабря).","SOLD%: 35% (Янв 2025) → ПЛАТО 32-35% в середине 2025 → 31% (Дек) → 29% (Апр 2026). ОПОСРЕДОВАННОЕ ОХЛАЖДЕНИЕ.","UNSOLD%: 50% → 54% (+4пп). Растёт запас нереализованного.","UNOPENED%: 15% → 17% (вырос лето 2025-2026 до 20% в Дек). Продажи не открываются позже.","ЦЕНА: 136 796 → 151 397 ₽/м² (+11% за 14 мес). МЕДЛЕННЕЕ инфляции и ставки ЦБ 11%. Девелоперы СДЕРЖИВАЮТ рост цен чтобы зажечь спрос.","PIPELINE ПО ГОДУ ВВОДА: 2026 sold 54% → 2027 29% → 2028 15% → 2029 4% → 2030 0.2%. ОКНО ИНВЕСТ: ввод 2026-2027.","REPRO QUERY: SELECT TO_CHAR(snapshot_date,'YYYY-MM'), total_square, sold_perc, price_avg FROM domrf_realization WHERE region_code=66 AND endpoint_type='total' AND type_square='total' ORDER BY snapshot_date;"]}
{"type":"entity","name":"Competitor_Benchmark_Brusnika_Apr27","entityType":"research","observations":["Брусника (developer_id 5791_0) — BENCHMARK для PRINZIP. Средний-крупный portfolio + растущий sold%.","ПОРТФЕЛЬ (developer_aggregates РФ-итог): 30 106 кв-р / 1.80M м² / ср. 60 м².","КВАРТИРОГРАФИЯ: 1к 47%, 2к 35%, 3к 17%, 4+к 1% — СБАЛАНСИРОВАННО семейный профиль.","СВЕРДЛ: 352 тыс м², sold% 47% (Апр 2026). Динамика: 36% (Янв 2025) → 64% (Дек 2025 ПИК) → 47% (Апр 2026 после приёма новых проектов).","КОРПУСОВ (kn_objects.dev_id=5791_0): 45 жилых комплексов, 28 сданы, 17 строятся.","ЧТО ПОДРАЖАТЬ PRINZIP'у: баланс квартирографии (1к/2к/3к 47/35/17 vs PRINZIP 75/19/3), работа с эскроу-проектами (Брусника 17 строит крупно), рост портфеля без потери sold% (Q4 2025 был 64%).","REPRO: SELECT * FROM v_developer_full_metrics WHERE developer_id='5791_0';"]}
{"type":"entity","name":"Competitor_Benchmark_ForumGroup_Apr27","entityType":"research","observations":["Холдинг Форум-групп (developer_id 5832_0) — БЕЗУСЛОВНЫЙ ЛИДЕР VELOCITY Свердл 27.04.","ПОРТФЕЛЬ (РФ-итог): 1 850 кв-р / 113 тыс м² / ср. 61 м².","КВАРТИРОГРАФИЯ: 1к 44%, 2к 34%, 3к 18%, 4+к 3% — ближе всех к 'family balanced' от рыночного спроса.","СВЕРДЛ: 113 тыс м² (мини-портфель относительно лидеров), sold% ЛИДЕР 54% (Апр 2026). Динамика: 33% (Янв 2025) → 47% (Дек) → 54% (Апр 2026) = +21пп за год.","КОРПУСОВ (kn_objects): 44, 34 сданы, 10 строятся.","ОСОБЕННОСТИ: НЕ РОС портфель за 14 мес (113 тыс м² стабильно), выиграл велосити без расширения. МОДЕЛЬ 'ДОПРОДАТЬ ЧТО ЕСТЬ ПРИ РОСТЕ ЦЕН НА НЕПРОДАННОЕ' — ближайшая к PRINZIP.","ЧТО ПОДРАЖАТЬ: PRINZIP имеет ту же логику (не растут объёмы с 31 тыс м²), но благодаря меньшей квартирографии идёт медленнее (PRINZIP +33пп vs Форум +21пп, но Форум выше absolute 54% vs PRINZIP 48%). ПОДНЯТЬ средний м² в портфеле — выравняться с Форумом.","REPRO: SELECT * FROM v_developer_full_metrics WHERE developer_id='5832_0';"]}
{"type":"entity","name":"DomRF_Lazy_Loaded_Apr27_2026","entityType":"event","observations":["Дата: 27.04.2026. ВЕХА: догружены 5 lazy-load страниц ДОМ.РФ + распарсены stat_series XLSX + дропнуты дубли + созданы territory aliases.","СКРЕЙПЕР 30_scrape_domrf.py расширен per-page direct-API триггерами (trigger_housing/_dev/realization/mortgage_rates/stat_series). Внутри page.evaluate(fetch()) — куки/WAF из chromium-context.","5 СТРАНИЦ ИСТОЧНИКИ: housing (302 JSON, /portal-analytics/api/dashboard/*), housing_dev (SSR __NEXT_DATA__), realization (501 JSON, /аналитика/api/rpp/*) ОСНОВНОЙ, mortgage_rates (SSR), stat_series (9 XLSX через fetch+arrayBuffer→base64).","ДОБАВЛЕНО В ПРОД (6 новых таблиц): domrf_realization (9 747), domrf_xlsx_files (9 BYTEA), domrf_stat_series_observations (809 236), domrf_stat_series_indicators (123), domrf_federal_districts (8), domrf_territory_aliases (101). + 333 raw JSONB endpoints в domrf_raw_endpoints.","ДРОПНУТЫ 2 ДУБЛЯ: domrf_sold_out_by_year (покрывался realization endpoint=ready_year) + domrf_sold_out_by_progress (покрывался endpoint=housing). domrf_sold_out ОСТАВЛЕН ради attracted_funds_mln_rub.","FK АУДИТ: добавлены 4 FK (на snapshots+regions), мигрирован region_code -1→0 (2742 ряда), дропнуты 2 дублирующих индекса. Детали в Schema_FK_Map_Apr27.","TERRITORY ALIASES: 101 alias resolver text→(level, region_id|fo_id) + view v_stat_series_resolved. 100% coverage 809K observations stat_series. Детали в Schema_Views_Catalogue_Apr27.","MCP postgres-mcp ПОДКЛЮЧЕН (.mcp.json в project root, .gitignore). С этого момента все DDL/SELECT через mcp__postgres__execute_sql.","ОГРАНИЧЕНИЯ: housing_dev/mortgage_rates SSR-блобы лежат в raw_endpoints (НЕ нормализованы). 2 XLSX 01_05_*.xlsx 'Сводный' формат остаются в xlsx_files BYTEA. См. Schema_Open_TODOs_Apr27.","АРТЕФАКТЫ: data/sql/30_scrape_domrf.py + 33-39_*.sql/py (10 файлов). Список в Schema_ETL_Artefacts_Apr27.","REPRO для Свердлобл realization sold% timeseries: SELECT TO_CHAR(snapshot_date,'YYYY-MM'), total_square, sold_perc, price_avg FROM domrf_realization WHERE region_code=66 AND endpoint_type='total' AND type_square='total' ORDER BY snapshot_date;"]}
{"type":"entity","name":"Anton_Imported_Apr27_2026","entityType":"event","observations":["Дата: 27.04.2026 поздний вечер. ИМПОРТ SQLite Антона (23.5 MB, 27 таблиц + 8 view) в prod Postgres.","ИСТОЧНИК: C:\\Users\\user\\Downloads\\Telegram Desktop\\db\\db\\domrf.db. Антон параллельно собрал 50+ источников (см. SUMMARY_FULL.md в дампе).","СТРАТЕГИЯ: импорт только уникальных таблиц. Дубли ПРОПУЩЕНЫ: regions, federal_districts, mortgage_rates, escrow_banks, rc_classes/dev_size/city_pop, rc_dynamics_rf, egrn_deals (наш rosreestr_deals 4.97M raw богаче чем его 154K cleaned).","ЗАЛИТЫ 13 НОВЫХ ТАБЛИЦ (197K рядов, +50 MB): domrf_kn_flats (27 563 поквартирный прайс РФ), domrf_kn_objects (1 516 ЖК Свердл с GPS), cbr_mortgage_series (3 308 ЦБ серий), cbr_mortgage_files (19), sber_ddf_metrics (20), yandex_realty_zk (12), yandex_realty_class_prices (3), ekb_districts (9), ekb_metro (10), sv_cities (24), sv_dev_sales (50), domrf_dev_growth (139), rosreestr_rent_deals (1 071). Полный список в Schema_Tables_Map_Apr27.","DEVELOPERS MERGE: было 2 734 в проде → Антон 8 618 (вкл. архивные). Добавлены 5 895 НОВЫХ (2 723 совпали). Итого domrf_developers: 8 629 рядов.","АРТЕФАКТЫ: data/sql/43_anton_import.sql + 44_import_anton_db.py. Список ETL в Schema_ETL_Artefacts_Apr27.","ОГРАНИЧЕНИЕ PRINZIP: в 27 563 flats Антона ОБЩИЙ РФ-срез (10 700 Москва, 286 ЕКБ), PRINZIP-квартиры ОТСУТСТВУЮТ — нужен отдельный probe /api/kn/flats?regions=66&developers=6208_0. TODO в Schema_Open_TODOs_Apr27.","ДОПОЛНИТЕЛЬНЫЕ ИСТОЧНИКИ АНТОНА (НЕ в дампе, требуют отдельного пасса): PRINZIP CRM (49 MB SQLite на analytics.prinzipevent.ru, 102K заявок / 39.9 млрд ₽ revenue), Rosreestr архив 2000-2021 (6.7M сделок, _rosreestr_sv_deals.json 73 MB), 1 267 фото-рендеров ЖК.","PARTNERSHIP НОТЕ: Антон имеет свой граф (114 entities + 339 relations, отдельный jsonl), prod-БД ОБЩИЙ ресурс через SSH-туннель. user подтвердил доступ к CRM/Yandex Realty — 'это и наш доступ тоже'."]}
{"type":"entity","name":"Session_End_Apr27_2026","entityType":"event","observations":["Дата: 27.04.2026 конец дня. СЛЕДУЮЩИЙ ЧАТ НАЧИНАЙ С ЭТОЙ СУЩНОСТИ ПЛЮС 4 ССЫЛОЧНЫх (ниже).","MCP CONNECTOR: crystaldba/postgres-mcp подключён через .mcp.json в project root (в .gitignore). Инструменты: mcp__postgres__execute_sql, list_objects, analyze_db_health, explain_query, get_object_details. Использовать вместо docker run psql.","КЛЮЧЕВОЙ VIEW: v_developer_full_metrics — одним запросом видно portfolio + квартирография доли + realization Свердл sold%/цена. SELECT * FROM v_developer_full_metrics WHERE developer_id IN ('6208_0','5791_0','5832_0').","СДЕЛАНО ЗА ДЕНЬ (ссылки на entity):","1. Lazy-load 5 страниц ДОМ.РФ + stat_series XLSX (DomRF_Lazy_Loaded_Apr27_2026)","2. История 14 мес realization+sold_ready, Янв 2025-Февр 2026 (DomRF_History_Loaded_Apr27_2026)","3. Импорт SQLite Антона 13 таблиц × 197K рядов (Anton_Imported_Apr27_2026)","4. Relations v2: +4 FK связь КВАРТИРЫ↔ЖК↔ДЕВЕЛОПЕРЫ + 4 analytical views (в Schema_Views_Catalogue_Apr27)","5. Два стратегических отчёта: Sverdl_Quartirography_Report_Apr27 + PRINZIP_Strategy_Apr27 + 2 benchmark-карточки (Brusnika, ForumGroup)","• Импорт PRINZIP CRM (49 MB SQLite на analytics.prinzipevent.ru) — 102K заявок / 39.9 млрд ₽ revenue.","• Парсер __NEXT_DATA__ для housing_dev/mortgage_rates SSR-блобов.","• GROUP BY comm_name в v_developer_portfolio — текущий считает корпуса, не жилые комплексы.","GRAPH HEALTH: 127 entities + 388 relations. Размер jsonl ~190K chars. После декомпозиции самый большой entity 8 881 chars (DataSources_Analysis_Apr26). Бывший гигант DB_Schema_Final_Apr26 УДАЛЁН, декомпозирован на 5 Schema_*_Apr27.","HARDLINK TRAP ГРАФА: MCP-сервер atomic-write периодически разрывает hard-link между C:\\mcp\\.aim\\memory-gendesign.jsonl и repo/memory/memory-gendesign.jsonl. Перед git commit ПРОВЕРИТЬ: fc /b memory\\memory-gendesign.jsonl C:\\mcp\\.aim\\memory-gendesign.jsonl. Если разные — del + New-Item -ItemType HardLink.","PROD ДОСТУП: SSH 'gendesign' алиас → 46.173.16.127 с LocalForward 15432:5432. Ключ: C:\\Users\\user\\.ssh\\gendesign_deploy. Пароль PG: 2J2SBPMKuS998fiwhtQqDhMI. Туннель уже открыт (netstat -an | grep 15432 LISTENING).","ОБНОВЛЕНО поздний вечер 27.04.2026: ПРОД-БД теперь 59 таблиц / 1871 MB. +6 таблиц от скрейпера (sale_graph, sales_agg, infrastructure, photos, kn_scrape_runs, kn_scrape_failures).","НОВЫЕ SESSION-ИТОГИ к ранее записанным буллетам: 6) Интерактивный дашборд /analytics (Analytics_Dashboard_Apr27) — 3 страницы на ECharts. 7) Парсер DOM.РФ kn-API + 4 extras (DomRf_Kn_Scraper_Apr27) — собственный sweep Свердл 442+2+1072 = 1516 жК, валидирован через PRINZIP probe (28 жК / 826 квартир / 5409 POI / 5150 фото-мета).","READ FIRST ОБНОВЛЕНО (6 entity вместо 4): Schema_Tables_Map_Apr27 + Schema_Open_TODOs_Apr27 + PRINZIP_Strategy_Apr27 + Sverdl_Quartirography_Report_Apr27 + Analytics_Dashboard_Apr27 + DomRf_Kn_Scraper_Apr27. Первые 4 — данные/стратегия, последние 2 — фичи построенные поверх.","PRIORITY НА СЛЕДУЮЩУЮ СЕССИЮ ОБНОВЛЕН (все из GitHub backlog): 1) #13 Расширить kn-scraper на 442 строящихся Свердл. 2) #14 Импорт PRINZIP CRM. 3) #15 API endpoints /api/v1/analytics/object/{id}/* + UI drill-down. 4) #16 multi-target Dockerfile."]}
{"type":"entity","name":"Analytics_Dashboard_Apr27","entityType":"deliverable","observations":["Дата: 27.04.2026 вечер. ИНТЕРАКТИВНЫЙ ВЕБ-ДАШБОРД АНАЛИТИКИ Свердл рынок + PRINZIP реализован за один проход. План: C:\\\\Users\\\\user\\\\.claude\\\\plans\\\\crispy-waddling-swing.md.","СТЕК: Backend FastAPI (sync SQLAlchemy + psycopg, Pydantic). Frontend Next.js 15 App Router + React 19 + React Query (TanStack) + ECharts (echarts + echarts-for-react v6). 3 страницы, ~16 компонентов, 11 endpoints.","BACKEND ФАЙЛЫ: backend/app/api/v1/analytics.py (роутер 11 endpoints), backend/app/services/analytics_queries.py (SQL-функции). Зарегистрирован в backend/app/main.py prefix /api/v1/analytics tags=['analytics']. Sync Session через get_db().","ENDPOINTS: GET /sverdl/market-pulse · /sverdl/quartirography?source=portfolio|deals · /sverdl/pipeline · /sverdl/districts · /sverdl/yandex-listings · /developers/top?limit · /developers/{id} · /developers/{id}/portfolio · /developers/history?ids=csv · /prinzip/insights (статика из PRINZIP_Strategy_Apr27) · /prinzip/districts (хардкод 8 районов из стратегии).","FRONTEND ФАЙЛЫ: frontend/src/app/analytics/{layout.tsx, page.tsx, prinzip/page.tsx, developers/page.tsx}. Компоненты frontend/src/components/analytics/*: ChartShell, KpiCard, Section, AnalyticsNav, MarketPulseChart, QuartirographyChart, PipelineChart, DistrictTreemap, YandexClassPie, DeveloperLeaderboard (sortable table), VelocityScatter, PrinzipVelocityChart, PrinzipQuartirographyPie, PrinzipGapBar, PrinzipDistrictsBar, InsightCards. lib: analytics-api.ts (React Query hooks), types/analytics.ts.","ROOT ИЗМЕНЕНИЯ: providers.tsx (QueryClientProvider, staleTime 5мин), layout.tsx обёрнут в Providers, page.tsx +ссылка на /analytics. tslib добавлен (требует echarts-for-react). package.json +echarts ^6 +echarts-for-react ^3 +tslib.","STATIC TS BUILD: ✅ npm run type-check clean, npm run build successful 9/9 routes. Размер /analytics 4.52KB, /analytics/prinzip 4.91KB, /analytics/developers 4.26KB First Load 116-120KB.","API SMOKE-TEST через uvicorn + SSH-туннель :15432 — все 11 endpoints отвечают 200, цифры совпадают с Sverdl_Quartirography_Report_Apr27 и PRINZIP_Strategy_Apr27 (sold% PRINZIP 48 / однушки 75.4% / 814 кв.; рынок Свердл Апр 2026 5686 тыс м² 29% 151 397 ₽).","КАК ЗАПУСКАТЬ ЛОКАЛЬНО: backend через docker-compose.yml ИЛИ uv run uvicorn app.main:app + переменная DATABASE_URL='postgresql+psycopg://gendesign:2J2SBPMKuS998fiwhtQqDhMI@127.0.0.1:15432/gendesign'. Frontend cd frontend && npm run dev. Прод: gendsgn.ru через Caddy.","ИЗВЕСТНЫЕ ОГРАНИЧЕНИЯ MVP: (1) /prinzip/districts хардкод из стратегии — нет геометрии районов в ekb_districts для real spatial-join; TODO добавить geometry. (2) Yandex listings в БД всего 12 строк (граф ошибочно говорил 258 — устаревший снимок). (3) v_developer_full_metrics.sverdl_price_avg всегда NULL — KPI ср. цены девелопера пока без данных. (4) Auth нет — публичный URL.","БАГ ИСПРАВЛЕН ВО ВРЕМЯ SMOKE: SQL :region_code в quartirography source=deals использовал не тот биндинг параметра — переименовал на :region_id. Также rosreestr_deals.deal_count это мультипликатор (max 2278) а не штучные сделки — заменено на COUNT(*).","СЛЕДУЮЩИЙ ШАГ: добавить geometry в ekb_districts → real spatial-join PRINZIP-ЖК → carto-карта на /analytics/prinzip. Альтернатива: импорт CRM PRINZIP (49 MB SQLite) → conversion-аналитика. Дальше — авторизация и /analytics/{region}/{developer} параметризация для повторного использования другими клиентами."]}
{"type":"entity","name":"DomRf_Kn_Scraper_Apr27","entityType":"deliverable","observations":["Дата: 27.04.2026. ПАРСЕР НАШ.ДОМ.РФ для КЖ (kn/object) и квартир (слоённый portal/table) реализован. План: C:\\\\Users\\\\user\\\\.claude\\\\plans\\\\crispy-waddling-swing.md.","REAL ENDPOINTS (проверены через chrome-devtools): GET /сервисы/api/kn/object?offset=0&limit=999999&place={place}&objStatus={s}&sortField=default&sortType=desc · GET /portal-kn/api/sales/portal/table?externalId={objId}. Auth header: Authorization: Basic MTpxd2U= (декодируется в 1:qwe — НЕ jwe как было в предыдущей памяти).","PARAMS КЛЮЧЕВЫЕ: place=66 (Регион Свердл) или place='0-4' (город ЕКБ). objStatus: 0=строящиеся, 1=архив-1 (~2 регион), 2=сданные/архив-2 (самый большой бакет). place=66 все 3 статуса = 442+2+1072 = 1516 ЖК (точно совпало с domrf_kn_objects).","СЕРВЕРНЫЙ ФИЛЬТР developers/regions НЕ РАБОТАЕТ — size/page/regions/developers все игнорируются. Поэтому фильтр по девелоперу реализован ЛОКАЛЬНО: фильтруем по developer.companyGroup из ответа. PRINZIP companyGroup=6208.","СТЕК: Playwright Chromium держит живую страницу «новостройки» (cookies+JA3 фингерпринт реального Chrome 147), fetch() из in-page context. httpx вариант НЕ РАБОТАЕТ — ServicePipe WAF проверяет TLS-fingerprint, различает Python httpx от Chrome даже с идентичными cookies. План был 'gibrid Playwright bootstrap + httpx' — НЕ СРАБОТАЛ, пивотнул на 'pure Playwright in-context'.","BACKEND ФАЙЛЫ: backend/app/services/scrapers/{stealth.py, domrf_kn.py, __init__.py}. backend/app/workers/celery_app.py (beat из settings.scrape_kn_cron). backend/app/workers/tasks/scrape_kn.py (с jitter 0..SCRAPE_KN_JITTER_SECONDS). backend/app/api/v1/admin_scrape.py (POST /api/v1/admin/scrape/kn + GET /runs, авторизация через X-Admin-Token = SCRAPE_ADMIN_TOKEN env). data/sql/50_schema_kn_extensions.sql + 50_scrape_kn_flats.py CLI.","FRONTEND: frontend/src/app/admin/scrape/page.tsx — кнопка «Запустить сейчас» (region, devs csv, fetch_flats checkbox) + таблица последних 20 прогонов из kn_scrape_runs (обновляется каждые 5 сек). Token хранится в localStorage.","КОНФИГ: env vars (settings) — SCRAPE_KN_CRON='15 4 * * mon' (любой 5-филд cron), SCRAPE_KN_JITTER_SECONDS=1800 (0..30мин random delay), SCRAPE_KN_DEFAULT_REGIONS='66' (csv), SCRAPE_KN_STATE_PATH='data/playwright_state.json', SCRAPE_ADMIN_TOKEN='' (пусто=выкл admin endpoint).","PLAYWRIGHT FINGERPRINT СНЯТ с локальной машины: data/playwright_state.json (7.3 KB, 26 cookies — AUTH_SESSION_ID, KC_AUTH_SESSION_HASH, ServicePipe NSC_*, Yandex tracking). Закоммичен в git для использования на сервере (worker подхватит при starting cold — ServicePipe видит returning user, не запускает JS-challenge). CLI flags --save-state PATH и --load-state PATH для периодического обновления.","DOCKER: docker-compose.yml +сервисы worker и beat (оба из образа backend). backend/Dockerfile +строка 'playwright install --with-deps chromium' — доп. ~80MB system libs.","СХЕМА-МИГРАЦИЯ ПРИМЕНЕНА: PK сняты с domrf_kn_flats.id и domrf_kn_objects.obj_id, заменены на UNIQUE (id|obj_id, snapshot_date). +индексы (region_cd, snapshot_date). +таблица kn_scrape_runs (журнал прогонов). Backfill region_cd=66 на Антоновых flats: 0 рядов затронуто (их obj_id не матчился с kn_objects).","SMOKE-ТЕСТ PRINZIP ПРОШЁЛ: 4 минуты, run_id=2 в kn_scrape_runs status='done'. Получено: place=66 × (status 0,1,2) = 442+2+1072 = 1516 объектов, локальный фильтр по companyGroup=6208 = 28 PRINZIP ЖК (= jk_count в v_developer_full_metrics!) + 826 квартир (с 814 agg_flats_total разница +12). 31 request total, 22 из них = 404 для сданных (квартиры уже нет в продаже — ок).","TYPE COERCION ИСПРАВЛЕН ДЛЯ BOOLEAN (0/1→bool), DATE ('YYYY-MM-DD'/'DD-MM-YYYY HH:MM:SS'/'IV кв. 2028' → последний день квартала), TEXT (problem_flag из int).","РАСПИСАНИЕ + ПЛАВАЮЩИЙ СТАРТ + КНОПКА выполнены: cron из SCRAPE_KN_CRON env, внутри таска random delay 0..SCRAPE_KN_JITTER_SECONDS берёт время, ручной триггер передаёт skip_jitter=True для немедленного старта.","СЛЕДУЮЩИЙ ШАГ: 1) Развёрнуть worker+beat в docker-compose, проверить celery beat schedule в живюю. 2) Добавить link на /admin/scrape с главной (пока только по прямому URL). 3) Full РФ-sweep (89 регионов) с multi-region cron после стабилизации Свердл. 4) Изучить /сервисы/api/object/{id}/sale_graph + sales_agg для time-series по продажам (видели в нетворке объектной страницы).","EXTRAS-ЭНДПОЙНТЫ ДОБАВЛЕНЫ (per-КЖ, после 27.04.2026 вечер): /сервисы/api/object/{id}/sale_graph?type=apartments|parking (time-series продаж), /sales_agg (текущие агрегаты 3 типа), /infrastructure (POI), /construction/progress/photo (мета+binary).","EXTRAS-ТАБЛИЦЫ: domrf_kn_sale_graph (obj_id, report_month, type, realised, contracted, area_sq, price_avg, snapshot_date), domrf_kn_sales_agg (obj_id, type ∈{apartments,nonliv,parking}, name, total, realised, perc), domrf_kn_infrastructure (нормализованная POI с lat/lon/dist_m/category), domrf_kn_photos (метаданные + local_path к binary). Schema: data/sql/51_schema_kn_extras.sql.","FAILURE LOG: kn_scrape_failures (run_id, obj_id, endpoint, full_url, http_status, error, body_preview, occurred_at). API GET /api/v1/admin/scrape/failures?run_id=N. В admin UI раскрывающийся блок с кнопкой «копировать URL» для ручной проверки в Chrome.","CLI РАСШИРЕН 50_scrape_kn_flats.py: флаги --no-extras / --download-photos / --no-flats / --probe URL. Probe поднимает Playwright-сессию и дёргает один URL — полезно для дебага конкретного фейла.","DOCKER FIX (буг #25): uv.lock не был реген после добавления playwright+tenacity — uv sync --frozen игнорил новые депы. Надо всегда делать 'cd backend && uv lock' после изменения pyproject.toml. Также Dockerfile реструктурирован: Chromium-libs вынесены явно в apt-get install (libnss3, libnspr4, libdbus-1-3, libatk1.0-0, libatk-bridge2.0-0, libcups2, libdrm2, libxkbcommon0, libxcomposite1, libxdamage1, libxfixes3, libxrandr2, libgbm1, libasound2t64, libatspi2.0-0), playwright install chromium без --with-deps, перед rm -rf /var/lib/apt/lists/*. ENV PLAYWRIGHT_BROWSERS_PATH=/opt/playwright для shared chromium-cache.","DOCKER ОПТИМИЗИРОВАН (#16, 27.04 поздний вечер): backend/Dockerfile расщеплён на 2 таргета. target=runner (lean, ~1.6 ГБ) для backend/beat. target=runner-with-chromium (~2.9 ГБ) для worker. docker-compose.{yml,prod.yml} и .github/workflows/deploy.yml пушат 2 GHCR-образа: gendesign-backend + gendesign-worker. Экономия ~1.3 ГБ на backend image.","PER-OBJECT DRILL-IN (#15) ГОТОВ: 5 backend GET endpoints (/object/{id}, /sale_graph, /sales_agg, /infrastructure, /photos) + /prinzip/objects с sparkline-data. UI: новая страница /analytics/objects/[id] (KPI + sale-chart + POI-таблица с фильтром по категории + фото-галерея с lightbox), плюс PrinzipObjectsTable на /analytics/prinzip с sparkline в каждой строке и кнопкой Drill-in.","GitHub issues #13, #14, #15, #16 закрыты 27.04.2026 поздний вечер. README обновлён с разделами 'Запуск 442-sweep' + PRINZIP CRM в карте таблиц + ETL artefacts +52_schema/52_import."]}
{"type":"entity","name":"Prinzip_CRM_Pipeline_Apr27","entityType":"deliverable","observations":["Дата: 27.04.2026 поздний вечер. ПАЙПЛАЙН ДЛЯ ИМПОРТА PRINZIP CRM SQLite (analytics.prinzipevent.ru, 49 МБ, 102K заявок, 9K сделок) реализован, ждёт файла. GitHub #14 закрыт с instructions.","SCHEMA: data/sql/52_schema_prinzip_crm.sql — prinzip_leads (lead_id PK, source/channel, phone_hash SHA256[:16] + phone_last4, email_hash MD5, obj_interest soft FK к domrf_kn_objects, status, converted, deal_id) + prinzip_deals (deal_id PK, lead_id, closed_at, obj_id soft FK, deal_price, payment_type, mortgage_*) + 2 MV (funnel_monthly по месяцам×source, funnel_by_object по КЖ). Применено в прод.","IMPORT SCRIPT: data/sql/52_import_prinzip_crm.py. UPSERT по ID. PII-hashing при импорте (152-ФЗ). Использовать --inspect-only для discovery реальных колонок SQLite и подправить LEAD_FIELD_MAP/DEAL_FIELD_MAP. REFRESH MV автоматически в конце.","BACKEND: 3 endpoints в backend/app/api/v1/analytics.py — /prinzip/funnel/monthly?months=, /prinzip/funnel/by-source?months=, /prinzip/funnel/by-object. Используют MV быстрых выборок.","FRONTEND: 2 новых ECharts-компонента на /analytics/prinzip — PrinzipFunnelSankey (leads→engaged→converted by source, type=sankey) + PrinzipFunnelMonthly (бары leads/engaged/converted + линия conv%). Оба обрабатывают пустой dataset изящно (текст 'Нет данных CRM').","СЛЕДУЮЩИЙ ШАГ: user скачивает SQLite в data/raw/prinzip_crm.sqlite (в .gitignore), запускает импорт. Ожидаемые после импорта: SUM(deal_price)/1e9 ≈ 39.9 (млрд ₽), conversion 2025 ≈ 5.4%, пик 12.81% в 2023. UI будет живым автоматически после импорта."]}
{"type":"entity","name":"Route_Home","entityType":"ui_route","observations":["URL: /","Файл: frontend/src/app/page.tsx","Sitemap-страница с карточками-ссылками на все разделы. 3 секции: Аналитика (4 карточки), Админка (2), Generative (2). Footer со ссылками на /api/v1/docs, /health, GitHub."]}
{"type":"entity","name":"Route_Analytics_Sverdl","entityType":"ui_route","observations":["URL: /analytics","Файл: frontend/src/app/analytics/page.tsx","Свердловский рынок: 4 KPI-карточки + market-pulse line chart + парадокс «строят vs покупают» + pipeline + treemap районов ЕКБ + яндекс listings pie. Публичный доступ."]}
{"type":"entity","name":"Route_Analytics_Prinzip","entityType":"ui_route","observations":["URL: /analytics/prinzip","Файл: frontend/src/app/analytics/prinzip/page.tsx","PRINZIP drill-down: 4 KPI карточки + velocity vs benchmarks (toggle) + квартирография pie + gap-bar к рынку + районы ЕКБ + таблица 28 ЖК с sparkline + insight-карточки. Публичный (CRM-funnel вынесён в /admin/leads)."]}
{"type":"entity","name":"Route_Analytics_Developers","entityType":"ui_route","observations":["URL: /analytics/developers","Файл: frontend/src/app/analytics/developers/page.tsx","Топ-15 девелоперов: sortable leaderboard + velocity scatter + сравнение sold% по месяцам. drill-in через ?id="]}
{"type":"entity","name":"Route_Analytics_Object","entityType":"ui_route","observations":["URL: /analytics/objects/[id]","Файл: frontend/src/app/analytics/objects/[id]/page.tsx","Drill-in одного ЖК: 6 KPI + sale-chart (apartments+parking+price line) + POI-таблица с фильтром по категории/радиусу + фото-галерея с lightbox. Пример: /analytics/objects/60160 (Парк Победы)."]}
{"type":"entity","name":"Route_Admin_Scrape","entityType":"ui_route","observations":["URL: /admin/scrape","Файл: frontend/src/app/admin/scrape/page.tsx + admin/layout.tsx","Token-protected. Ручной запуск скрапера (регион, devs, extras, photos) + живая очередь Celery (active/reserved/scheduled) с кнопками '🛑 Прервать' (SIGTERM) и '⊘ Удалить из очереди' (revoke) + журнал прогонов + журнал ошибок с copy-URL."]}
{"type":"entity","name":"Route_Admin_Leads","entityType":"ui_route","observations":["URL: /admin/leads","Файл: frontend/src/app/admin/leads/page.tsx + admin/layout.tsx","Token-protected. CRM-воронка PRINZIP: Sankey leads→engaged→converted by source + monthly bars + 5 KPI карточек + 4 фильтра (поиск/статус/source/converted) + таблица лидов с пагинацией. PII (phone/email) хешированы, в UI только ***1234."]}
{"type":"entity","name":"Endpoint_Analytics_Object","entityType":"api_endpoint","observations":["GET /api/v1/analytics/object/{obj_id}","GET /api/v1/analytics/object/{obj_id}/sale_graph?type=apartments|parking","GET /api/v1/analytics/object/{obj_id}/sales_agg","GET /api/v1/analytics/object/{obj_id}/infrastructure?category=&max_distance=","GET /api/v1/analytics/object/{obj_id}/photos?limit=","GET /api/v1/analytics/prinzip/objects (с sparkline-data)","Источник: backend/app/api/v1/analytics.py + analytics_queries.py. Публичные."]}
{"type":"entity","name":"Endpoint_Admin_Scrape","entityType":"api_endpoint","observations":["POST /api/v1/admin/scrape/kn (trigger)","GET /api/v1/admin/scrape/runs (journal)","GET /api/v1/admin/scrape/failures?run_id=","GET /api/v1/admin/scrape/queue (Celery inspect: active/reserved/scheduled/workers)","POST /api/v1/admin/scrape/revoke {task_id, terminate}","Auth: X-Admin-Token. Файл: backend/app/api/v1/admin_scrape.py."]}
{"type":"entity","name":"Endpoint_Admin_Leads","entityType":"api_endpoint","observations":["GET /api/v1/admin/leads/ (фильтры: status/source/converted/obj_id/search/date_from/date_to + lim/off)","GET /api/v1/admin/leads/stats?months=12 (KPI)","GET /api/v1/admin/leads/sources (distinct list)","GET /api/v1/admin/leads/funnel/monthly?months=","GET /api/v1/admin/leads/funnel/by-source?months=","GET /api/v1/admin/leads/funnel/by-object","Auth: X-Admin-Token. Файл: backend/app/api/v1/admin_leads.py."]}
{"type":"entity","name":"Module_Scraper_Stealth","entityType":"code_module","observations":["backend/app/services/scrapers/stealth.py","BrowserSession — Playwright Chromium + cookie jar + storage_state load/save. get_json() в браузерном контексте (TLS-fingerprint = real Chrome 147). download_binary() для фото. Auth: Basic MTpxd2U= (1:qwe). Jitter 600-1500мс + concurrency 3."]}
{"type":"entity","name":"Module_Scraper_Kn","entityType":"code_module","observations":["backend/app/services/scrapers/domrf_kn.py","Endpoints для /сервисы/api/kn/object + portal/table + 4 extras (sale_graph/sales_agg/infrastructure/photos). place=66 для Свердл, objStatus 0/1/2 = 442+2+1072. Локальный фильтр по developer.companyGroup. _classify_and_log() — 404 для sale_graph/sales_agg не пишет в failures (ожидаемые для сданных)."]}
{"type":"entity","name":"Module_Celery_App","entityType":"code_module","observations":["backend/app/workers/celery_app.py + workers/tasks/scrape_kn.py","Beat schedule из SCRAPE_KN_CRON env (default '15 4 * * mon'). Random jitter 0-1800с внутри таска. SCRAPE_KN_DEFAULT_REGIONS csv. Ручные триггеры из admin endpoint передают skip_jitter=True."]}
{"type":"entity","name":"Docker_Multi_Target","entityType":"infra","observations":["backend/Dockerfile target=runner (lean, 1.6GB) для backend+beat. target=runner-with-chromium (2.9GB) для worker.","docker-compose.yml выбирает target per service.",".github/workflows/deploy.yml пушит 2 GHCR-образа: gendesign-backend + gendesign-worker.","Экономия 1.3GB на backend image."]}
{"type":"entity","name":"Docker_Auto_Cleanup","entityType":"infra","observations":["deploy.yml после pull вызывает: docker image prune -af --filter 'until=72h' + docker builder prune -af.","Разовая очистка 27.04: 21→13 GB (-8 GB).","Будущие деплои сами чистят image старше 72ч + build cache."]}
{"type":"entity","name":"PII_Compliance_152FZ","entityType":"policy","observations":["PRINZIP CRM импорт (data/sql/52_import_prinzip_crm.py): phone → SHA256[:16] + last 4 digits, email → MD5. raw никогда не попадают в БД. В UI только ***1234. Поддержка 152-ФЗ при будущих запросах удаления."]}
{"type":"entity","name":"Auth_Admin_Token","entityType":"policy","observations":["X-Admin-Token заголовок, значение из SCRAPE_ADMIN_TOKEN env. Пустая строка → admin endpoints отвечают 503 'admin disabled'. Неверный → 401 'invalid admin token'.","Активный токен в prod хранится в backend/.env (gitignored). В UI — localStorage после ввода на /admin/scrape, работает для обеих admin-вкладок."]}
{"type":"entity","name":"Stealth_Fingerprint_State","entityType":"infra","observations":["data/playwright_state.json (в git, 7.3 KB).","26 cookies вкл. AUTH_SESSION_ID, KC_AUTH_SESSION_HASH, ServicePipe NSC_*, Yandex tracking.","Обновляется через 'python data/sql/50_scrape_kn_flats.py --regions 66 --bootstrap-only --save-state data/playwright_state.json'.","Worker подхватывает в cold-start — ServicePipe видит returning user без JS-challenge."]}
{"type":"entity","name":"GitHub_Issue_13_Closed","entityType":"github_issue","observations":["#13 Расширить kn-scraper на 442 строящихся Свердл ЖК","Closed 27.04.2026. Инструкции в README «Запуск 442-sweep». Готов к UI/CLI запуску — кода нового не нужно."]}
{"type":"entity","name":"GitHub_Issue_14_Closed","entityType":"github_issue","observations":["#14 Импорт PRINZIP CRM SQLite","Closed 27.04.2026. Pipeline реализован — schema (52_schema_prinzip_crm.sql) + import script (52_import_prinzip_crm.py) + 6 endpoints + funnel UI в /admin/leads. Ждёт файла от user."]}
{"type":"entity","name":"GitHub_Issue_15_Closed","entityType":"github_issue","observations":["#15 API endpoints /api/v1/analytics/object/{id}/...","Closed 27.04.2026. 5 endpoints + /analytics/objects/[id] page + PrinzipObjectsTable с sparkline."]}
{"type":"entity","name":"GitHub_Issue_16_Closed","entityType":"github_issue","observations":["#16 Multi-target Dockerfile","Closed 27.04.2026. lean backend (1.6GB) + worker-with-chromium (2.9GB)."]}
{"type":"entity","name":"Endpoint_Recommend_Mix","entityType":"api_endpoint","observations":["POST /api/v1/analytics/recommend/mix","Body: {district_name, area_total_m2?, target_class?, months_window=12}","Response: {scope, buckets[5], summary, comparables[≤5]}","Файл: backend/app/api/v1/analytics.py","Pydantic: app/schemas/recommend.py · response_model=RecommendMixOutput"]}
{"type":"entity","name":"Module_Recommend_Query","entityType":"code_module","observations":["backend/app/services/analytics_queries.py :: recommend_mix(db, *, district_name, area_total_m2, target_class, months_window, region_code=66)","Возвращает dict (scope/buckets/summary/comparables). Через response_model FastAPI приводит к Pydantic.","Lookup района через ekb_districts ILIKE; исключает 'не определён'.","Класс multiplier через AVG price_from FROM yandex_realty_zk FILTER (WHERE obj_class=:cls).","Comparable ЖК: domrf_kn_objects WHERE addr ILIKE '%район%' AND obj_class match → LEFT JOIN domrf_kn_sales_agg для sold%."]}
{"type":"entity","name":"Schema_Recommend_IO","entityType":"code_module","observations":["backend/app/schemas/recommend.py","RecommendMixInput (district_name str, area_total_m2 float|None ge=100 le=500000, target_class Literal[Comfort/Comfort+/Business/Elite]|None, months_window int 3-36)","RecommendBucket (bucket, share_pct, deal_count, area_avg_m2, area_median_m2, price_p25/median/p75, units_planned, revenue_planned_rub)","RecommendComparable (obj_id, comm_name, dev_name, obj_class, flat_count, sold_perc)","RecommendMixOutput (scope dict, buckets, summary dict, comparables)"]}
{"type":"entity","name":"Module_Bucket_Distribution","entityType":"code_module","observations":["backend/app/services/analytics_queries.py :: _bucket_distribution(db, region_code, months_window) + _BUCKET_SQL","Вынесено отдельно чтобы переиспользовать при auto-extend до 24 мес.","Возвращает 5 бакетов: deals, area_avg, area_median, price p25/median/p75 (city-wide).","Бакетизация: <30 студия, 30-45 1к, 45-60 2к, 60-80 3к, 80+ 80+ м²."]}
{"type":"entity","name":"Route_Analytics_Recommend","entityType":"ui_route","observations":["URL: /analytics/recommend","Файл: frontend/src/app/analytics/recommend/page.tsx","Публичная (как другие /analytics/*).","Layout: 360px sticky form слева + основной поток справа (KPIs, charts, sliders, table, comparables, caveats).","Все вычисления выручки/weighted-avg клиентские по effectiveShares (после слайдеров)."]}
{"type":"entity","name":"Component_Recommend_Form","entityType":"ui_component","observations":["frontend/src/components/analytics/RecommendForm.tsx","Селект района из useDistricts() с фильтром 'не определён'.","Площадь (опц. 100..500000), класс (опц. Comfort/Comfort+/Business/Elite), окно 12/18/24 мес.","submit triggers useRecommendMix() mutation; кнопка disabled пока пустой район."]}
{"type":"entity","name":"Component_Recommend_Sliders","entityType":"ui_component","observations":["frontend/src/components/analytics/RecommendShareSliders.tsx","5 слайдеров с auto-rescale: при изменении одного, остальные пропорционально пересчитываются к (100-X)%.","Если у других нет массы — распределяет поровну. Round 1 decimal, drift compensation на изменённом слайдере.","Кнопка ↻ Сбросить к рекомендации (disabled когда не было правок). Бейдж '+X.X' рядом со значением показывает delta от API."]}
{"type":"entity","name":"Component_Recommend_Charts","entityType":"ui_component","observations":["Три ECharts-обёртки в frontend/src/components/analytics/:","RecommendBucketsChart.tsx — horizontal bar share% с двумя сериями (серый 'Рекомендация' / синий 'Ваше распределение'), barGap=-100%.","RecommendRevenueChart.tsx — stacked bar (1 категория) с цветовыми сегментами по бакетам, label 'млн ₽' если segment ≥5%.","RecommendBucketsTable.tsx — sortable таблица с p25/median/p75, units_planned, revenue. Алгоритм allocation клиентский.","Chart-серии reactive: пересчитываются при изменении effectiveShares/areaTotal."]}
{"type":"entity","name":"Component_Recommend_Comparables","entityType":"ui_component","observations":["frontend/src/components/analytics/RecommendComparables.tsx","Карточки 3-5 ЖК с comm_name/dev_name/obj_class/flat_count/sold% (цветной бейдж: green ≥50, amber 30-50, red <30).","Каждая карточка — Link на /analytics/objects/{obj_id}.","Grid auto-fill 260px."]}
{"type":"entity","name":"Hook_useRecommendMix","entityType":"code_module","observations":["frontend/src/lib/analytics-api.ts :: useRecommendMix()","useMutation (НЕ useQuery — это POST с body, нет кэширования).","POST /api/v1/analytics/recommend/mix · application/json","TypeScript типы в frontend/src/types/analytics.ts (RecommendMixInput/Output/Bucket/Comparable)."]}
{"type":"entity","name":"Window_Auto_Extend_24mo","entityType":"policy","observations":["Если в любом из 5 бакетов <30 сделок при months_window<24, recommend_mix автоматически расширяет окно до 24 мес для ВСЕХ бакетов (одинаковое окно для согласованности).","Добавляет warning 'Окно расширено до 24 мес' в summary.warnings.","scope.effective_window_months отражает реальное использованное окно (12/18/24)."]}
{"type":"entity","name":"Class_Multiplier_Yandex","entityType":"policy","observations":["Class multiplier = AVG(price_from) FILTER (WHERE obj_class=:cls) / AVG(price_from) overall — из yandex_realty_zk.","Если данных по классу нет → 1.0 + warning. target_class=None → 1.0 без warning.","Применяется к price_p25/median/p75 каждого бакета в ответе."]}
{"type":"entity","name":"Quartirography_Filter_Fix","entityType":"policy","observations":["В _BUCKET_SQL добавлены фильтры выбросов:","realestate_type_code='002001003000' (квартиры; 001=земля, 002=нежилые)","area BETWEEN 10 AND 200 (отсечь коммерческие площади 1974 м² в bucket 80+)","price_per_sqm BETWEEN 30000 AND 1000000","Без них bucket 80+ показывал 719 'сделок' с area_avg=1974 — это были склады/коммерция."]}
{"type":"entity","name":"Limit_District_Median_Null","entityType":"limitation","observations":["Все 8 районов в ekb_districts имеют median_price_per_m2 = NULL (импорт Antona не наполнил).","Текущее поведение recommend_mix: district_factor = 1.0 + warning 'коэффициент района = 1.0'.","Чтобы оживить district_factor — нужен ETL job, наполняющий ekb_districts.median/mean из rosreestr_deals (через парсинг addr → district mapping или geometry)."]}
{"type":"entity","name":"Limit_District_Geometry","entityType":"limitation","observations":["rosreestr_deals имеет только quarter_cad_number, без района. ekb_districts не имеет PostGIS-полигонов.","Поэтому в MVP recommend_mix bucket-распределение город-wide (регион 66). Район влияет ТОЛЬКО на ценовой коэффициент.","v2: добавить PostGIS-полигоны → spatial-join (точка→район) или (cad_quarter→район) → per-district demand."]}
{"type":"entity","name":"Endpoint_Photos_Serve","entityType":"api_endpoint","observations":["GET /api/v1/photos/{obj_id}/{file_id}?size=thumb|full","Файл: backend/app/api/v1/photos.py","size=thumb: WebP 320×240 q=70 из data/raw/domrf_photos/<obj>/<file>_thumb.webp.","Cache-Control: public, max-age=604800, immutable.","size=full: оригинал PNG/JPG из локалки или 302 redirect на DOM.РФ."]}
{"type":"entity","name":"Module_Photo_Thumbs","entityType":"code_module","observations":["backend/app/services/photos/thumbs.py :: make_thumbnail(src, size=(320,240), quality=70)","Pillow + ImageOps.fit (cover) + WebP encode.","thumb_path_for(src) → src.with_name(stem + '_thumb.webp').","Idempotent: skip if dst.exists() and not overwrite. Логирует ошибки и продолжает.","Зависимость: pillow>=10.4.0 в backend/pyproject.toml."]}
{"type":"entity","name":"Photo_Lazy_Fetch","entityType":"policy","observations":["При запросе thumb на фото без локальной копии — endpoint синхронно качает оригинал с DOM.РФ через httpx + Basic auth (1:qwe).","Сохраняет оригинал в data/raw/domrf_photos/<obj>/<file>.{png,jpg}, генерит thumb рядом, UPDATE-ит local_path/thumb_path/downloaded_at, отдаёт thumb.","Подтверждено: urllib + Basic auth работает (200 OK 3.3 МБ PNG) — Playwright-fingerprint не требуется для image CDN, в отличие от JSON API.","Last resort: 302 redirect на upstream если download failed."]}
{"type":"entity","name":"Schema_Photo_Thumb_Path","entityType":"infrastructure","observations":["data/sql/53_schema_kn_thumbs.sql — применена в прод 27.04.2026 поздний вечер.","ALTER TABLE domrf_kn_photos ADD COLUMN IF NOT EXISTS thumb_path TEXT;","CREATE INDEX idx_kn_photos_obj_visible ON domrf_kn_photos (obj_id) WHERE COALESCE(hidden, FALSE) = FALSE;","object_photos analytics-query возвращает thumb_url + full_url (всегда, ссылаются на наш backend)."]}
{"type":"entity","name":"Queue_Optimised_DB","entityType":"policy","observations":["GET /api/v1/admin/scrape/queue: 'active' читается из kn_scrape_runs WHERE status='running' (instant).","inspect.reserved() + inspect.ping() запускаются параллельно в ThreadPoolExecutor с дедлайном 0.8s.","queue_depth — Redis LLEN 'celery'. scheduled — пустой (мы не используем ETA).","Worst-case latency ~600ms vs ~8s раньше (4×inspect timeout=2s)."]}
{"type":"entity","name":"Zombie_Autocleanup","entityType":"policy","observations":["В начале /api/v1/admin/scrape/queue: UPDATE kn_scrape_runs SET status='zombie', finished_at=NOW(), error='auto-marked: no heartbeat 60+ min' WHERE status='running' AND started_at < NOW() - INTERVAL '60 minutes'.","Срабатывает при каждом обращении UI к /queue (poll каждые 3 сек).","Дополнительно: worker_ready hook режет на 5 минут (с heartbeat) — см. Worker_Ready_Hook."]}
{"type":"entity","name":"Redis_Singleton_Lock","entityType":"infrastructure","observations":["backend/app/workers/tasks/scrape_kn.py :: _region_lock(region_code, devs) context manager.","SET NX EX 7200s по ключу 'scrape:kn:lock:<region>:<devs_csv|*>'.","Если beat double-fire или два worker-а — второй сразу выходит {skipped:True, reason:'lock_held'} без INSERT.","TTL 2ч прикроет случай умершего worker (lock сам очистится).","Используется в scrape_kn_region и resume_kn_run одинаково."]}
{"type":"entity","name":"Resume_Checkpoint_Mechanism","entityType":"deliverable","observations":["Дата: 27.04.2026 ночь. Решает Bug_Worker_SIGKILL_Lost_Run.","Phase A в run_region_sweep: после fetch_objects+filter — upsert_objects + _insert_raw + UPDATE kn_scrape_runs SET objects_snapshot=:objs::jsonb, total_obj_count, heartbeat_at=NOW(). Один commit.","Phase B/C (per-object): каждые 10 объектов — _checkpoint(db, run_id, i+1) → UPDATE progress_obj_index, heartbeat_at + commit.","При resume_from_run_id: пропускаем Phase A, читаем objects_snapshot+progress_obj_index+params из старого run, INSERT нового run с resumed_from_run_id, продолжаем с start_index.","UPSERT-семантика всех таблиц защищает от дублей при reprocessing 10-объектового хвоста между checkpoint-ами."]}
{"type":"entity","name":"Schema_Resume_Columns","entityType":"infrastructure","observations":["data/sql/55_schema_scrape_resume.sql — применена в прод 27.04.2026 ночь.","ALTER TABLE kn_scrape_runs ADD: heartbeat_at TIMESTAMPTZ, progress_obj_index INT, total_obj_count INT, objects_snapshot JSONB, params JSONB, resumed_from_run_id BIGINT REFERENCES kn_scrape_runs(run_id).","INDEX idx_kn_scrape_runs_running_heartbeat ON (heartbeat_at) WHERE status IN ('running','resuming').","Размер objects_snapshot для Свердл sweep ~1-2 МБ JSONB на ряд (1516 объектов)."]}
{"type":"entity","name":"Task_Resume_Kn_Run","entityType":"code_module","observations":["backend/app/workers/tasks/scrape_kn.py :: resume_kn_run(run_id) Celery task.","Читает region_codes/developer_ids из исходного run, берёт Redis-lock, вызывает run_region_sweep(resume_from_run_id=N).","Не требует jitter — это срочный resume.","max_retries=2, name='tasks.scrape_kn.resume_kn_run'."]}
{"type":"entity","name":"Worker_Ready_Hook","entityType":"code_module","observations":["backend/app/workers/celery_app.py :: @worker_ready.connect _resume_zombie_runs(sender=None, **_kwargs).","Триггерится после каждого старта Celery worker (включая redeploy).","SELECT runs WHERE status='running' AND objects_snapshot IS NOT NULL AND COALESCE(heartbeat_at, started_at) < NOW() - INTERVAL '5 minutes' LIMIT 20.","UPDATE их в 'zombie' одним апдейтом (audit trail), затем enqueue resume_kn_run.apply_async([rid]) для каждого.","Защищён try/except — провал scan не валит worker."]}
{"type":"entity","name":"Module_Scrape_Log","entityType":"code_module","observations":["backend/app/services/scrapers/domrf_kn.py :: log_progress(db, run_id, message, *, level='info', stage=None, obj_id=None).","INSERT INTO kn_scrape_log (run_id, level, stage, obj_id, message). message[:500] чтобы не раздуть.","Best-effort: SQL ошибки swallowed → не валят sweep.","Расставлен в run_region_sweep на: start, fetch_objects (per status), filter_devs, phase_a, fetch_flats (каждые 25), extras (каждые 10), resume, done, failed."]}
{"type":"entity","name":"Schema_Scrape_Log_Table","entityType":"infrastructure","observations":["data/sql/54_schema_scrape_log.sql — применена в прод 27.04.2026 ночь.","kn_scrape_log (log_id BIGSERIAL PK, run_id BIGINT REFS kn_scrape_runs ON DELETE CASCADE, ts TIMESTAMPTZ DEFAULT NOW(), level TEXT CHECK in ('info','warn','error'), stage TEXT, obj_id INT, message TEXT NOT NULL).","Индексы: (run_id, ts DESC), (ts DESC). ON DELETE CASCADE — лог чистится с run."]}
{"type":"entity","name":"Endpoint_Scrape_Logs","entityType":"api_endpoint","observations":["GET /api/v1/admin/scrape/logs?run_id=&since_id=&limit=200 (max 1000).","Файл: backend/app/api/v1/admin_scrape.py.","Auth: X-Admin-Token. since_id — для инкрементального polling (передавай max log_id виденного).","Возвращает rows ORDER BY log_id DESC."]}
{"type":"entity","name":"UI_Scrape_Progress_Panel","entityType":"ui_component","observations":["Секция в frontend/src/app/admin/scrape/page.tsx :: 'Прогресс задач'.","Тёмная консоль (background #0f172a, моноширинный) с цветовой раскладкой INFO/WARN/ERROR.","Формат строки: 'HH:MM:SS LEVEL [run-N · stage · obj=X] message'.","useQuery(refetchInterval: 3000) с фильтром по run_id (input).","scroll-контейнер 360px maxHeight."]}
{"type":"entity","name":"Bug_Worker_SIGKILL_Lost_Run_Fixed","entityType":"bug","observations":["Симптом: при redeploy/SIGKILL/OOM worker умирал без вызова except/finally → row в kn_scrape_runs оставался status='running' навечно, вся работа sweep терялась.","Closed 27.04.2026 ночь. Resolved by Resume_Checkpoint_Mechanism + Worker_Ready_Hook + Schema_Resume_Columns.","User-reported: 'после авто деплоя умираю и остаются не завершенные зомби'."]}
{"type":"entity","name":"Bug_Beat_Double_Fire_Fixed","entityType":"bug","observations":["Симптом: 27.04 у user'а run_id=4 и run_id=5 стартовали в одну секунду (16:38:01) — beat double-fire или два beat-контейнера.","UI показывал два 'в работе' дубликата одного и того же региона.","Closed 27.04.2026 ночь. Resolved by Redis_Singleton_Lock в scrape_kn_region (SET NX EX). Второй выходит с skipped:True/lock_held без INSERT."]}
{"type":"entity","name":"Bug_Inspect_Slow_Queue_Fixed","entityType":"bug","observations":["Симптом: GET /admin/scrape/queue ждал до 8s (4 вызова inspect.* с timeout=2s последовательно).","User-reported: 'очередь так же долго получается'.","Closed 27.04.2026 ночь. Resolved by Queue_Optimised_DB (active из БД, inspect в ThreadPoolExecutor с дедлайном 0.8s)."]}
{"type":"entity","name":"Bug_RealEstate_Outliers_Fixed","entityType":"bug","observations":["Симптом: bucket 80+ в recommend_mix выдавал 719 'сделок' с area_avg=1974 м² и medianna 155K ₽/м² — это нежилые помещения / склады.","rosreestr_deals.realestate_type_code: 002001003000=квартиры, 002001001000=земля, 002001002000=нежилые.","Closed 27.04.2026 ночь. Resolved by Quartirography_Filter_Fix в _BUCKET_SQL."]}
{"type":"entity","name":"Photo_Storage_Pipeline","entityType":"deliverable","observations":["Дата: 27.04.2026 поздний вечер. Кеширование thumb-копий фото DOM.РФ на backend.","Архитектура: scraper скачивает оригинал PNG/JPG → Pillow генерит 320×240 WebP q=70 рядом → path в thumb_path колонке.","Endpoint /api/v1/photos/{obj}/{file}?size=thumb|full отдаёт из локалки (FileResponse, Cache-Control 7d).","Lazy fetch при первом запросе thumb на фото без локальной копии (httpx + Basic auth).","Frontend перешёл с Next/Image на прямой <img src={thumb_url}> — backend выдаёт уже оптимизированный WebP, никаких cold-hit оптимизатора в dev.","lightbox использует full_url — выдаёт оригинал или redirect на DOM.РФ."]}
{"type":"entity","name":"Recommend_Level1_Apr27","entityType":"deliverable","observations":["Дата: 27.04.2026 ночь. Реализован Уровень 1 rule-based рекомендатора квартирографии. База для ML v2.","Алгоритм: city-wide ДДУ-сделки Свердл (rosreestr_deals) бакетизируются по площади (5 бакетов) × дистрикт multiplier (median_price ratio) × класс multiplier (yandex_realty_zk).","Allocation: если задан area_total_m2 — units_planned = round(allocated/area_avg), revenue = units × area_avg × price_median.","User-confirmed дизайн-решения: input=district_name, class через yandex_realty_zk, output=4 секции, slider auto-rescale, fallback 24мес при <30 сделок.","Реальные цифры для Свердл 12 мес (после фильтров): студии 72 сделок/119K₽, 1к 27/105K, 2к 12/105K, 3к 10/154K, 80+ 73/164K."]}
{"type":"entity","name":"Session_Resume_Recommend_Apr28_2026","entityType":"event","observations":["Дата: переход 27→28.04.2026 ночь. Продолжение Session_End_Apr27_2026.","СДЕЛАНО ЗА СЕССИЮ (ссылки на entity):","1. Photo_Storage_Pipeline (Pillow тхумбы + endpoint /api/v1/photos + lazy fetch + frontend переход с Next/Image).","2. Queue_Optimised_DB + Zombie_Autocleanup + Redis_Singleton_Lock (исправили 8s→0.6s латенси и beat double-fire).","3. Module_Scrape_Log + Schema_Scrape_Log_Table + Endpoint_Scrape_Logs + UI_Scrape_Progress_Panel (живой лог прогресса в админке).","4. Resume_Checkpoint_Mechanism + Schema_Resume_Columns + Task_Resume_Kn_Run + Worker_Ready_Hook (resume после redeploy с checkpoint каждые 10 объектов).","5. Recommend_Level1_Apr27 + Endpoint_Recommend_Mix + Module_Recommend_Query + Schema_Recommend_IO + Module_Bucket_Distribution + Route_Analytics_Recommend + 5 UI-компонентов + useRecommendMix.","BUGS CLOSED: Bug_Worker_SIGKILL_Lost_Run_Fixed, Bug_Beat_Double_Fire_Fixed, Bug_Inspect_Slow_Queue_Fixed, Bug_RealEstate_Outliers_Fixed.","OPEN TODOs (новые): Limit_District_Median_Null — нужен ETL для наполнения ekb_districts.median_price; Limit_District_Geometry — PostGIS-полигоны районов для per-district demand.","ПРОД SCHEMA: 4 новые миграции применены: 53_kn_thumbs.sql, 54_scrape_log.sql, 55_scrape_resume.sql, плюс изменения в domrf_kn_photos (thumb_path) и kn_scrape_runs (heartbeat_at, progress_obj_index, total_obj_count, objects_snapshot, params, resumed_from_run_id).","ПРИОРИТЕТЫ НА СЛЕДУЮЩУЮ СЕССИЮ: 1) ETL ekb_districts.median из rosreestr_deals (оживит district_factor в recommend_mix). 2) PostGIS-полигоны РАЙОНОВ ЕКБ для spatial-join. 3) PRINZIP CRM импорт (ожидает SQLite). 4) Тест resume в проде (запустить sweep × restart worker × проверить '♫ Resume from index N')."]}
{"type":"entity","name":"Bug_SQLAlchemy_DoubleColon_Cast","entityType":"bug","observations":["Системный баг: SQLAlchemy 2.0 + psycopg3 ИГНОРИРУЕТ привязку в конструкции :name::type. Парсер named-bind видит :name, но ::type не распознаётся как PostgreSQL cast → остаётся литералом в скомпилированном SQL.","Симптом: psycopg.errors.SyntaxError: syntax error at or near ':' на INSERT/UPDATE.","Решение (canonical): всегда использовать CAST(:name AS type) вместо :name::type.","Найден в 5 местах (28.04.2026): исправлены. analytics_queries.py:1222 (recommend_mix comparables :cls::text) · domrf_kn.py:1024 (resume INSERT :rc/devs/params/objs::*) · domrf_kn.py:1060 (new run INSERT :params::jsonb) · domrf_kn.py:1144 (Phase A snapshot UPDATE :objs::jsonb) · admin_leads.py:70 (lead filter :date_to::date).","Эффект бага: 100% блокировка run_region_sweep на INSERT, worker принимал task'и но никогда не создавал run_id."]}
{"type":"entity","name":"Pattern_CAST_AS_Type","entityType":"policy","observations":["Использовать CAST(:name AS type) в любых SQL-выражениях SQLAlchemy text() вместо :name::type.","Обратный паттерн ARRAY[:rc]::int[] РАБОТАЕТ — :: приклеено к закрывающей скобке, а не к bind-name.","Правило проверки перед PR: grep -nE ':[a-z_]+::[a-z]' backend/app — должен выводить пустоту.","Это попадало в 4 разных PR'а (recommend_mix, run_region_sweep refactor, admin_leads filter) — выработать lint-правило с ruff или pre-commit на будущее."]}
{"type":"entity","name":"Recommend_Velocity_Calculator_Apr28","entityType":"deliverable","observations":["Дата: 28.04.2026. Расширение Recommend_Level1_Apr27 — live-калькулятор 'цена ↔ темп ↔ срок ↔ ликвидность'.","По запросу Антона для CEO: 'Изменил цену → изменилась скорость продаж. Изменил срок → система показала какая цена/ассортимент нужны. Изменил ассортимент → изменилась ликвидность, средний чек, темп.'","Архитектура: API выдаёт BASELINE (velocity_baseline + elasticity коэффициент). Все слайдеры и target_months рассчитываются КЛИЕНТСКИ — без round-trip.","Новые компоненты: Component_Recommend_Velocity_Panel + Component_Recommend_Liquidity_Chart. Расширены: BucketsTable (+колонки Темп/Срок), RecommendForm (+target_months input).","Headline для CEO: 'Цена × выручка · срок · чек · темп · ликвидность' одной тёмной плашкой."]}
{"type":"entity","name":"Module_Velocity_Baseline","entityType":"code_module","observations":["backend/app/services/analytics_queries.py :: _velocity_baseline(db, *, region_code, district_name, target_class)","SQL: median+avg из domrf_kn_sale_graph WHERE type='apartments' за 24 мес для ЖК в (район+класс) через obj_pool с addr ILIKE район.","Результат: {realised_per_month_avg, realised_per_month_median, objects_count, observations}.","Если sale_graph пуст — fallback на rosreestr deals/month (city-wide). Сейчас sale_graph покрывает 2 ЖК, поэтому в 99% случаев идёт fallback."]}
{"type":"entity","name":"Module_Elasticity_Coef","entityType":"code_module","observations":["backend/app/services/analytics_queries.py :: _elasticity_coef(db, *, region_code, district_name, target_class)","SQL: regr_slope(LN(realised), LN(price_avg)) + regr_r2 на sale_graph за 36 мес для (район+класс).","Выдаёт {elasticity, r2, n, source: 'regression'|'fallback'}. fallback = -1.5 при n<30 или r2<0.1 или slope>=0.","Используется во фронте для расчёта velocity = base × price_factor^elasticity."]}
{"type":"entity","name":"Module_Required_Price_Factor","entityType":"code_module","observations":["backend/app/services/analytics_queries.py :: внутри recommend_mix (пункт 5c).","Inverse mode: если target_months задан, система решает required_price_factor = (total_units / target_months / base_total_velocity)^(1/elasticity).","Если < 0.7 → warning 'скидка >30% нереалистична, рассмотри сдвиг ассортимента'.","В UI: 'Применить →' кнопка копирует значение в price_factor слайдер (обрезая в [0.85, 1.15])."]}
{"type":"entity","name":"Module_Liquidity_Score_24mo","entityType":"code_module","observations":["Клиентский расчёт в RecommendVelocityPanel.tsx + backend дублирует в recommend_mix пункте 5d.","Формула: liquidity = Σ (min(1, 24/months_to_sellout) × units_planned) / total_units × 100. Диапазон 0..100.","Цветовые пороги: ≥0a7a3a (зелёный) >=70, #9a6700 (жёлтый) 40–⋅0, #b3261e (красный) <40."]}
{"type":"entity","name":"Component_Recommend_Velocity_Panel","entityType":"ui_component","observations":["frontend/src/components/analytics/RecommendVelocityPanel.tsx","4 больших KPI: Средний чек / Срок реализации / Темп продаж / Ликвидность (светофор).","Slider price_factor 0.85..1.15 step=0.01 — live recompute всех KPI по формуле base × pf^elasticity.","Inverse-mode плашка когда target_months задан: показывает required_price_factor + кнопка 'Применить'.","Нижняя подпись 'Эластичность -1.5 (регрессия sale_graph: R²=X, n=N или fallback)' — для CEO-легитимности."]}
{"type":"entity","name":"Component_Recommend_Liquidity_Chart","entityType":"ui_component","observations":["frontend/src/components/analytics/RecommendLiquidityChart.tsx","ECharts line+area: кумулятивные % продаж по месяцам 0..36, пунктир-markline на 24 мес.","При изменении priceFactor или mix-слайдеров кривая live пересчитывается.","Empty-state: 'Укажи площадь — посчитаем сколько и когда продастся'."]}
{"type":"entity","name":"Feature_Headline_CEO","entityType":"ui_component","observations":["Тёмная плашка сразу под H1 на /analytics/recommend.","Формат: '💼 «Район · Класс · X м²»: выручка млн ₽ · за ~Y мес · ср. чек Z М ₽ · темп W кв/мес · ликвидность V/100'.","Генеритсь backend'ом в recommend_mix.summary.headline — для screenshots/экспорта. Фронт обёртывает в div с emoji + bold район/класс/площадь.","Известная проблема: int(months) округляет 0.66 → 0 мес. TODO — использовать f'{x:.1f}'."]}
{"type":"entity","name":"Bug_Velocity_Mix_Static_OPEN","entityType":"bug","observations":["Симптом: при движении mix-слайдеров KPI Срок/Темп практически не меняются. Из скрина 28.04: 'Темп 159.0 кв/мес' статичен, 'Срок 0.8 мес' округляется в 0 мес в headline.","Причина: все 5 бакетов используют ОДИН market_velocity_per_month. Групповая формула baseVelocity = Σ(per_bucket_v × effective_share/share) ≡ city_total независимо от mix.","Установлен и отложен (Tier α work).","Решение: per-bucket velocity = bucket_market_share_in_total × city_v / N_competitors. Из rosreestr по бакетам отдельно (студии 710/24=30, 1к 1306/24=54, ит.д.) и поделить на N_active_ЖК в районе/классе."]}
{"type":"entity","name":"Bug_Velocity_Unrealistic_OPEN","entityType":"bug","observations":["Симптом: 'Срок реализации 0.8 мес' / 'Темп 159 кв/мес' / 'Ликвидность 100/100' — фантастичные числа.","Причина: при fallback (sale_graph пуст) market_velocity_per_month = total_deals / months_window. Для Свердл 3815 сделок / 24 = 159 кв/мес — темп РЫНКА, не проекта. 107 юнитов ÷ 159 = 0.7 мес — 'все сделки рынка идут у нас'.","Решение (Tier α): velocity_per_project = market_velocity / N_active_competing_ЖК (из domrf_kn_objects с site_status='Строящиеся' в (район+класс)). Для Свердл ~442 active → 0.36 кв/мес на ЖК → срок 100-300 мес.","Плюс prominent warning-badge в UI 'Темп грубый, нужен sale_graph для точных данных'."]}
{"type":"entity","name":"Bug_Recommend_500_CAST_Fixed","entityType":"bug","observations":["Симптом: POST /api/v1/analytics/recommend/mix возвращал 500 с 'syntax error at or near :' на строке :cls::text IS NULL.","Причина: SQLAlchemy не парсит :name::type (см. Bug_SQLAlchemy_DoubleColon_Cast).","Closed 28.04.2026. Resolved by Pattern_CAST_AS_Type в analytics_queries.py:1222 (CAST(:cls AS TEXT) IS NULL)."]}
{"type":"entity","name":"Bug_Phase_A_INSERT_500_Fixed","entityType":"bug","observations":["Симптом (28.04.2026 23:29): в /admin/scrape 'Кнопка не работает' — worker принимал task'и (task_received в kn_scrape_log), но НИКОГДА не создавал run_id в kn_scrape_runs.","Диагностика: docker compose logs worker показал трейсбек 'syntax error at or near : LINE 8: :params::jsonb' на INSERT INTO kn_scrape_runs.","Причина: в 4 местах (resume INSERT, new run INSERT, snapshot UPDATE) были :name::jsonb / :name::int[] / :name::text[] — SQLAlchemy bug.","Closed 29.04.2026. Resolved by Pattern_CAST_AS_Type в domrf_kn.py:1024,1060,1144 и бонусом admin_leads.py:70 (:date_to::date).","Smoke: выполнил INSERT руками через SSH-тоннель — run_id=8 создан (и удалён вручную), SQL парсится ОК."]}
{"type":"entity","name":"Bug_Lock_Held_Silent_Fixed","entityType":"bug","observations":["Симптом: при повторном нажатии кнопки task_id возвращаетсь, но run_id не появляется. Никаких логов.","Причина: Redis-lock от зомби-воркера с TTL=2ч блокирует новые task'и · воркер своим retry получает lock_held и выходит без записи в БД.","Closed 28.04.2026 by: TTL_Lock_Reduction (7200→1800), Module_Lock_Diagnostic_Logs (task_received/skipped в kn_scrape_log), Endpoint_Release_Lock + Param_Force_Trigger + UI '🔓 Снять Redis-lock' кнопка."]}
{"type":"entity","name":"Endpoint_Release_Lock","entityType":"api_endpoint","observations":["POST /api/v1/admin/scrape/release-lock","Body: {region_code, developers}. Auth: X-Admin-Token.","Файл: backend/app/api/v1/admin_scrape.py.","Вручную удаляет Redis ключ 'scrape:kn:lock:<region>:<devs>'. Нужен для emergency-режима (зомби-воркер оставил lock).","Возвращает {released: bool, region_code, developers}."]}
{"type":"entity","name":"Param_Force_Trigger","entityType":"policy","observations":["Новый параметр в TriggerKnRequest: force: bool = False.","При force=True эндпоинт /admin/scrape/kn вызывает force_release_lock() ПЕРЕД apply_async — снимает зомби-lock.","Фронтенд: чекбокс '⚡ Force (снять lock)' в форме запуска (красный при включении).","Ответ содержит lock_was_released: bool — видно был ли lock."]}
{"type":"entity","name":"Module_Lock_Diagnostic_Logs","entityType":"code_module","observations":["backend/app/workers/tasks/scrape_kn.py :: _log_task_received(region, devs, task_id) и _log_task_skipped(region, devs, task_id, reason).","Пишут в kn_scrape_log с run_id=NULL (run_id не существует до Phase A INSERT). FK accept NULL.","task_received вызывается в первой строке scrape_kn_region и resume_kn_run.","task_skipped вызывается при lock_held.","Даёт UI понимание 'worker подхватил и что сделал' даже когда run_region_sweep не запускается."]}
{"type":"entity","name":"TTL_Lock_Reduction","entityType":"infrastructure","observations":["_LOCK_TTL_SECONDS в backend/app/workers/tasks/scrape_kn.py: 7200 (2ч) → 1800 (30мин).","Обоснование: full Свердл sweep идёт ~25-30 мин — 30 мин это потолок. Зомби-lock истекает за полчаса, не блокирует новые task'и в рабочий день.","Heartbeat-based autoclean в /queue endpoint по всё равно подхватит зомби-runs за 10 мин по heartbeat_at."]}
{"type":"entity","name":"Phase_A_Heartbeat_Tick","entityType":"code_module","observations":["Добавлено _checkpoint(db, run_id, 0) в run_region_sweep ПОСЛЕ каждого фетча objStatus (Phase A).","Phase A для 1516 ЖК идёт ~3 мин. Без heartbeat-tick новый 10-мин autoclean threshold мог бы ложно пометить легитимный sweep как zombie.","progress_obj_index ставится 0 (снапшот ещё не сохранён), но heartbeat_at = NOW() обновляется в каждой итерации фетча."]}
{"type":"entity","name":"Autoclean_Heartbeat_Threshold","entityType":"policy","observations":["Изменён фильтр zombie autoclean в /api/v1/admin/scrape/queue.","Было: status='running' AND started_at < NOW() - 60 minutes (резал валидные долгие sweep'ы).","Стало: status='running' AND COALESCE(heartbeat_at, started_at) < NOW() - 10 minutes (heartbeat обновляется каждые ~30 сек, 10 мин без него = точно мёртв).","COALESCE подхватывает legacy-runs без heartbeat по старому критерию."]}
{"type":"entity","name":"Deploy_Cache_State_Apr28","entityType":"infrastructure","observations":["Проверка 28.04.2026: GHA cache (cache-from/cache-to type=gha,scope=*) УЖЕ в .github/workflows/deploy.yml для всех 3 билдов (backend/worker/frontend). Не нужно добавлять.","Сделаны дополнительные исправления для фактического хита кэша:","1. .gitignore +*.tsbuildinfo (frontend/tsconfig.tsbuildinfo был tracked и менялся в каждом коммите → invalidate frontend context).","2. git rm --cached frontend/tsconfig.tsbuildinfo.","3. frontend/.dockerignore расширен: +.git +*.tsbuildinfo +.next/cache +tests +*.md +coverage.","4. backend/.dockerignore расширен: +.git +data/raw +data/raw_endpoints +*.log +*.md +.coverage.","5. backend/Dockerfile +RUN --mount=type=cache,target=/root/.cache/uv на uv sync. +RUN --mount=type=cache,target=/var/cache/apt на apt install (во всех 3 стейджах).","6. frontend/Dockerfile +RUN --mount=type=cache,target=/root/.npm на npm ci.","Ожидаемый эффект: 8 мин → 2-3 мин на типовых Python-правках."]}
{"type":"entity","name":"Tier_Alpha_Velocity_Overhaul_TODO","entityType":"feedback","observations":["Отложенная работа (Tier α, введён в плане 28.04.2026): переделка velocity-модели recommend_mix.","Части:","A. _active_competitors_count(db, district, class) — SELECT COUNT FROM domrf_kn_objects WHERE site_status='Строящиеся' AND addr ILIKE district AND obj_class=cls.","B. Per-bucket velocity = bucket_market_share × city_total_velocity / N_competitors. Отдельный темп для каждого bucket'а.","C. headline format: f'{months:.1f} мес' вместо int().","D. Warning-badge в RecommendVelocityPanel когда velocity_source==fallback.","E. Headline compact: 3 главных метрики вместо 5.","Делается ПОСЛЕ стабилизации скрапера (Bug_Phase_A_INSERT_500_Fixed)."]}
{"type":"entity","name":"Session_Apr28_Calc_Scraper_Apr28_2026","entityType":"event","observations":["Дата: 28.04.2026 вечер → ночь. Продолжение Session_Resume_Recommend_Apr28_2026.","СДЕЛАНО:","1. Recommend_Velocity_Calculator_Apr28 (live калькулятор цена↔темп↔срок↔ликвидность) + Module_Velocity_Baseline + Module_Elasticity_Coef + Module_Required_Price_Factor + Module_Liquidity_Score_24mo + Component_Recommend_Velocity_Panel + Component_Recommend_Liquidity_Chart + Feature_Headline_CEO.","2. Bug_Recommend_500_CAST_Fixed (CAST(:cls AS TEXT) вместо :cls::text).","3. Deploy_Cache_State_Apr28 (.gitignore tsbuildinfo, .dockerignore tighten, uv/npm/apt cache mounts).","4. Module_Lock_Diagnostic_Logs (task_received/skipped в kn_scrape_log) + Endpoint_Release_Lock + Param_Force_Trigger + TTL_Lock_Reduction (7200→1800) + Autoclean_Heartbeat_Threshold (60→10 мин) + Phase_A_Heartbeat_Tick.","5. Bug_Phase_A_INSERT_500_Fixed (4 места :name::type → CAST). Главный corner-case сессии — объясняет почему скрапер не работал 26+ часов.","6. Bug_Lock_Held_Silent_Fixed.","OPEN BUGS ПОСЛЕ СЕССИИ: Bug_Velocity_Mix_Static_OPEN, Bug_Velocity_Unrealistic_OPEN. Оба решает Tier_Alpha_Velocity_Overhaul_TODO.","ПРИОРИТЕТЫ НА СЛЕДУЮЩУЮ: 1) Развернуть Bug_Phase_A_INSERT_500_Fixed в прод, проверить что sweep реально проходит 1516 ЖК + 28K flats. 2) Tier_Alpha (Bug_Velocity_Mix_Static + Bug_Velocity_Unrealistic). 3) ЭТИЛЬАРНЫе тиры 1-3 предикта (mortgage rate impact, region trend multiplier, pipeline pressure, hedonic features, developer reputation)."]}
{"type":"entity","name":"Geo_District_Mapping_Apr29","entityType":"deliverable","observations":["Дата: 29.04.2026. Главная победа сессии — ЛОКАЛЬНОЕ решение Limit_District_Geometry: железная привязка ЖК ЕКБ к 8 районам через PostGIS-полигоны OSM.","Архитектура: Overpass API (admin_level=9 в bbox ЕКБ) → shapely сборка OSM way-members в MultiPolygon → ekb_districts_geom с GIST-индексом → ST_Contains UPDATE domrf_kn_objects.district_name.","Результат backfill: Академический 586/208 строящихся, Чкаловский 510/158, Верх-Исетский 288/80, Ленинский 284/98, Орджоникидзевский 266/58, Кировский 236/68, Октябрьский 204/50, Железнодорожный 204/39. NULL=454 ЖК вне ЕКБ (Первоуральск, Н.Тагил).","Эффект в recommend_mix: velocity_source переключился с 'rosreestr_fallback' на 'sale_graph' (Академический: 104 ЖК × 1872 точки), competitors_count 208 вместо fallback singleton, comparable ЖК реальные (ТЭН СТАРТ, Эхо леса, KORTROS Eleven)."]}
{"type":"entity","name":"Module_Fetch_Ekb_Districts","entityType":"code_module","observations":["data/sql/56_fetch_ekb_districts.py — CLI загрузчик Overpass API → PostGIS.","Overpass query: relation['boundary'='administrative']['admin_level'='9']['name'~'район'] в bbox ЕКБ (56.71..57.00 шир. / 60.42..60.95 долг.). Возвращает 8 relations.","shapely-ассемблинг: way-members рваные в OSM, polygonize() сшивает их в closed rings, .buffer(0) исправляет self-intersections.","Кэш в data/raw/ekb_districts.geojson (коммитится в git — повторно Overpass не дыбаем).","Flags: --force-refetch (игнор кэш), --dry-run (без БД).","OSM names → ekb_districts.district_name хардкод-мап из 8 районов ('Академический район' → 'Академический')."]}
{"type":"entity","name":"Schema_Ekb_Districts_Geom","entityType":"infrastructure","observations":["data/sql/56_schema_ekb_districts_geom.sql — применена в прод 29.04.2026.","CREATE TABLE ekb_districts_geom (district_name TEXT PK FK→ekb_districts, geom geometry(MultiPolygon, 4326), osm_id BIGINT, fetched_at TIMESTAMPTZ).","GIST index idx_ekb_districts_geom_geom для spatial-join performance.","8 районов залиты из OSM (osm_id 5803327..14040275). Площади ST_Area в диапазоне 5-50 км²."]}
{"type":"entity","name":"Schema_Kn_Objects_District_Column","entityType":"infrastructure","observations":["data/sql/57_kn_objects_district.sql — применена в прод 29.04.2026.","ALTER TABLE domrf_kn_objects ADD COLUMN district_name TEXT.","INDEX idx_kn_objects_district WHERE district_name IS NOT NULL.","Initial backfill UPDATE через ST_Contains(d.geom, ST_MakePoint(o.lon, o.lat)) для region_cd=66.","3032 ЖК Свердл: 2578 привязаны к 8 районам, 454 NULL (вне ЕКБ)."]}
{"type":"entity","name":"File_Ekb_Districts_Geojson_Cache","entityType":"infrastructure","observations":["data/raw/ekb_districts.geojson — коммитится в git.","FeatureCollection с 8 MultiPolygon-фичами. Properties: name (OSM), osm_id, admin_level=9.","Источник: Overpass API в 29.04.2026 в 7:57 утра. При обновлении OSM-бордеров перефетчить через --force-refetch."]}
{"type":"entity","name":"Module_Backfill_District_Names_Scraper","entityType":"code_module","observations":["backend/app/services/scrapers/domrf_kn.py :: _backfill_district_names(db, snapshot_date, region_code).","Вызывается в run_region_sweep ПОСЛЕ Phase A commit (когда свежие upsert_objects уже в БД).","UPDATE через ST_Contains только для region_cd=66 (другие регионы полигонов не имеют сейчас).","Best-effort: try/except, не валит sweep при сбое привязки."]}
{"type":"entity","name":"Pattern_OSM_Overpass_Admin_Level","entityType":"policy","observations":["Для России в OSM городские районы = admin_level=9. Город как целое = 8.","Прямой query: relation['boundary'='administrative']['admin_level'='9'](bbox) работает лучше чем area-based поиск (last раз area['name'='Екатеринбург'] → 0 элементов).","User-Agent header обязателен — Overpass банит default urllib UA."]}
{"type":"entity","name":"Bug_Recommend_Addr_ILIKE_Returns_Zero_Fixed","entityType":"bug","observations":["Симптом: несмотря на успешный ночной sweep (1516 объектов + 192K квартир + 7938 sale_graph rows), recommend_mix пишет 'недостаточно данных'.","Причина: фильтр addr ILIKE '%Академический%' даёт 0 объектов — все domrf_kn_objects.addr = 'Город Екатеринбург', без названия района.","Closed 29.04.2026 by Geo_District_Mapping_Apr29: в 4 местах в analytics_queries.py заменили 'addr ILIKE :dn' на 'district_name = :dn' (_velocity_baseline, _elasticity_coef, _active_competitors_count, comparable query)."]}
{"type":"entity","name":"Module_Graceful_Obj_Class_Degrade","entityType":"code_module","observations":["В recommend_mix: target_class_for_geo — если в районе нет ни одного ЖК с НЕ-NULL obj_class — фильтр по классу ОПУСКАЕТСЯ на уровне velocity/elasticity/comparable запросов.","class_multiplier (из yandex_realty_zk) на ценах продолжает работать.","Причина: kn-API возвращает obj_class=NULL для ВСЕХ 3032 ЖК Свердл (отдельный баг скрейпера). Без degrade фильтр obj_class='Comfort' режет всё в НОЛЬ.","Warning пользователю: 'obj_class не заполнен — фильтр по классу игнорируется'."]}
{"type":"entity","name":"Bug_Kn_API_Obj_Class_Always_Null_OPEN","entityType":"bug","observations":["Симптом: domrf_kn_objects.obj_class=NULL для ВСЕХ 3032 ЖК Свердл. SELECT obj_class, COUNT(*) GROUP BY obj_class даёт только (NULL, 3032).","Причина: kn-API возвращает фильтр по objClass но сам objClass в ответе пустой, или _norm_object не читает правильный ключ.","Временный обход: Module_Graceful_Obj_Class_Degrade игнорирует target_class в geo-запросах.","Реальный фикс: проверить реальные ключи kn-API response через chrome-devtools пробив, поправить _norm_object."]}
{"type":"entity","name":"Bug_Kn_Flats_Price_Per_M2_Sparse_OPEN","entityType":"bug","observations":["Симптом: domrf_kn_flats.price_per_m2 заполнен только для 288 из 192K квартир (0.15%). Практически все квартиры без цены.","Эффект на backfill ekb_districts.median_price_per_m2: сработало только для 2 районов (Орджоникидзевский, Октябрьский). 6 районов остаются median=NULL.","Причина: kn-API не возвращает price для большинства квартир в sales/portal/table респонсе.","Реальный фикс: разобраться почему price=NULL (пробив chrome-devtools), возможно другой ключ в JSON. Или: брать price из sales_agg вместо per-flat."]}
{"type":"entity","name":"Backfill_District_Median_From_Kn_Flats","entityType":"code_module","observations":["Сырой SQL: UPDATE ekb_districts SET median = (PERCENTILE_CONT(0.5) FROM kn_flats JOIN kn_objects ON district_name) WHERE n>=30.","Результат 29.04.2026: Орджоникидзевский=205051 (n=233), Октябрьский=191786 (n=55). Для расчёта district_factor оживило 2 из 8 районов.","При вызове recommend_mix: Орджоникидзевский district_factor=1.03 (выше city median), Октябрьский=0.97 (ниже).","Остальные 6 районов — median NULL, district_factor=1.0 + warning. Блокир Bug_Kn_Flats_Price_Per_M2_Sparse_OPEN."]}
{"type":"entity","name":"Component_Recommend_Page_Reorder_Apr29","entityType":"ui_component","observations":["frontend/src/app/analytics/recommend/page.tsx — реорганизация порядка секций.","Было: Velocity → Liquidity Chart → KPI strip (city-wide) → Buckets → Revenue → Sliders → Table → Comparable.","Стало: Headline → Velocity (с price slider) → SLIDERS MIX → Liquidity → District-KPI → Buckets → Revenue → Table → Comparable.","Причина: user 'хочу видеть как меняются параметры при изменении mix' — все контроли (цена+mix) выше результатов."]}
{"type":"entity","name":"Component_Recommend_District_KPI_Strip","entityType":"ui_component","observations":["Новый KPI-strip в page.tsx вместо старых city-wide дублей ('Район / Сделок / Weighted / Выручка' — все одинаковые между районами).","4 новых KPI: 'Конкуренты в районе' (с hint о scope), 'Sale_graph покрытие' (X ЖК / Y точек / fallback), 'District factor', 'Class multiplier'.","Все 4 меняются при переключении района. Старые city-wide вынесены в headline-плашку и velocity-panel."]}
{"type":"entity","name":"Cleanup_Unused_Vars_Recommend","entityType":"code_module","observations":["Убраны totalRevenue + weightedAvgPrice из page.tsx (были в useMemo но нигде не использовались после рефактора).","Single source of truth: backend.recommend_mix считает эти значения, фронт отображает из summary.headline и RecommendVelocityPanel."]}
{"type":"entity","name":"Pricing_Slider_Range_Expanded_Apr29","entityType":"policy","observations":["Диапазон Price ± slider: 0.85..1.15 (±15%) → 0.01..3.0 (−0.99..+2.0 = −99%..+200%).","min=0.01 (НЕ 0) чтобы избежать pf^elasticity = ∞ (при elasticity=-1.5 и pf=0).","Pydantic schema: RecommendMixInput.price_factor Field(ge=0.01, le=3.0).","Inverse-mode 'Применить required_pf' тоже клампит на [0.01, 3.0].","Практически для CEO-демо: -50% в цене → velocity × 0.5^-1.5 = ×2.83 (в почти 3 раза быстрее), +100% → ×0.35."]}
{"type":"entity","name":"Limit_District_Geometry_Closed","entityType":"limitation","observations":["Дата закрытия: 29.04.2026.","Изначально: rosreestr_deals имеет только quarter_cad_number, без района. ekb_districts не имела PostGIS-полигонов.","Решение: Geo_District_Mapping_Apr29 (Overpass API → PostGIS → spatial-join через lat/lon ЖК). Обходим отсутствие cad_quarter→район маппинга через kn_objects как мост (lat/lon → district).","Per-district demand работает в recommend_mix: 4 запроса используют district_name = :dn."]}
{"type":"entity","name":"Limit_District_Median_Partial","entityType":"limitation","observations":["Частично решен Limit_District_Median_Null (29.04.2026): 2 из 8 районов имеют median (Орджоникидзевский 205051, Октябрьский 191786) из kn_flats.","Остальные 6 = NULL: kn-API возвращает price для всего 0.15% квартир (Bug_Kn_Flats_Price_Per_M2_Sparse_OPEN).","Блокирующий fix: разобраться почему kn-API не отдаёт price (возможно другой ключ в JSON, или взять из sales_agg.price_avg).","Альтернативный путь (отложен): rosreestr_deals → cad_quarter → район через NSPD кадастровые полигоны."]}
{"type":"entity","name":"Session_GeoMapping_Apr29_2026","entityType":"event","observations":["Дата: 29.04.2026. Продолжение Session_Apr28_Calc_Scraper_Apr28_2026.","ГЛАВНОЕ: Geo_District_Mapping_Apr29 — PostGIS-полигоны 8 районов ЕКБ из OSM Overpass, backfill domrf_kn_objects.district_name, recommend_mix переведён на district_name = :dn (вместо addr ILIKE).","СДЕЛАНО:","1. Module_Fetch_Ekb_Districts (Overpass loader) + File_Ekb_Districts_Geojson_Cache + Schema_Ekb_Districts_Geom + Schema_Kn_Objects_District_Column + Module_Backfill_District_Names_Scraper.","2. Pattern_OSM_Overpass_Admin_Level (admin_level=9 для районов РФ).","3. Bug_Recommend_Addr_ILIKE_Returns_Zero_Fixed (4 места).","4. Module_Graceful_Obj_Class_Degrade (kn-API obj_class=NULL не валит фильтры).","5. Backfill_District_Median_From_Kn_Flats (2/8 районов).","6. Component_Recommend_Page_Reorder_Apr29 + Component_Recommend_District_KPI_Strip + Cleanup_Unused_Vars_Recommend.","7. Pricing_Slider_Range_Expanded_Apr29 (±15% → −99..+200%).","CLOSED: Limit_District_Geometry_Closed, Bug_Recommend_Addr_ILIKE_Returns_Zero_Fixed, Limit_District_Median_Partial.","OPENED: Bug_Kn_API_Obj_Class_Always_Null_OPEN, Bug_Kn_Flats_Price_Per_M2_Sparse_OPEN.","ПРОД SCHEMA: 2 новые миграции применены: 56_schema_ekb_districts_geom.sql + 57_kn_objects_district.sql. ekb_districts.median обновлён для 2 районов.","ПРИОРИТЕТЫ: 1) Разобраться с obj_class/price из kn-API (оба ОПЕН бага). 2) NSPD GeoJSON cad-кварталов для rosreestr-маппинга. 3) Этильбарные тиры 1-3 предикта."]}
{"type":"entity","name":"Tier2_District_Macro_Factors_Apr29","entityType":"deliverable","observations":["Дата: 29.04.2026. Расширение recommend_mix тремя district-специфичными факторами + макро-контекст для CEO.","Факторы: sat_factor (зрелость рынка), trend_factor (ускорение/выхлаждение 6мо), poi_factor (развитость района).","Результат (Comfort, 50K м²): Орджоникидзевский 31 мес vs Академический 58 мес — разнос 1.9x при одинаковых вводных параметрах.","Macro context: ставка ИЖК 7.84% (Свердл, Янв 2026) в footer headline для CEO-легитимности."]}
{"type":"entity","name":"Module_District_Saturation_Factor","entityType":"code_module","observations":["backend/app/services/analytics_queries.py :: _district_market_saturation(db, *, district_name).","Median sold% активных строящихся ЖК в районе из domrf_kn_sales_agg.perc.","Применение: sat_factor = 1 + (sold_median - 50) / 100 * 0.3 — ±15% при крайних (>50% зрелый → +bonus, <20% свежий → -penalty).","Требует ≥5 ЖК в районе с perc != NULL.","Данные (29.04.2026): Ленинский 48% (зрелый), Академический 38%, Кировский 29.5% (свежий). Разнос ~20пп."]}
{"type":"entity","name":"Module_District_Velocity_Trend","entityType":"code_module","observations":["backend/app/services/analytics_queries.py :: _district_velocity_trend(db, *, district_name).","Ratio recent_6mo / prior_6mo realised из domrf_kn_sale_graph (apartments). H1 2025 vs H2 2025+.","Применение: trend_factor = clamp(ratio, 0.7, 2.0) — блокировка экстремумов (Академический raw 6.66 в начале 2025).","Данные: все 8 районов НАРАСТАЮТ (ratio 2.07..6.66) — H1 2025 был холодным. Когда наберём 24+ мес истории — числа станут дифференцированными.","UI: в KPI strip 🚀 (>1.5 рынок ускоряется) / → (стабильный) / ❄ (<0.8 остывает)."]}
{"type":"entity","name":"Module_District_Poi_Score","entityType":"code_module","observations":["backend/app/services/analytics_queries.py :: _district_poi_score + _city_avg_poi_score.","Weighted POI count по РАЙОНУ: SUM(weight) per ЖК в радиусе 1000м, потом AVG по ЖК района.","Веса категорий: Метро 2.0, Транспорт 1.5, Медицина 1.3, Образование 1.2, Спорт 1.0, Продукты 0.8, Развлечения 0.7, Новостройки 0.0 (сами ЖК, не amenity).","Применение: poi_factor = 1 + (district / city_avg - 1) * 0.05 — ±5% влияние на ЦЕНЫ (не на velocity).","Сейчас ratios 0.99..1.02 — все районы ~city avg. Даст больше эффекта когда POI покрытие выравняется."]}
{"type":"entity","name":"Module_Current_Mortgage_Rate","entityType":"code_module","observations":["backend/app/services/analytics_queries.py :: _current_mortgage_rate.","SQL: title ILIKE 'Средневзвешенная ставка по ипотечным жилищным%' AND '%в рублях, %' AND value BETWEEN 1 AND 30.","Выдаёт 7.84% (Свердл, Янв 2026) — СО ЛЬГОТАМИ (семейная, IT, ДВ-ипотека входят в средневзвешенную).","Рыночная ставка без льгот ~20.5% (РБК, Янв 2026) — в БД НЕТ такой серии. UI footer явно пишет 'со льготами; рыночная ~20%'."]}
{"type":"entity","name":"Bug_Mortgage_Rate_5_57_Wrong_Match_Fixed","entityType":"bug","observations":["Симптом: scope.mortgage_rate_pct выдавал 5.57% вместо реальных 7.84%. User заметил: 'слишком маленькая'.","Причина: SQL filter title ILIKE '%ипотечн%жилищн%' слишком широкий — матчил 'ДОЛЮ ипотечных жилищных кредитов на ИЖС' (5.57%, это НЕ ставка). ORDER BY period DESC LIMIT 1 случайно брал эту строку.","Closed 29.04.2026 в Module_Current_Mortgage_Rate: title ILIKE 'Средневзвешенная ставка...' + '%в рублях, %' + value BETWEEN 1 AND 30. Теперь выдаёт 7.84%."]}
{"type":"entity","name":"Macro_Context_Mortgage_Rate_Apr29","entityType":"research","observations":["Дата: 29.04.2026. Проверено вебом (РБК, cbr.ru) по запросу user 'погугли про ставку'.","Рыночная ставка (без льгот) ПЕРВИЧКА Янв 2026: 20.49%. ВТОРИЧКА: 20.5%.","Средневзвешенная (с учётом льготных программ) Янв 2026: 7.6% по РФ, 7.84% по Свердл.","Ключевая ставка ЦБ ~21% (Ноябрь 2025+).","70% покупателей Comfort/Comfort+ подпадают под льготы (семейная основная — 6%); Business/Elite в большинстве берут рыночную ~20%.","БД cbr_mortgage_series имеет ТОЛЬКО средневзвешенную (с льготами), рыночной раздельно нет. UI footer явно уточняет это."]}
{"type":"entity","name":"Component_Tier2_KPI_Strip_Update","entityType":"ui_component","observations":["frontend/src/app/analytics/recommend/page.tsx — обновлён district-KPI strip.","4 KPI: Конкуренты / Sale_graph покрытие / Sold% медиана / Тренд 6 мес / Class × District (combined).","Sold% хинт: 'зрелый рынок' / 'свежий, мало распродано' / 'умеренная зрелость' с числом N ЖК.","Тренд: 🚀 (>1.5) / → (стабильный) / ❄ (<0.8) + ratio.","Class × District: перемноженный mult из 3 (class * district * poi) + breakdown в hint."]}
{"type":"entity","name":"Component_Headline_Macro_Footer","entityType":"ui_component","observations":["frontend/src/app/analytics/recommend/page.tsx — footer в headline-плашке под основной строкой.","Показывает: 📊 Средневзв. ИЖК 7.84% (Янв 2026, со льготами; рыночная ~20%) · POI 130/82 (выше среднего).","Отделён в визуале border-top с opacity 0.1, fontSize 12 · color #94a3b8."]}
{"type":"entity","name":"Component_Velocity_Panel_Methodology_Tier2","entityType":"ui_component","observations":["frontend/src/components/analytics/RecommendVelocityPanel.tsx — расширен methodology note.","Теперь показывает все 3 macro factors: 'sat ×0.96 (sold% 38) · trend ×2.00 (raw ×6.66 clamp 0.7..2.0) · POI ×1.02 (на цену)'.","Полная прозрачность для CEO: откуда каждая цифра."]}
{"type":"entity","name":"Limit_Trend_Always_Capped_OPEN","entityType":"limitation","observations":["Дата: 29.04.2026. trend_factor во всех 8 районах хлопается в max=2.0.","Причина: H1 2025 был холодным (мало сделок в свежевыпущенных ЖК) и sale_graph покрытие было тонким. recent_6mo / prior_6mo выходит всюду >2.0.","Решение отложено: когда наберём 24+ мес истории sale_graph (в мае/июне 2026), перевести trend window на H2 2025 vs H1 2026 — будут реальные ratios.","Пока эффект trend_factor одинаковый для всех районов (×2.0) — не дифференцирует их."]}
{"type":"entity","name":"Limit_POI_Factor_Tiny_OPEN","entityType":"limitation","observations":["Дата: 29.04.2026. poi_factor во всех районах в диапазоне 0.99..1.02.","Причина: POI покрытие равномерное по всем районам (1284 ЖК с POI из 1516 покрыты ровно), весовая формула даёт похожие числа.","Решение отложено: повысить sensitivity 0.05 → 0.15-0.20 или изменить формулу на percentile-rank вместо ratio. Или ввести разные weights для Comfort/Business (премиум покупатели больше ценят amenity).","POI категории: Новостройки 65K (игнор), Продукты 55K, Спорт 53K, Образование 48K, Медицина 5K, Развлечения 1.8K."]}
{"type":"entity","name":"Session_Tier2_Apr29_2026_Late","entityType":"event","observations":["Дата: 29.04.2026 днём. Продолжение Session_GeoMapping_Apr29_2026.","СДЕЛАНО:","1. Tier2_District_Macro_Factors_Apr29 — sat_factor + trend_factor + poi_factor + mortgage_rate.","2. 5 helpers: Module_District_Saturation_Factor + Module_District_Velocity_Trend + Module_District_Poi_Score + _city_avg_poi_score + Module_Current_Mortgage_Rate.","3. Component_Tier2_KPI_Strip_Update + Component_Headline_Macro_Footer + Component_Velocity_Panel_Methodology_Tier2.","4. Bug_Mortgage_Rate_5_57_Wrong_Match_Fixed + Macro_Context_Mortgage_Rate_Apr29 (верифицировано веб-поиском).","Smoke (Comfort, 50K м²): 5 районов, сроки 31..58 мес (разнос 1.9x). Орджоникидзевский 31, Кировский 34, Ленинский 39, Чкаловский 51, Академический 58. Чек 2.7-2.8 М ₽. Ликвидность 40/100.","OPEN BUGS: Limit_Trend_Always_Capped_OPEN (trend_factor везде max 2.0 пока sale_graph история тонкая), Limit_POI_Factor_Tiny_OPEN (±1-2% эффект).","OPEN BUG скрейпера (с прошлых сессий): Bug_Kn_API_Obj_Class_Always_Null_OPEN (kn-API отдаёт obj_class=NULL), Bug_Kn_Flats_Price_Per_M2_Sparse_OPEN (kn-API отдаёт price для 0.15% квартир)."]}
{"type":"entity","name":"Bug_Velocity_Region_Wide_Rosreestr_Fixed_Apr29","entityType":"bug","observations":["Симптом: «Верх-Исетский · 5 000 м²»: за ~3.7 мес, темп 33.6 кв/мес, ликвидность 100/100 — фантастика для одного ЖК.","Корень: bucket_market_velocities в analytics_queries.py (lines 1685–1693) использовал rosreestr_deals/window per bucket по ВСЕМУ region_code=66. Window auto-extend до 24mo → ~159 deals/mo на регион → после /sqrt(80 competitors) × sat × trend = 33.8 кв/мес total. Точно совпадает с UI-цифрой.","footer показывал «Базовый темп 4.2 кв/мес (sale_graph: 40 ЖК / 720 точек)», но это число НЕ использовалось в bucket-расчёте — лишь декоративно.","Фикс (29.04.2026):","1) market_vel_pm = sale_graph median per ЖК района (либо rosreestr-fallback / N_competitors → per-ЖК proxy).","2) bucket_market_velocities = market_vel_pm × bucket.share / 100 (аллоцируем per-ЖК baseline на размерные сегменты).","3) Удалена нормировка /sqrt(competitors) — market_vel_pm уже per-ЖК.","4) Removed import math (больше не нужен).","Результат для 5K м² по 8 районам ЕКБ: 7.5..18 мес (вместо 3.7). Между районами реальный разброс 2.4x: Октябрьский 7.5 → Академический 18.","Closed by: 3 правки в backend/app/services/analytics_queries.py:1627–1739."]}
{"type":"entity","name":"Bug_Mortgage_5_57_Stale_Deploy_Apr29","entityType":"bug","observations":["Симптом: footer показывал 5.57% (старая неправильная), хотя _current_mortgage_rate был исправлен в Bug_Mortgage_Rate_5_57_Wrong_Match_Fixed.","Не код-баг: DB напрямую отдаёт 7.84% (Январь 2026, 'Средневзвешенная ставка по ипотечным жилищным... в рублях, %', value BETWEEN 1 AND 30 — корректная строка).","Backend на проде не передеплоен с фиксом → продолжает кешировать старый ответ.","Action: nginx reload / pm2 restart backend → подхватит новый код, footer покажет 7.84%.","Документировано в плане crispy-swinging-gadget.md секция Approach — B."]}
{"type":"entity","name":"NSPD_API_Endpoints_Apr29","entityType":"research","observations":["NSPD geoportal v2 API: nspd.gov.ru — публичная аналитика недвижимости РФ.","ВАЖНО: WAF блокирует не-РФ IP (HTTP 403 + 'Rule: ...'). Для скрейпа нужен российский egress.","chrome-devtools MCP не помогает обойти — sandboxed Chrome у Anthropic тоже блокируется (тот же IP).","ПРОВЕРЕННО РАБОТАЮЩЕЕ: same-origin fetch со страницы NSPD у пользователя — WAF пропускает, certs OK.","ENDPOINTS:","1. GET /api/geoportal/v2/search/geoportal?thematicSearchId={id}&query={text} — основной search.","  thematicSearchId: 1=Объекты недвижимости, 2=Кадастровое деление, 4=Адм-тер деление, 5=Зоны и территории, 7=Терр зоны, 15=Комплексы.","  query=cad-номер квартала: id=2 → 1 polygon квартала; id=1 → до 20 features (земля+здания+помещения+машино-места+сооружения) внутри квартала.","2. GET /api/aeggis/v4/{layer_id}/wms?REQUEST=GetFeatureInfo&BBOX=...&I=256&J=256&FEATURE_COUNT=10&INFO_FORMAT=application/json — векторные данные слоя.","  FEATURE_COUNT > 10 → HTTP 500. Только 10 features per call.","3. POST /api/geoportal/v1/download/objects/csv — кнопка 'Скачать список'. CSV метаданных, не GeoJSON.","4. GET /api/geoportal/v1/layers-theme — список тематик (PKK, ARN, etc.).","5. GET /api/geoportal/v1/layers-theme-tree?themeId={id} — слои в тематике.","ТЕМАТИКИ:","- 1 (PKK): 63 слоя — Кадастровые округа/районы/кварталы (36071), Здания (36049), Объекты незавершенного строительства (36329), Кадастровая стоимость (37236).","- 665 (ARN): 12 слоёв — Объекты по площади 0-25/25-40/40-60/60-80/80-100/100+ м² (WMS+MVT)."]}
{"type":"entity","name":"Cad_Quarter_Scrape_Apr29","entityType":"deliverable","observations":["Дата: 29.04.2026. Цель — связать rosreestr_deals.quarter_cad_number ↔ domrf_kn_objects (lat/lon) через PostGIS spatial-join.","Schema: cad_quarters_geom (cad_number, geom MultiPolygon 4326) + cad_buildings (cad_num, geom geometry, cost_value, year_built, purpose, area, floors, addr).","ALTER domrf_kn_objects ADD cad_quarter, cad_building_num.","Pipeline (через debug-Chrome пользователя):","1. fetch /api/geoportal/v2/search/geoportal?thematicSearchId=2&query={cad} → polygon квартала","2. fetch /api/geoportal/v2/search/geoportal?thematicSearchId=1&query={cad} → 20 зданий + помещения + земля","3. Filter buildings by categoryName='Здания' AND cad_num LIKE '66:41:%' (исключить out-of-EKB).","4. Convert geometry to WKT (EPSG:3857), batch-INSERT в Postgres через mcp__postgres__execute_sql с ST_Transform→4326.","5. После полного scrape: backfill domrf_kn_objects.cad_quarter через ST_Contains.","Прогресс: schema готова, 5 quarters в БД (66:41:0105031, :0106002, :0106009, :0106021, :0106023). 669 осталось.","Estimate: 670 × 2 fetch × 700ms = 15-20 мин в browser + 134 × 5s INSERT = 12 мин = ~30 мин.","ВАЖНО: search id=1 включает здания из других округов (66:15, 66:36, 66:51 — Невьянский/В.Пышма/Красноуральск) с похожими суффиксами. Фильтр 'cad LIKE 66:41:%' обязателен.","Полные файлы артефактов: data/sql/58_schema_cad_quarters.sql, 58_fetch_cad_quarters_nspd.py (ineffective без РФ-IP), 59_backfill_obj_cad_quarter.sql, 60_v_zk_rosreestr_velocity.sql + data/raw/cad_quarter_list.txt."]}
{"type":"entity","name":"NSPD_Scrape_Complete_Apr30","entityType":"deliverable","observations":["Дата: 30.04.2026. Завершён полный скрейп NSPD кадастровых данных через debug-Chrome (обход WAF через same-origin XHR + JWT gosuslugi.ru auth).","ИТОГ: 709 cad-кварталов / 10590 зданий в БД. Покрытие свежих ДДУ-сделок Свердл (12mo): 91% (713/784).","Scope: ЕКБ (674 квартала из rosreestr_deals) + 43 пригорода с активными ДДУ за 12mo (Сысерть, Арамиль, В.Пышма, Сухой Лог, Богданович, Реж, Артёмовский).","Schema: cad_quarters_geom (cad_number PK, geom MultiPolygon 4326, raw_props jsonb) + cad_buildings (cad_num PK, geom Geometry, purpose, building_name, address, area, floors, year_built, year_commisioning, cost_value, registration_date, status, ownership_type, cultural_heritage, underground_floors, build_record_*, common_data_status, obj_type, raw_props jsonb).","Pipeline: chrome-devtools MCP browser → fetch NSPD endpoints (thematicSearchId=2 для квартала + =1 для зданий внутри) → save via 61_import_nspd_batch.py через SSH-tunnel localhost:15432.","Время: ~3-4 часа активной работы (с 60-90s drain интервалами + import batches).","Closed limitations: Limit_District_Geometry_Closed, Limit_District_Median_Partial (теперь rosreestr_deals → cad_quarter → ЖК работает).","Files: data/sql/58_schema_cad_quarters.sql, 61_import_nspd_batch.py (v2 with raw_props), data/raw/nspd_drain_*.jsonl + nspd_refetch_*.jsonl (50+ batch files)."]}
{"type":"entity","name":"NSPD_API_Endpoints_Reference","entityType":"reference","observations":["Дата: 30.04.2026. Полная карта NSPD API endpoints (из debug-Chrome обхода).","BASE: https://nspd.gov.ru","АУТХ: JWT через gosuslugi.ru SSO. JWT exp ~30 мин. Cookie: authAccessToken+authRefreshToken. Без auth — HTTP 403 на API (но статика проходит).","WAF: блокирует не-РФ IP на /api/* endpoints. chrome-devtools MCP sandboxed Chrome тоже блокируется (egress = Anthropic IP). РАБОЧИЙ ОБХОД: same-origin XHR со страницы nspd.gov.ru/map в браузере пользователя.","Endpoints:","1. GET /api/geoportal/v2/search/geoportal?thematicSearchId={id}&query={text}","  thematicSearchId: 1=Объекты недвижимости (земля+здания+помещения+маш-места+сооружения), 2=Кадастровое деление (квартал/район/округ), 4=Адм-тер деление, 5=Зоны, 7=Терр. зоны, 15=Комплексы.","  query=cad-номер: id=2 → 1 polygon квартала; id=1 → до 90 features (по 20 на категорию) внутри квартала.","2. GET /api/aeggis/v4/{layer_id}/wms?REQUEST=GetFeatureInfo&BBOX=...&I/J=&FEATURE_COUNT=10 — векторные данные слоя по bbox+pixel. FEATURE_COUNT > 10 → HTTP 500.","3. POST /api/geoportal/v1/download/objects/csv — CSV-экспорт выбранных объектов (но не GeoJSON).","4. GET /api/geoportal/v1/layers-theme — список тематик.","5. GET /api/geoportal/v1/layers-theme-tree?themeId={id} — слои в тематике.","Тематики: 1 (PKK, 63 слоя — Кадастровые квартал=36071, Здания=36049, Объекты незавершенного строительства=36329, Кадастровая стоимость=37236), 665 (ARN=Аналитика рынка недвижимости, 12 слоёв — объекты по площади 0-25/25-40/40-60/60-80/80-100/100+ м² WMS+MVT).","Geometry SRID: EPSG:3857 (web mercator). На стороне БД ST_Transform(3857→4326).","ВАЖНО: search id=1 включает здания из других кадастровых округов с похожими суффиксами. Фильтр 'cad_num LIKE \"66:41:%\"' обязателен."]}
{"type":"entity","name":"Cad_Buildings_Schema_v2","entityType":"schema","observations":["Дата: 30.04.2026. cad_buildings (10590 строк) — итоговая схема после v2 extension.","Колонки структурированные:","- cad_num TEXT PK — кадастровый номер здания (66:41:0108043:59)","- quarter_cad_num TEXT — родительский квартал (3 первых сегмента)","- geom Geometry(Geometry, 4326) — Point/Polygon/MultiPolygon","- purpose TEXT — Многоквартирный дом / Жилое / Жилой дом / Нежилое / Гараж","- building_name TEXT, readable_address TEXT","- area NUMERIC, floors TEXT (например '10-18')","- year_built INTEGER, year_commisioning INTEGER","- cost_value NUMERIC — кадастровая стоимость ₽","- registration_date DATE","- status TEXT — 'Учтенный' (1679) / 'Ранее учтенный' (8148)","- ownership_type TEXT, cultural_heritage TEXT, underground_floors TEXT","- build_record_area NUMERIC, build_record_type TEXT","- common_data_status TEXT, obj_type TEXT","- raw_props jsonb — ПОЛНЫЙ options-объект NSPD (для будущих запросов)","Распределение purpose: Нежилое 4040 / Многоквартирный дом 3245 / Жилое 1567 / Гараж 559 / Жилой дом 601.","Cross-validation: NSPD кадастровая стоимость per м² ≈ 30-40K ₽/м², рыночная (sale_graph) 130-244K — разница в 3-5×. Premium 50-90% типично, аномалии (-34% Белая Башня) сигнализируют outlier."]}
{"type":"entity","name":"Cad_Quarter_Backfill_Apr30","entityType":"deliverable","observations":["Дата: 30.04.2026. Spatial-join: domrf_kn_objects.cad_quarter заполнен через ST_Contains(cad_quarters_geom.geom, lat/lon).","Coverage: 2262/2578 ЖК (88%) ЕКБ привязаны к cad_quarter, 237 уникальных кварталов используются.","По районам: Академический 96%, Октябрьский 93%, Железнодорожный 93%, Ленинский 88%, Чкаловский 87%, Кировский 87%, Орджоникидзевский 80%, Верх-Исет 69%.","По статусу: Строящиеся 357/442 (81%), Сданные 774/1073 (72%), Проблемные 1/2 (50%).","ЖК↔здание матч через ST_DWithin(50м): 349 ЖК сматчены с конкретным МКД из cad_buildings.","Топ-точные совпадения (ошибка 36-77м): ЖК «Сибирский сад» → 66:41:0603016:198, Атлас Ривер → 66:41:0508075:1406, Парковый квартал 2.0 → 66:41:0402030:2391 (yc=2025)."]}
{"type":"entity","name":"Sprint1_Plan_May2026","entityType":"plan","observations":["Дата создания плана: 30.04.2026. План реализации Sprint 1 (нед 1-2 мая).","Tier 1 — критичный путь:","A. NSPD-scraper индустриализация (~2 дня): Playwright + gosuslugi SSO auth → backend/app/services/scrapers/nspd_kn.py + Celery task scrape_nspd_region + nspd_scrape_runs table + crontab(day=20, month='2,5,8,11'). 80% переиспользование domrf_kn.py паттернов.","B. Recommend_mix Tier 3 (~3 дня): per-bucket elasticity вместо скаляра. SQL window-functions по area_bucket + frontend per-bucket curve.","C. NSPD кадастр vs sale_graph cross-check UI (~1 день): premium % колонка + warning badge для аномалий >50%.","D. Issue #4 SENTRY_RELEASE (~30 мин): SSH→.env.runtime + sentry_sdk init.","Итого Sprint 1: ~7 дней работы.","План в C:\\Users\\user\\.claude\\plans\\next-iteration-roadmap.md."]}
{"type":"entity","name":"Sprint2_Stage1_Generative","entityType":"plan","observations":["Sprint 2 (нед 3-6): Stage 1 Generative MVP — продуктовое ядро, делает gendesign продаваемым.","Issue #5 Stage 1a (~5 дней): app/services/generative/geometry.py (Shapely парсер GeoJSON, отступы, placement grid), Pydantic ConceptInput/Output, frontend Leaflet drag-drop + 3 таба-варианта (заглушки).","Issue #12 Stage 1b (~5 дней): Greedy алгоритм 3 стратегии (max_area/max_insolation/balanced) с STRtree коллизиями. Цель: 3 варианта ≤15сек на 1 га. Frontend визуализация корпусов + ТЭП метрики.","Issue #6 Stage 1c (~6 дней): services/generative/teap.py + financial.py (revenue/cost/IRR), экспортеры PDF/Excel/DXF, API POST /concepts/{id}/export. Завершение Stage 1.","Итого: ~16 дней. После этого Stage 1 = продаваемый артефакт для встреч с инвесторами."]}
{"type":"entity","name":"Sprint3_Stage2_SiteFinder","entityType":"plan","observations":["Sprint 3 (нед 7-10): Stage 2 Site Finder MVP — конец продуктового vision.","Issue #7 Stage 2a (~5 дней): site_finder/parser.py (ПКК Rosreestr, GeoAlchemy2 Parcel модель, ≥1000 участков ЕКБ) + workers/sales_tracker.py (шахматки топ-7 застройщиков: Атомстрой, Брусника, ТЭН, Стройтек, Прогресс, УГМК, КОРТРОС).","Issue #8 Stage 2b (~5 дней): scorer.py (3-4 критерия: distance_to_center, POI_density, district_price + опц. velocity_score), POST /parcels/search ≤500мс, frontend Mapbox color-graded markers + sidebar filters.","Issue #9 Stage 2c (~3 дня): кнопка 'Обсчитать концепцию' на карточке участка → pipe в /concepts. + Реестр ПО подача (60-180 дней). + финмодель 5-летняя для инвест-deck.","Pre-existing data: NSPD cad_quarters (709 кварталов) переиспользуем как один из источников для site_finder. ПКК даст vri+address+другие слои."]}
{"type":"entity","name":"GitHub_Issues_Open_Apr30","entityType":"reference","observations":["8 открытых issues на 30.04.2026.","#3 Selectel/Yandex S3 backup setup — ❌ ИСКЛЮЧЕНО пользователем (не делаем).","#4 SENTRY_RELEASE deploy.yml tracking — Tier 4 (~30 мин).","#5 Stage 1a Shapely service + API contract — Sprint 2.","#6 Stage 1c TEAP + finmodel + экспорты PDF/Excel/DXF — Sprint 2.","#7 Stage 2a ПКК parser + sales_tracker — Sprint 3.","#8 Stage 2b Scoring + API + UI — Sprint 3.","#9 Stage 2c Integration + реестр ПО + финмодель — Sprint 3.","#11 Антон onboarding к knowledge-graph (Claude Desktop + MCP) — Tier 4 (~30 мин документации).","#12 Stage 1b Greedy алгоритм 3 стратегии STRtree — Sprint 2."]}
{"type":"entity","name":"Open_Limitations_Apr30","entityType":"limitation","observations":["Дата: 30.04.2026. Открытые ограничения после NSPD-pipeline.","1. Limit_Trend_Always_Capped_OPEN — все 8 районов ЕКБ имеют raw trend ratio 5+ (capped к 2.0). Решится через 6-12 мес sale_graph истории. Не действуем сейчас.","2. Limit_POI_Factor_Tiny_OPEN — POI ratio 0.99-1.02 везде (равномерное распределение POI). Можно увеличить вес с 5% до 10% или добавить distance-weighting к метро.","3. Bug_Kn_API_Obj_Class_Always_Null_OPEN — kn-API НЕ отдаёт obj_class для всех 3032 ЖК Свердл. Решение: fallback на yandex_realty_zk.obj_class через name-match (~1 день).","4. Bug_Kn_Flats_Price_Per_M2_Sparse_OPEN — kn-API даёт price для 0.15% квартир. ekb_districts.median для 6 районов NULL. Workaround есть в recommend_mix (sale_graph baseline). Дополнительно: можно взять median из cad_buildings.cost_value (но это кадастр, не рыночная).","5. ✅ CLOSED: Limit_District_Geometry_Closed (через OSM ekb_districts), Limit_District_Median_Partial (через cad_quarter mapping)."]}
{"type":"entity","name":"Excluded_Items_User_Pref","entityType":"policy","observations":["Дата: 30.04.2026. Пользователь явно исключил из roadmap.","❌ Issue #3 Selectel/Yandex S3 backup — пропускаем.","❌ Любое перемещение infra в Yandex Cloud / Selectel — пропускаем.","❌ pg_dump → cloud — пропускаем.","Причина не указана. Если потребуется ДР-стратегия — спросить отдельно."]}
{"type":"entity","name":"Session_End_Apr30_2026","entityType":"event","observations":["Дата: 30.04.2026. Длинная сессия (~5+ часов): NSPD scrape end-to-end + planning.","Главное:","1. NSPD_Scrape_Complete_Apr30 — 709 кварталов / 10590 зданий, 91% покрытие свежих ДДУ.","2. Cad_Buildings_Schema_v2 — расширили схему raw_props jsonb + 8 новых колонок.","3. Cad_Quarter_Backfill_Apr30 — spatial-join 2262/2578 ЖК (88%).","4. Cross-check: NSPD кадастр vs ДОМ.РФ рынок — premium 50-90% типично.","5. Sprint1_Plan_May2026 + Sprint2_Stage1_Generative + Sprint3_Stage2_SiteFinder — план на 10-12 недель до Phase 0 финиша.","OPEN на следующую сессию: Sprint 1 task A (NSPD scraper индустриализация Playwright+Celery).","Артефакты: ~50 JSONL drain-файлов в data/raw/, обновлённый 61_import_nspd_batch.py, план в C:\\Users\\user\\.claude\\plans\\next-iteration-roadmap.md.","ИНСАЙТ: rosreestr_deals.realestate_type='002001003000' даёт 91% покрытие за 12mo. Sale_graph ДОМ.РФ остаётся золотым стандартом для velocity (rosreestr недополнен — для топ-ЖК показывает 0.1 кв/мес против реальных 16-45 из sale_graph).","Pipeline через debug-Chrome работает но мануальный — индустриализация в Sprint 1."]}
{"type":"entity","name":"Objective_Integration_May07_2026","entityType":"deliverable","observations":["Дата: 07.05.2026. Интеграция с api.objctv.ru (Объектив) — внешний B2B аналитический API с per-flat данными по новостройкам РФ.","Цель: получить data feed богаче чем ДОМ.РФ kn-API: per-flat статус/цена/банк/дата регистрации + per (месяц × корпус × room-bucket) агрегаты для recommend_mix.","Архитектура: settings.objective_api_key → ObjectiveClient (httpx + Bearer-токен в Redis с in-memory fallback) → 4 канонические отчёты → objective_raw_reports (jsonb) → 70_parse_objective_raw.py → objective_corpus_room_month + objective_lots + objective_lots_history.","Celery-task tasks.scrape_objective.sync_objective_group: еженедельно пн 05:00 МСК (settings.objective_sync_cron='0 5 * * mon'). Тянет 2 рабочих отчёта (Сводные/Корпуса + Поквартирные/Лоты), сохраняет raw, сразу же парсит через late-import парсера 70.","Smoke-test 07.05 подтвердил: Парк Культуры (1 ЖК × 7 дней) → corp_sum 8 строк (13.5 KB) + lots_pf 563 квартир (818.8 KB). Парсер dry-run обработал все строки без warning.","ОТЛИЧИЕ ОТ ДОМ.РФ kn-API: точные per-flat поля — Статус, Цена за м2, Дата договора, Дата регистрации, Тип сделки (ДДУ/ДКП), Банк (ипотека!), Тип обременения. Это ×100 точнее domrf_kn_flats и даёт банковские предпочтения покупателей по проектам.","Открывает: velocity-anomaly detection (issue #17), elasticity per-flat-history (Tier 4 точнее regression × лет), competitor-360 (issue #19), mortgage-rate sensitivity (issue #20).","ОГРАНИЧЕНИЯ ТАРИФА: 2 из 4 канонических отчётов возвращают HTTP 500 'An unexpected error occurred' — Сводные/Лоты и Поквартирные/Корпуса. Не блокер: оба нужных получаем.","СТАТУС: код готов и протестирован локально (dry-run). Не применено: schema 68 на проде (mcp postgres был на svc_mosgas — нужно вручную через SSH-tunnel localhost:15432). OBJECTIVE_API_KEY в backend/.env прода не прописан.","Файлы: backend/app/services/scrapers/objective.py (ObjectiveClient) · backend/app/workers/tasks/scrape_objective.py (Celery task с inline-парсингом) · backend/app/workers/celery_app.py (beat schedule) · data/sql/68_schema_objective.sql v2 · data/sql/69_objective_smoke.py · data/sql/69b_objective_minimal.py · data/sql/70_parse_objective_raw.py."]}
{"type":"entity","name":"Module_Objective_Client","entityType":"code_module","observations":["backend/app/services/scrapers/objective.py — HTTP-клиент к api.objctv.ru.","Auth: GET /Users/User/GetToken?apiKey=<KEY> → {token: '...'} (~30 мин TTL). Bearer на /v2/Report/GetReport.","Кеширование токена: Redis (ключ 'objective:bearer_token', TTL settings.objective_token_ttl_seconds=25*60) + in-memory fallback _TOKEN_MEMORY_CACHE (когда Redis недоступен — локальные скрипты, сетевой сбой). Лог про Redis печатается ОДИН раз на инстанс (флаг _redis_warned), не спамит.","Rate-limiting: _DEFAULT_RATE_MS=500мс между запросами. Ретраи: 3 попытки на 401/429/502/503/504. Backoff на 429: 30, 60, 120, 240с (потолок 300с). Слушает Retry-After header если присутствует.","401 → один раз форс-рефреш токена; если повтор — ObjectiveAuthError. 429/5xx → exponential backoff. Брotli accept по дефолту в Accept-Encoding (их рекомендация).","Публичные методы: report_corpuses_summary, report_lots_summary, report_corpuses_per_flat, report_lots_per_flat. Универсальный get_report() с явными именованными параметрами (report_section, report_type, report_name, group_name, complex_name, start_date, end_date, use_ddu, use_dkp, page='Отчеты', v2=True).","Date format Объектива: YYYY.MM.DD (точка-разделитель!) — _fmt_date конвертит из date/str.","fetch_with_raw_log() — one-shot helper для smoke-сценариев и backfill: вызывает <fn_name>(**kwargs), сохраняет raw JSON в файл если save_dir."]}
{"type":"entity","name":"Module_Objective_Parser","entityType":"code_module","observations":["data/sql/70_parse_objective_raw.py — парсер raw → normalized слой Объектива.","Режимы: --file-corp-sum/--file-lots-pf (локальные JSON, smoke без БД, --dry-run) | --raw-id N (один объект из objective_raw_reports) | --latest-run (все unparsed raw из последнего objective_scrape_runs.run_id).","Эвристика detect_kind() по полям первого row payload: 'corp_sum' если ['Месяц','Корпус','Объем предложения, шт.'] · 'lots_pf' если ['Id','Номер лота','Площадь, м2(ПД)']. None → skip с warning.","Helpers: _parse_ru_month('апрель-2026' → date(2026,4,1)) · _parse_iso_date · _to_int/_to_num · _normalize_rooms('студия'→0, '1'→1, …'5+'→5) · _parse_pct('17%'→17) · _parse_bool_yes('да'/'нет' → True/False).","parse_corp_sum: маппит ~30 полей → INSERT в objective_corpus_room_month с ON CONFLICT (report_month, group_name, project_name, corpus_name, room_bucket) DO UPDATE (right move — отчёт за месяц уточняется неделя-к-неделе пока месяц не закрыт).","parse_lots_pf: маппит per-flat → INSERT в objective_lots с ON CONFLICT (objective_lot_id) DO UPDATE + INSERT в objective_lots_history с ON CONFLICT (objective_lot_id, snapshot_date) DO NOTHING (один снимок per день — повторный sync в тот же день не создаёт дубль).","Late-import используется в Celery-task: importlib.util.spec_from_file_location → exec_module. Это позволяет inline-парсинг сразу после save_raw без копирования кода в backend.","Smoke 07.05 на локальных файлах: corp_sum 8 rows + lots_pf 563 lots / 563 history rows — все отработали без warning'ов про обязательные поля."]}
{"type":"entity","name":"Schema_Objective_v2_May07","entityType":"infrastructure","observations":["data/sql/68_schema_objective.sql v2 (07.05.2026) — ВЫРОВНЕНА по реальным полям payload-ов вместо изначальных гипотез.","Таблицы (6): objective_scrape_runs (журнал) · objective_raw_reports (jsonb payload) · objective_corpus_room_month (long-формат, заменяет старую objective_oks) · objective_lots (UPSERT по objective_lot_id) · objective_lots_history (append-only weekly snapshots) · objective_complex_mapping (Objective.ComplexName ↔ domrf_kn_objects.obj_id с is_reviewed).","objective_corpus_room_month: UNIQUE (report_month, group_name, project_name, corpus_name, room_bucket). Колонки: capacity по ПД (lots_pd_count/area), сделки ДДУ/ДКП/всего (по 7 метрик каждое), offer (count/area/sum_mln_rub/avg_price_thousand_rub_per_m2). Ключ инсайт: одна строка = (месяц × корпус × room_bucket) — long-формат, не per-corpus как было задумано в v1.","objective_lots: UNIQUE (objective_lot_id). Поля per-flat: 3 источника комнат (rooms_dev_site/rooms_pd/rooms_objective + нормализованный rooms_int), 2 площади (dev_site/pd), полный pricing (calculated_total/per_m2/offer_total/delta_rub/delta_pct + методы и даты), полный deal (contract/registration_date/contract_type/buyer_type/registration_number), encumbrance/mortgage (encumbrance_type/bank_name/encumbrance_start_date/egrn_actual_date).","objective_lots_history: UNIQUE (objective_lot_id, snapshot_date) — сами строим weekly timeline через INSERT при каждом sync (Объектив не отдаёт per-day price/status timeline в одном вызове, поэтому накапливаем сами). Для elasticity (точность × лет) и velocity-anomaly detection.","objective_complex_mapping: связь Objective.ComplexName/objective_project_id ↔ domrf_kn_objects.obj_id. is_reviewed=TRUE — человек подтвердил соответствие.","Размеры (оценка для Свердл.обл): corpus_room_month ~5K rows/мес (~250 ЖК × 5 корпусов × 5 mix × 1 мес), lots ~50K rows (~250 ЖК × 200 квартир), lots_history +50K rows/нед.","Применять: psql через SSH-tunnel localhost:15432 (mcp postgres был воткнут не в ту БД 27.04 → ручной apply). Идемпотентно через IF NOT EXISTS."]}
{"type":"entity","name":"Objective_API_Findings_May07","entityType":"research","observations":["Дата: 07.05.2026. Эмпирические находки об api.objctv.ru через локальные пробы (data/sql/69b_objective_minimal.py).","ENDPOINTS: GetToken на /Users/User/GetToken?apiKey=<KEY> → JSON {token: '...'}. GetReport на /v2/Report/GetReport?Page=Отчеты&ReportSection=Объединенные данные&ReportType=...&ReportName=...&GroupName=...&[ComplexName]&[StartDate]&[EndDate]&[UseDdu]&[UseDkp]. Auth: Authorization: Bearer <token>. Date format: YYYY.MM.DD (точка-разделитель).","ФОРМАТ ИМЕНИ ЖК: ComplexName требует БЕЗ префикса 'ЖК' и БЕЗ кавычек. Пример: 'Парк Культуры' → 200 OK, 'ЖК \"Парк Культуры\"' → HTTP 500. Проверено 07.05 на 2 запросах подряд.","PAYLOAD ОБЁРНУТ В {result: [...]}, не голый список — все ответы такие.","ДОСТУПНЫЕ НА ТАРИФЕ ОТЧЁТЫ (2 из 4): ✅ Сводные/Корпуса (per месяц × корпус × room_bucket) · ✅ Поквартирные/Лоты (per-flat snapshot с Id-stable). HTTP 500 'An unexpected error occurred' на: Сводные/Лоты, Поквартирные/Корпуса. Гипотезы: тариф / косяк бэка / неправильные параметры (попробовать без ComplexName, попробовать с/без StartDate).","RATE-LIMIT: жёсткий — 500мс между запросами недостаточно, нужен ~3000мс + пауза 15с между отчётами (default в скрипте 69b после фиксов). Иначе HTTP 429 на 2-м запросе. Backoff на 429 респектит Retry-After header.","ОТКЛИК: первый запрос отчёта может занимать 18-52 секунды (отчёт реально считается на бэке Объектива). Возможно у них лимит 1 concurrent request — с маленьким inter-delay прилетает 429.","REDIS LOCAL: на локальной машине Redis недоступен (редис только в docker compose) → in-memory fallback токена в ObjectiveClient критичен.","ПОЛЯ ИЗ corp_sum (Парк Культуры): Месяц (текст 'апрель-2026'), Проект, Девелопер ('PRINZIP'), Район ('Автовокзал'), Класс ('Комфорт'), Корпус ('1.1'), 'Количество комнат (Данные Объектива)' (студия|1|2|3), 'Лотов по ПД, шт.', 'Площадь по ПД, м2.', 7 метрик ДДУ × 7 метрик ДКП × 7 метрик 'всего' (count, count_priced, vol, vol_priced, sum_priced_млн_Р, avg_price_тыс_Р/м2, avg_area_м2), Объем предложения шт/м2, Суммарная стоимость лотов в продаже млн.Р, Средняя цена м2 лота в продаже тыс.Р/м2. NB: цены в ТЫС.Р/м2, не Р/м2; стоимости в МЛН.Р.","ПОЛЯ ИЗ lots_pf (per-flat, 563 квартир в Парк Культуры): Id (stable Objective lot_id, 1965382), 'Id проекта' (3802), Проект/Девелопер/Город/Район/Корпус/Адрес/Класс/Секция/Этаж/Номер лота/'Вид помещения' (квартира|нежилое|паркинг|кладовая), Готовность ('17%'), 'Стадия строительства' (строящийся), 'Отделка по корпусу' (под чистовую), Статус (резерв|свободна|продан|бронь), Продано (да/нет), 3 источника комнат, 2 площади (Сайт девелопера/ПД), полный pricing block (Расчетный бюджет, Цена за м2, Цена предложения, Дельта Р/%, Способ определения цены, Дата установки/актуальности цены), полный deal block (Дата договора, Дата регистрации, Тип сделки ДДУ|ДКП, Тип покупателя, Номер регистрации), encumbrance (Тип обременения, Банк, Дата начала обременения, Дата актуальности данных из ЕГРН).","ИНСАЙТ ДЛЯ РЕКОММЕНДА: Сводные/Корпуса УЖЕ даёт нам монетизированную monthly history per (corpus, room_bucket) — не надо строить из sale_graph + median area. Это подменяет половину recommend_mix без всяких регрессий.","ИНСАЙТ ДЛЯ ИПОТЕКИ: lots_pf.Банк = stable банковская атрибуция per flat. За 6 мес weekly sync получим ground-truth статистику ипотечных предпочтений по проектам/девелоперам/районам Свердл.обл — нет в открытых источниках."]}
{"type":"entity","name":"Session_End_May07_2026","entityType":"event","observations":["Дата: 07.05.2026. Сессия после возвращения юзера ('я вернулся давай вспомним на чем остановились'). Continued работу над Objective integration после context compaction.","СДЕЛАНО ЗА СЕССИЮ:","1. Объяснил юзеру где остановились: scaffold Objective integration был готов (settings, ObjectiveClient, schema 68 v1, Celery task, smoke-script), но не применён и не протестирован.","2. Создал data/sql/69b_objective_minimal.py — минимальный probe (4 отчёта × 1 ЖК × 7 дней) с CLI-флагами (--complex, --no-complex, --group, --days, --only).","3. Юзер запустил 1-й раз: получили формат имени ЖК ('Парк Культуры' без префикса/кавычек) + 429 на 2-м отчёте (Redis недоступен локально → новый GetToken на каждый запрос → rate-limit).","4. Фикс in-memory fallback токена в ObjectiveClient + дефолт --complex без префикса + datetime.utcnow→timezone.aware. Запуск 2 — снова 429 (rate-limit после первого отчёта).","5. Доб --inter-delay 15s между отчётами + --rate-ms 3000ms + Retry-After header + backoff 30/60/120 в клиенте. Запуск 3 — получили 2 рабочих отчёта (corp_sum 8 строк, lots_pf 563 квартиры). 2 других вернули HTTP 500.","6. Прочитал оба payload-а — обнаружил расхождения с schema 68 v1: corp_sum в long-формате (не per-corpus), lots_pf имеет stable Id + богатые поля (банк! 3 источника комнат! полный deal/encumbrance block).","7. ПЕРЕПИСАЛ 68_schema_objective.sql v2 под реальную структуру: objective_oks → objective_corpus_room_month, расширенная objective_lots с UNIQUE objective_lot_id, append-only objective_lots_history с UNIQUE (lot_id, snapshot_date).","8. Написал data/sql/70_parse_objective_raw.py — полный парсер с эвристикой detect_kind, helpers _parse_ru_month/_normalize_rooms/etc., 3 режима (--file/--raw-id/--latest-run). Smoke на локальных файлах: 8 corp + 563 lots без warning.","9. Обновил Celery-task scrape_objective: убрал 2 нерабочих отчёта (HTTP 500 на тарифе), добавил late-import парсера 70 для inline-нормализации сразу после save_raw, обновил _heartbeat/_finish_run новыми счётчиками (rows_corpus_room/rows_lots/rows_history).","OPEN на следующую сессию: применить schema 68 v2 на проде (вручную через SSH-tunnel localhost:15432, mcp postgres до сих пор воткнут не в gendesign) · прописать OBJECTIVE_API_KEY в backend/.env прода · реальный прогон Celery-task (sync_objective_group) на проде с группой 'Екатеринбург' (без ComplexName-фильтра, по всему городу) · обновить knowledge graph (этот entity).","ПРИОРИТЕТЫ ПОСЛЕ APPLY: 1) Прогон без ComplexName на ЕКБ — сколько rows? Объём lots_pf может быть огромным (~50K квартир × ~2KB). 2) Исследовать почему Сводные/Лоты + Поквартирные/Корпуса возвращают 500 (попробовать варианты params без ComplexName / с/без StartDate). 3) Спросить саппорт Объектива.","ИНСТРУМЕНТАРИЙ ПРОВЕРКИ: cd backend; OBJECTIVE_API_KEY=<key> uv run python -X utf8 ../data/sql/69b_objective_minimal.py [--no-complex --days 3 | --only corp_sum]. Сохраняет в data/raw/objective_test/<timestamp>/.","ФИНАЛЬНЫЕ файлы изменены 07.05: backend/app/services/scrapers/objective.py · backend/app/workers/tasks/scrape_objective.py · data/sql/68_schema_objective.sql · data/sql/69b_objective_minimal.py (новый) · data/sql/70_parse_objective_raw.py (новый)."]}
{"type":"entity","name":"SiteFinder_v0_2_May08","entityType":"build","observations":["Дата импорта в репо: 8 мая 2026 (вайб-код вёлся с начала мая, коммит 97b19a0 на main)","Название: GenDesign Parcel Scoring v2 (из server.py title), локальный коднейм Site Finder. Путь в репо: site-finder/","Бэкенд: однофайловый FastAPI server.py (~85 KB), 35 эндпоинтов. Основные: GET /api/sites, /api/site/{id}, /api/districts, /api/district-polygons, /api/macro, /api/audiences, /api/district-velocity-trend/{district}, POST /api/analyze. Ключевая оптимизация: в ОП Екб используется кэш 9479 OSM POI вместо Overpass-запроса (~30с -> <100мс)","Данные: SQLite analysis.db = 340 МБ (не в git, регенерируется пайплайном). Объёмы: 380 ЖК, 316 тыс site-POI пар, 303 тыс квартир с Объектива. Схема в db_init.py","Пайплайн сборки данных: 12 скриптов 01_load_sites.py -> 02_fetch_pois.py -> 03_score.py -> 04_report.py -> 05_objective_pull.py -> 06_match_economics.py -> 07_objective_full_pull.py -> 08_enrich_economics.py -> 09_macro_and_trend.py -> 10_score_v2.py -> 11_refetch_pois_extended.py -> 12_more_pois.py","Фронт: статика в static/. index.html около 3500 строк (Leaflet UI: карта + 11 табов + 4 модалки), sw.js — Service Worker для кэша тайлов карты. Не Next.js — ванильный HTML/JS","Кэши в репо: cache/ekb_admin_districts.geojson (148K, адм-районы Екб), cache/jk_polygons.geojson (592K, полигоны ЖК), cache/parcel_polygons/ (drop-zone для ручно выгруженных с nspd.gov.ru полигонов, README внутри), cache/geocode_cache.json (тёплый кэш геокодинга). НЕ в git: cache/objective_raw (1.2 GB), cache/osm_buildings_all.geojson, cache/overpass_raw.json","Production: сайт https://gendsgn.ru/sf/ (лендинг), https://gendsgn.ru/sf/app.html (приложение). Сервер: /opt/gendesign/site-finder/, Docker-контейнер gendesign-site-finder-1","Production memory path: /opt/gendesign/memory/memory-gendesign.jsonl (отличается от локального ~/.aim/ на macOS и C:\\mcp\\.aim\\ на Windows). Для полной синхронизации нужен такой же watcher на проде (сейчас реализован только для anton@macOS)","Контраст с MVP_Scope_AreaSelect_Apr25: этот билд — фактический Site Finder в проде (скоринг участков по POI/экономике/макро), но решение от 25 апреля откладывало Site Finder в Пост-MVP. Нужно сверить: (а) Site Finder всё-таки остаётся в MVP в виде этого прода, (б) он эксплораторский прототип параллельно основному MVP, (в) решение от 25 апр отменено фактически"]}
{"type":"relation","from":"Project_GenDesign","to":"TechStack_v2.2","relationType":"uses"}
{"type":"relation","from":"Project_GenDesign","to":"NorthStar_DiscoveryMVP","relationType":"targets"}
{"type":"relation","from":"Project_GenDesign","to":"Phase0_DiscoveryMVP","relationType":"currently_executes"}
{"type":"relation","from":"Phase0_DiscoveryMVP","to":"NorthStar_DiscoveryMVP","relationType":"delivers"}
{"type":"relation","from":"Validation_Findings_Apr25","to":"Project_GenDesign","relationType":"reviews"}
{"type":"relation","from":"Validation_Findings_Apr25","to":"TechStack_v2.2","relationType":"validates"}
{"type":"relation","from":"SalesTracking_Strategy_Apr25","to":"Project_GenDesign","relationType":"strengthens"}
{"type":"relation","from":"SalesTracking_Strategy_Apr25","to":"DataSources_Pricing_Apr25","relationType":"extends"}
{"type":"relation","from":"SalesTracking_Strategy_Apr25","to":"Phase0_DiscoveryMVP","relationType":"modifies"}
{"type":"relation","from":"SalesTracking_Strategy_Apr25","to":"Stages_MVP_v1","relationType":"amends_stage_2a"}
{"type":"relation","from":"PlanA_AnalyticsFirst_Apr25","to":"Stages_MVP_v1","relationType":"supersedes"}
{"type":"relation","from":"PlanA_AnalyticsFirst_Apr25","to":"WorkSplit_Generative_Stage1","relationType":"needs_revision"}
{"type":"relation","from":"PlanA_AnalyticsFirst_Apr25","to":"SalesTracking_Strategy_Apr25","relationType":"depends_on"}
{"type":"relation","from":"PlanA_AnalyticsFirst_Apr25","to":"DataSources_Pricing_Apr25","relationType":"depends_on"}
{"type":"relation","from":"PlanA_AnalyticsFirst_Apr25","to":"Project_GenDesign","relationType":"reshapes"}
{"type":"relation","from":"Domain_Setup_Apr26","to":"Project_GenDesign","relationType":"infrastructure_for"}
{"type":"relation","from":"Domain_Setup_Apr26","to":"Hosting_Decision_Apr25","relationType":"extends"}
{"type":"relation","from":"Sentry_Setup_Apr26","to":"Project_GenDesign","relationType":"monitors"}
{"type":"relation","from":"Sentry_Setup_Apr26","to":"Phase0_DiscoveryMVP","relationType":"infrastructure_for"}
{"type":"relation","from":"OpsBundle_Apr26","to":"Project_GenDesign","relationType":"infrastructure_for"}
{"type":"relation","from":"OpsBundle_Apr26","to":"Stages_MVP_v1","relationType":"prepares_for"}
{"type":"relation","from":"Production_Wipe_Apr26","to":"Runbook_VPS_Setup_Beget","relationType":"refreshed_state_of"}
{"type":"relation","from":"DockerOps_Apr26","to":"Runbook_VPS_Setup_Beget","relationType":"extends"}
{"type":"relation","from":"HTTPS_Live_Apr26","to":"Domain_Setup_Apr26","relationType":"completes"}
{"type":"relation","from":"HTTPS_Live_Apr26","to":"Phase0_DiscoveryMVP","relationType":"infrastructure_milestone_for"}
{"type":"relation","from":"HTTPS_Live_Apr26","to":"Project_GenDesign","relationType":"deploys"}
{"type":"relation","from":"DataSources_Analysis_Apr26","to":"DataSources_Pricing_Apr25","relationType":"supersedes"}
{"type":"relation","from":"DataSources_Analysis_Apr26","to":"PlanA_AnalyticsFirst_Apr25","relationType":"unblocks"}
{"type":"relation","from":"DataSources_Analysis_Apr26","to":"SalesTracking_Strategy_Apr25","relationType":"downgrades"}
{"type":"relation","from":"DataSources_Analysis_Apr26","to":"Stages_MVP_v1","relationType":"amends_stage_2a"}
{"type":"relation","from":"DataSources_Analysis_Apr26","to":"Project_GenDesign","relationType":"data_strategy_for"}
{"type":"relation","from":"DomRF_Tab11_MortgageStats_Apr26","to":"DomRF_Tab10_MortgageRates_Apr26","relationType":"paired_with"}
{"type":"relation","from":"DomRF_API_PortalAnalytics_Apr26","to":"DomRF_Host_Apr26","relationType":"hosted_on"}
{"type":"relation","from":"DomRF_API_PortalKn_Apr26","to":"DomRF_Host_Apr26","relationType":"hosted_on"}
{"type":"relation","from":"DomRF_API_KnObject_Apr26","to":"DomRF_Host_Apr26","relationType":"hosted_on"}
{"type":"relation","from":"DomRF_API_KnFlats_Apr26","to":"DomRF_Host_Apr26","relationType":"hosted_on"}
{"type":"relation","from":"DomRF_API_KnDicts_Apr26","to":"DomRF_Host_Apr26","relationType":"hosted_on"}
{"type":"relation","from":"DomRF_API_Files_Apr26","to":"DomRF_Host_Apr26","relationType":"hosted_on"}
{"type":"relation","from":"DomRF_API_Registries_Apr26","to":"DomRF_Host_Apr26","relationType":"hosted_on"}
{"type":"relation","from":"DomRF_Tab1_HousingIndicators_Apr26","to":"DomRF_API_PortalAnalytics_Apr26","relationType":"uses"}
{"type":"relation","from":"DomRF_Tab2_LaunchAndCommissioning_Apr26","to":"DomRF_API_PortalAnalytics_Apr26","relationType":"uses"}
{"type":"relation","from":"DomRF_Tab4_DevelopersDashboard_Apr26","to":"DomRF_API_PortalAnalytics_Apr26","relationType":"uses"}
{"type":"relation","from":"DomRF_Tab7_ReadyConstruction_Apr26","to":"DomRF_API_PortalAnalytics_Apr26","relationType":"uses"}
{"type":"relation","from":"DomRF_Tab8_Quartirografia_Apr26","to":"DomRF_API_PortalAnalytics_Apr26","relationType":"uses"}
{"type":"relation","from":"DomRF_Tab9_BuildingCommissioning_Apr26","to":"DomRF_API_PortalAnalytics_Apr26","relationType":"uses"}
{"type":"relation","from":"DomRF_Tab11_MortgageStats_Apr26","to":"DomRF_API_PortalAnalytics_Apr26","relationType":"uses"}
{"type":"relation","from":"DomRF_Tab1_HousingIndicators_Apr26","to":"DomRF_Architecture_Apr26","relationType":"follows"}
{"type":"relation","from":"DomRF_Tab3_ProjectFinance_Apr26","to":"DomRF_Architecture_Apr26","relationType":"follows"}
{"type":"relation","from":"DomRF_Tab5_Escrow_Apr26","to":"DomRF_Architecture_Apr26","relationType":"follows"}
{"type":"relation","from":"DomRF_Tab6_Realization_Apr26","to":"DomRF_Architecture_Apr26","relationType":"follows"}
{"type":"relation","from":"DomRF_Tab10_MortgageRates_Apr26","to":"DomRF_Architecture_Apr26","relationType":"follows"}
{"type":"relation","from":"DomRF_Tab12_StatRows_Apr26","to":"DomRF_Architecture_Apr26","relationType":"follows"}
{"type":"relation","from":"DomRF_PerFlat_Schema_Apr26","to":"DomRF_API_KnFlats_Apr26","relationType":"describes_schema_of"}
{"type":"relation","from":"DomRF_PerFlat_ETL_Apr26","to":"DomRF_PerFlat_Schema_Apr26","relationType":"uses_schema"}
{"type":"relation","from":"DomRF_PerFlat_VelocityTracker_Apr26","to":"DomRF_PerFlat_Schema_Apr26","relationType":"uses_field"}
{"type":"relation","from":"DomRF_PerFlat_VelocityTracker_Apr26","to":"DomRF_Tab6_Realization_Apr26","relationType":"alternative_to"}
{"type":"relation","from":"DomRF_PerFlat_VelocityTracker_Apr26","to":"DomRF_Tab7_ReadyConstruction_Apr26","relationType":"alternative_to"}
{"type":"relation","from":"DomRF_ExtractFlow_Objects_Apr26","to":"DomRF_API_PortalKn_Apr26","relationType":"step_1_uses"}
{"type":"relation","from":"DomRF_ExtractFlow_Objects_Apr26","to":"DomRF_API_KnObject_Apr26","relationType":"step_2_uses"}
{"type":"relation","from":"DomRF_Object_ETL_Apr26","to":"DomRF_ExtractFlow_Objects_Apr26","relationType":"implements"}
{"type":"relation","from":"DomRF_Object_ETL_Apr26","to":"DomRF_PerFlat_ETL_Apr26","relationType":"complements"}
{"type":"relation","from":"DomRF_BrokenEndpoints_Apr26","to":"DomRF_API_KnObject_Apr26","relationType":"failed_alternatives_to"}
{"type":"relation","from":"DomRF_Spec_SJS_v130","to":"DomRF_OfficialAuth_Apr26","relationType":"uses_auth"}
{"type":"relation","from":"DomRF_Spec_NSI_v101","to":"DomRF_OfficialAuth_Apr26","relationType":"uses_auth"}
{"type":"relation","from":"DomRF_Spec_UOPO_v102","to":"DomRF_OfficialAuth_Apr26","relationType":"uses_auth"}
{"type":"relation","from":"DomRF_Spec_APF_v22","to":"DomRF_OfficialAuth_Apr26","relationType":"uses_auth"}
{"type":"relation","from":"DomRF_OfficialVsFront_Comparison_Apr26","to":"DomRF_Spec_SJS_v130","relationType":"compares"}
{"type":"relation","from":"DomRF_OfficialVsFront_Comparison_Apr26","to":"DomRF_API_KnFlats_Apr26","relationType":"compares"}
{"type":"relation","from":"DomRF_KeyAndLegal_Apr26","to":"DomRF_API_KnObject_Apr26","relationType":"applies_to"}
{"type":"relation","from":"DomRF_KeyAndLegal_Apr26","to":"DomRF_API_KnFlats_Apr26","relationType":"applies_to"}
{"type":"relation","from":"DomRF_KeyAndLegal_Apr26","to":"DomRF_API_KnDicts_Apr26","relationType":"applies_to"}
{"type":"relation","from":"DomRF_Integration_Docs_Apr26","to":"DomRF_OfficialAuth_Apr26","relationType":"describes"}
{"type":"relation","from":"DomRF_PlanA_Mapping_Apr26","to":"DomRF_Tab8_Quartirografia_Apr26","relationType":"tile1_uses"}
{"type":"relation","from":"DomRF_PlanA_Mapping_Apr26","to":"DomRF_API_KnFlats_Apr26","relationType":"tile2_uses"}
{"type":"relation","from":"DomRF_PlanA_Mapping_Apr26","to":"DomRF_Tab6_Realization_Apr26","relationType":"tile3_uses"}
{"type":"relation","from":"DomRF_PlanA_Mapping_Apr26","to":"DomRF_Tab7_ReadyConstruction_Apr26","relationType":"tile3_uses"}
{"type":"relation","from":"DomRF_Tab9_BuildingCommissioning_Apr26","to":"DomRF_Tab11_MortgageStats_Apr26","relationType":"shares_backend_with"}
{"type":"relation","from":"DomRF_Recon_AcceptVersionLeak_Apr26","to":"DomRF_Recon_Summary_Apr26","relationType":"is_part_of"}
{"type":"relation","from":"DomRF_Recon_OIDC_Apr26","to":"DomRF_Recon_Summary_Apr26","relationType":"is_part_of"}
{"type":"relation","from":"DomRF_Recon_Stack_Apr26","to":"DomRF_Recon_Summary_Apr26","relationType":"is_part_of"}
{"type":"relation","from":"DomRF_Recon_RobotsTxt_Apr26","to":"DomRF_Recon_Summary_Apr26","relationType":"is_part_of"}
{"type":"relation","from":"DomRF_Recon_OptionsPost_Apr26","to":"DomRF_Recon_Summary_Apr26","relationType":"is_part_of"}
{"type":"relation","from":"DomRF_Recon_CORS_Apr26","to":"DomRF_Recon_Summary_Apr26","relationType":"is_part_of"}
{"type":"relation","from":"DomRF_Recon_PortalSitemap_Apr26","to":"DomRF_Recon_Summary_Apr26","relationType":"is_part_of"}
{"type":"relation","from":"DomRF_Recon_NoSourceMaps_Apr26","to":"DomRF_Recon_Summary_Apr26","relationType":"is_part_of"}
{"type":"relation","from":"DomRF_Recon_DisclosurePlan_Apr26","to":"DomRF_Recon_Summary_Apr26","relationType":"is_part_of"}
{"type":"relation","from":"DomRF_Recon_AcceptVersionLeak_Apr26","to":"DomRF_Host_Apr26","relationType":"annotates"}
{"type":"relation","from":"DomRF_Recon_AcceptVersionLeak_Apr26","to":"DomRF_Recon_Stack_Apr26","relationType":"evidence_for"}
{"type":"relation","from":"DomRF_Recon_OIDC_Apr26","to":"DomRF_OfficialAuth_Apr26","relationType":"extends"}
{"type":"relation","from":"DomRF_Recon_OIDC_Apr26","to":"DomRF_Recon_Stack_Apr26","relationType":"evidence_for"}
{"type":"relation","from":"DomRF_Recon_RobotsTxt_Apr26","to":"DomRF_Enums_Apr26","relationType":"complements"}
{"type":"relation","from":"DomRF_Recon_RobotsTxt_Apr26","to":"DomRF_Recon_PortalSitemap_Apr26","relationType":"leads_to"}
{"type":"relation","from":"DomRF_Recon_OptionsPost_Apr26","to":"DomRF_API_KnObject_Apr26","relationType":"annotates"}
{"type":"relation","from":"DomRF_Recon_CORS_Apr26","to":"DomRF_API_KnFlats_Apr26","relationType":"annotates"}
{"type":"relation","from":"DomRF_Recon_CORS_Apr26","to":"DomRF_API_KnObject_Apr26","relationType":"annotates"}
{"type":"relation","from":"DomRF_Recon_PortalSitemap_Apr26","to":"DomRF_API_Registries_Apr26","relationType":"complements"}
{"type":"relation","from":"DomRF_Recon_PortalSitemap_Apr26","to":"DomRF_ExtractFlow_Objects_Apr26","relationType":"alternative_to"}
{"type":"relation","from":"DomRF_Recon_DisclosurePlan_Apr26","to":"DomRF_Recon_AcceptVersionLeak_Apr26","relationType":"targets"}
{"type":"relation","from":"DomRF_Recon_DisclosurePlan_Apr26","to":"DomRF_Recon_OIDC_Apr26","relationType":"targets"}
{"type":"relation","from":"DomRF_Recon_Stack_Apr26","to":"DomRF_Architecture_Apr26","relationType":"annotates"}
{"type":"relation","from":"DataSource_CBR_Mortgage_Apr26","to":"DataSource_PerDeal_Reality_Apr26","relationType":"is_aggregate_for"}
{"type":"relation","from":"DataSource_Fedstat_Apr26","to":"DataSource_PerDeal_Reality_Apr26","relationType":"is_aggregate_for"}
{"type":"relation","from":"DataSource_Rosreestr_OpenService_Apr26","to":"DataSource_PerDeal_Reality_Apr26","relationType":"is_aggregate_for"}
{"type":"relation","from":"DataSource_UPN_Ekb_Apr26","to":"DataSource_PerDeal_Reality_Apr26","relationType":"is_aggregate_for"}
{"type":"relation","from":"DataSource_DomRFAsPerDeal_Apr26","to":"DataSource_PerDeal_Reality_Apr26","relationType":"best_synthetic_approximation_for"}
{"type":"relation","from":"DataSource_DomRFAsPerDeal_Apr26","to":"DomRF_API_KnFlats_Apr26","relationType":"uses"}
{"type":"relation","from":"DataSource_DomRFAsPerDeal_Apr26","to":"DomRF_PerFlat_ETL_Apr26","relationType":"implements"}
{"type":"relation","from":"DataSource_DomRFAsPerDeal_Apr26","to":"DomRF_PerFlat_VelocityTracker_Apr26","relationType":"extends"}
{"type":"relation","from":"DataSource_CBR_Mortgage_Apr26","to":"DomRF_Tab10_MortgageRates_Apr26","relationType":"complements"}
{"type":"relation","from":"DataSource_CBR_Mortgage_Apr26","to":"DomRF_Tab11_MortgageStats_Apr26","relationType":"complements"}
{"type":"relation","from":"DataSource_Fedstat_Apr26","to":"DomRF_Tab1_HousingIndicators_Apr26","relationType":"cross_validates"}
{"type":"relation","from":"DataSource_UPN_Ekb_Apr26","to":"DomRF_API_KnFlats_Apr26","relationType":"regional_complement_for"}
{"type":"relation","from":"DataSource_Rosreestr_OpenService_Apr26","to":"DataSource_Fedstat_Apr26","relationType":"publishes_aggregates_via"}
{"type":"relation","from":"DataSource_PerDeal_Reality_Apr26","to":"DomRF_PlanA_Mapping_Apr26","relationType":"informs"}
{"type":"relation","from":"DataSource_Rosreestr_DealsCSV_Apr26","to":"DataSource_Rosreestr_OpenService_Apr26","relationType":"is_part_of"}
{"type":"relation","from":"DataSource_Rosreestr_DealsCSV_Schema_Apr26","to":"DataSource_Rosreestr_DealsCSV_Apr26","relationType":"describes_schema_of"}
{"type":"relation","from":"DataSource_Rosreestr_DealsCSV_Sverdl_Q1_2026","to":"DataSource_Rosreestr_DealsCSV_Apr26","relationType":"validates"}
{"type":"relation","from":"DataSource_Rosreestr_ETL_Plan_Apr26","to":"DataSource_Rosreestr_DealsCSV_Apr26","relationType":"implements"}
{"type":"relation","from":"DataSource_Rosreestr_DealsCSV_Limits_Apr26","to":"DataSource_Rosreestr_DealsCSV_Apr26","relationType":"qualifies"}
{"type":"relation","from":"DataSource_Rosreestr_DealsCSV_Apr26","to":"DataSource_PerDeal_Reality_Apr26","relationType":"primary_solution_for"}
{"type":"relation","from":"DataSource_Rosreestr_DealsCSV_Apr26","to":"DataSource_DomRFAsPerDeal_Apr26","relationType":"supersedes_for_per_deal"}
{"type":"relation","from":"DataSource_Rosreestr_DealsCSV_Apr26","to":"DomRF_PlanA_Mapping_Apr26","relationType":"tile2_primary"}
{"type":"relation","from":"DataSource_Rosreestr_ETL_Plan_Apr26","to":"DomRF_PerFlat_ETL_Apr26","relationType":"complements"}
{"type":"relation","from":"DataSource_Rosreestr_DealsCSV_Sverdl_Q1_2026","to":"DataSource_UPN_Ekb_Apr26","relationType":"ground_truth_for"}
{"type":"relation","from":"DataSource_Rosreestr_DealsCSV_Sverdl_Q1_2026","to":"DataSource_Fedstat_Apr26","relationType":"ground_truth_for"}
{"type":"relation","from":"NSPD_OAuth_Architecture_Apr26","to":"NSPD_Architecture_Apr26","relationType":"extends"}
{"type":"relation","from":"NSPD_PhysicAccess_Apr26","to":"NSPD_OAuth_Architecture_Apr26","relationType":"uses"}
{"type":"relation","from":"NSPD_MarketAnalytics_API_Apr26","to":"NSPD_PhysicAccess_Apr26","relationType":"accessible_via"}
{"type":"relation","from":"NSPD_MarketAnalytics_API_Apr26","to":"DataSource_Rosreestr_DealsCSV_Apr26","relationType":"based_on_same_source"}
{"type":"relation","from":"NSPD_AEGGIS_WMTS_Apr26","to":"NSPD_Architecture_Apr26","relationType":"extends"}
{"type":"relation","from":"NSPD_PII_Leak_Apr26","to":"NSPD_OAuth_Architecture_Apr26","relationType":"qualifies"}
{"type":"relation","from":"NSPD_PII_Leak_Apr26","to":"Rosreestr_Recon_Findings_Apr26","relationType":"complements"}
{"type":"relation","from":"NSPD_MarketAnalytics_API_Apr26","to":"DomRF_PlanA_Mapping_Apr26","relationType":"tile2_alternative"}
{"type":"relation","from":"NSPD_PhysicAccess_Apr26","to":"Rosreestr_SiteMap_Apr26","relationType":"is_part_of"}
{"type":"relation","from":"NSPD_MarketAnalytics_FullArchitecture_Apr26","to":"NSPD_MarketAnalytics_API_Apr26","relationType":"supersedes"}
{"type":"relation","from":"NSPD_MarketAnalytics_FullArchitecture_Apr26","to":"NSPD_OAuth_Architecture_Apr26","relationType":"uses_auth_from"}
{"type":"relation","from":"NSPD_MarketAnalytics_FullArchitecture_Apr26","to":"NSPD_PhysicAccess_Apr26","relationType":"tested_with"}
{"type":"relation","from":"NSPD_OrgOnly_Endpoints_Apr26","to":"NSPD_MarketAnalytics_FullArchitecture_Apr26","relationType":"qualifies"}
{"type":"relation","from":"NSPD_OrgOnly_Endpoints_Apr26","to":"DataSource_Rosreestr_DealsCSV_Apr26","relationType":"duplicates_data_of"}
{"type":"relation","from":"NSPD_DataValue_For_GenDesign_Apr26","to":"NSPD_MarketAnalytics_FullArchitecture_Apr26","relationType":"applies"}
{"type":"relation","from":"NSPD_DataValue_For_GenDesign_Apr26","to":"DomRF_PlanA_Mapping_Apr26","relationType":"tile2_alternative_to"}
{"type":"relation","from":"NSPD_DataValue_For_GenDesign_Apr26","to":"Stages_MVP_v1","relationType":"extends_stage_2a_for"}
{"type":"relation","from":"TechStack_v2.2","to":"Project_GenDesign","relationType":"defines_tech_stack_for"}
{"type":"relation","from":"Stages_MVP_v1","to":"Project_GenDesign","relationType":"defines_roadmap_for"}
{"type":"relation","from":"Team_Setup","to":"Project_GenDesign","relationType":"executes"}
{"type":"relation","from":"PlanA_AnalyticsFirst_Apr25","to":"Project_GenDesign","relationType":"pivot_decision_for"}
{"type":"relation","from":"WorkSplit_Generative_Stage1","to":"Stages_MVP_v1","relationType":"details_phase_of"}
{"type":"relation","from":"WorkSplit_Generative_Stage1","to":"Team_Setup","relationType":"assigns_work_in"}
{"type":"relation","from":"Hosting_Decision_Apr25","to":"Project_GenDesign","relationType":"hosting_choice_for"}
{"type":"relation","from":"Hosting_Decision_Apr25","to":"Hosting_Pricing_Apr25","relationType":"informed_by"}
{"type":"relation","from":"Runbook_VPS_Setup_Beget","to":"Hosting_Pricing_Apr25","relationType":"implements_choice_from"}
{"type":"relation","from":"Runbook_VPS_Setup_Beget","to":"Project_GenDesign","relationType":"production_runbook_for"}
{"type":"relation","from":"Sentry_Setup_Apr26","to":"Runbook_VPS_Setup_Beget","relationType":"deployed_on_top_of"}
{"type":"relation","from":"OpsBundle_Apr26","to":"DockerOps_Apr26","relationType":"follows"}
{"type":"relation","from":"OpsBundle_Apr26","to":"Production_Wipe_Apr26","relationType":"will_apply_after"}
{"type":"relation","from":"Production_Wipe_Apr26","to":"DockerOps_Apr26","relationType":"applied_changes_from"}
{"type":"relation","from":"DockerOps_Apr26","to":"Sentry_Setup_Apr26","relationType":"precedes"}
{"type":"relation","from":"DomRF_Tab2_LaunchAndCommissioning_Apr26","to":"DomRF_Architecture_Apr26","relationType":"follows"}
{"type":"relation","from":"DomRF_Tab4_DevelopersDashboard_Apr26","to":"DomRF_Architecture_Apr26","relationType":"follows"}
{"type":"relation","from":"DomRF_Tab7_ReadyConstruction_Apr26","to":"DomRF_Architecture_Apr26","relationType":"follows"}
{"type":"relation","from":"DomRF_Tab8_Quartirografia_Apr26","to":"DomRF_Architecture_Apr26","relationType":"follows"}
{"type":"relation","from":"DomRF_Tab9_BuildingCommissioning_Apr26","to":"DomRF_Architecture_Apr26","relationType":"follows"}
{"type":"relation","from":"DomRF_Tab11_MortgageStats_Apr26","to":"DomRF_Architecture_Apr26","relationType":"follows"}
{"type":"relation","from":"DomRF_API_PortalAnalytics_Apr26","to":"DomRF_Architecture_Apr26","relationType":"implements_group_a_of"}
{"type":"relation","from":"DomRF_Enums_Apr26","to":"DomRF_API_PortalAnalytics_Apr26","relationType":"provides_enums_for"}
{"type":"relation","from":"DomRF_KeyAndLegal_Apr26","to":"DomRF_Architecture_Apr26","relationType":"documents_legal_status_of"}
{"type":"relation","from":"DomRF_KeyAndLegal_Apr26","to":"DomRF_Host_Apr26","relationType":"qualifies_auth_on"}
{"type":"relation","from":"DomRF_OfficialVsFront_Comparison_Apr26","to":"DomRF_Architecture_Apr26","relationType":"compares_against_official"}
{"type":"relation","from":"DomRF_OfficialVsFront_Comparison_Apr26","to":"DomRF_Spec_APF_v22","relationType":"compares"}
{"type":"relation","from":"DomRF_Recon_OptionsPost_Apr26","to":"DomRF_Architecture_Apr26","relationType":"annotates"}
{"type":"relation","from":"DomRF_PlanA_Mapping_Apr26","to":"DomRF_Architecture_Apr26","relationType":"uses"}
{"type":"relation","from":"DomRF_PlanA_Mapping_Apr26","to":"DomRF_Tab1_HousingIndicators_Apr26","relationType":"additional_source"}
{"type":"relation","from":"DomRF_PlanA_Mapping_Apr26","to":"DomRF_Tab2_LaunchAndCommissioning_Apr26","relationType":"additional_source"}
{"type":"relation","from":"DomRF_PlanA_Mapping_Apr26","to":"DomRF_Tab3_ProjectFinance_Apr26","relationType":"additional_source"}
{"type":"relation","from":"DomRF_PlanA_Mapping_Apr26","to":"DomRF_Tab5_Escrow_Apr26","relationType":"additional_source"}
{"type":"relation","from":"DomRF_PlanA_Mapping_Apr26","to":"DomRF_KeyAndLegal_Apr26","relationType":"tile2_uses_auth_from"}
{"type":"relation","from":"PlanA_AnalyticsFirst_Apr25","to":"DomRF_PlanA_Mapping_Apr26","relationType":"tile_design_described_in"}
{"type":"relation","from":"PlanA_AnalyticsFirst_Apr25","to":"DataSource_Rosreestr_DealsCSV_Apr26","relationType":"now_primary_data_source"}
{"type":"relation","from":"PlanA_AnalyticsFirst_Apr25","to":"DataSources_Analysis_Apr26","relationType":"data_layer_designed_in"}
{"type":"relation","from":"PlanA_AnalyticsFirst_Apr25","to":"Stages_MVP_v1","relationType":"modifies"}
{"type":"relation","from":"SalesTracking_Strategy_Apr25","to":"Stages_MVP_v1","relationType":"was_planned_for_stage_2a"}
{"type":"relation","from":"SalesTracking_Strategy_Apr25","to":"Project_GenDesign","relationType":"data_moat_for"}
{"type":"relation","from":"DataSources_Pricing_Apr25","to":"Project_GenDesign","relationType":"early_research_for"}
{"type":"relation","from":"DataSource_PerDeal_Reality_Apr26","to":"PlanA_AnalyticsFirst_Apr25","relationType":"unblocks_tile2_of"}
{"type":"relation","from":"DataSource_Rosreestr_DealsCSV_Apr26","to":"Project_GenDesign","relationType":"primary_pricing_source_for"}
{"type":"relation","from":"DataSource_Rosreestr_DealsCSV_Apr26","to":"DomRF_PlanA_Mapping_Apr26","relationType":"tile2_primary_alternative_to"}
{"type":"relation","from":"DataSource_Rosreestr_ETL_Plan_Apr26","to":"Stages_MVP_v1","relationType":"details_stage_2a_etl_for"}
{"type":"relation","from":"DataSource_UPN_Ekb_Apr26","to":"Project_GenDesign","relationType":"ekb_baseline_for"}
{"type":"relation","from":"Rosreestr_SiteMap_Apr26","to":"DataSource_Rosreestr_OpenService_Apr26","relationType":"lists"}
{"type":"relation","from":"Rosreestr_SiteMap_Apr26","to":"DataSource_Rosreestr_DealsCSV_Apr26","relationType":"lists"}
{"type":"relation","from":"Rosreestr_SiteMap_Apr26","to":"Rosreestr_OpenData_17Sets_Apr26","relationType":"lists"}
{"type":"relation","from":"Rosreestr_SiteMap_Apr26","to":"NSPD_Architecture_Apr26","relationType":"lists"}
{"type":"relation","from":"Rosreestr_OpenData_17Sets_Apr26","to":"Rosreestr_SiteMap_Apr26","relationType":"is_part_of"}
{"type":"relation","from":"Rosreestr_Recon_Findings_Apr26","to":"Rosreestr_SiteMap_Apr26","relationType":"security_annotation_for"}
{"type":"relation","from":"Rosreestr_Recon_Findings_Apr26","to":"NSPD_Architecture_Apr26","relationType":"annotates"}
{"type":"relation","from":"Rosreestr_TLS_Note_Apr26","to":"DataSource_Rosreestr_ETL_Plan_Apr26","relationType":"affects"}
{"type":"relation","from":"Rosreestr_TLS_Note_Apr26","to":"DataSource_Rosreestr_DealsCSV_Apr26","relationType":"affects_download_of"}
{"type":"relation","from":"NSPD_Architecture_Apr26","to":"Rosreestr_SiteMap_Apr26","relationType":"is_part_of"}
{"type":"relation","from":"NSPD_OAuth_Architecture_Apr26","to":"NSPD_Architecture_Apr26","relationType":"auth_subsystem_of"}
{"type":"relation","from":"NSPD_PhysicAccess_Apr26","to":"NSPD_Architecture_Apr26","relationType":"tested_role_in"}
{"type":"relation","from":"NSPD_AEGGIS_WMTS_Apr26","to":"NSPD_Architecture_Apr26","relationType":"is_subsystem_of"}
{"type":"relation","from":"NSPD_AEGGIS_WMTS_Apr26","to":"NSPD_MarketAnalytics_FullArchitecture_Apr26","relationType":"provides_basemap_for"}
{"type":"relation","from":"NSPD_AEGGIS_WMTS_Apr26","to":"Project_GenDesign","relationType":"embeddable_basemap_for"}
{"type":"relation","from":"NSPD_PII_Leak_Apr26","to":"NSPD_OAuth_Architecture_Apr26","relationType":"security_annotation_for"}
{"type":"relation","from":"NSPD_PII_Leak_Apr26","to":"NSPD_PhysicAccess_Apr26","relationType":"annotates"}
{"type":"relation","from":"NSPD_MarketAnalytics_API_Apr26","to":"NSPD_Architecture_Apr26","relationType":"is_subsystem_of"}
{"type":"relation","from":"NSPD_MarketAnalytics_FullArchitecture_Apr26","to":"NSPD_Architecture_Apr26","relationType":"is_subsystem_of"}
{"type":"relation","from":"NSPD_MarketAnalytics_FullArchitecture_Apr26","to":"Project_GenDesign","relationType":"potential_data_source_for"}
{"type":"relation","from":"NSPD_DataValue_For_GenDesign_Apr26","to":"Project_GenDesign","relationType":"data_value_assessment_for"}
{"type":"relation","from":"NSPD_DataValue_For_GenDesign_Apr26","to":"PlanA_AnalyticsFirst_Apr25","relationType":"informs_tile2_of"}
{"type":"relation","from":"NSPD_DataValue_For_GenDesign_Apr26","to":"DataSource_Rosreestr_DealsCSV_Apr26","relationType":"cross_validates_with"}
{"type":"relation","from":"NSPD_DataValue_For_GenDesign_Apr26","to":"NSPD_AEGGIS_WMTS_Apr26","relationType":"uses_basemap"}
{"type":"relation","from":"NSPD_OrgOnly_Endpoints_Apr26","to":"NSPD_PhysicAccess_Apr26","relationType":"qualifies_403_for"}
{"type":"relation","from":"DomRF_Recon_Stack_Apr26","to":"DomRF_API_PortalAnalytics_Apr26","relationType":"stack_annotation_for"}
{"type":"relation","from":"NorthStar_DiscoveryMVP","to":"Project_GenDesign","relationType":"goal_for"}
{"type":"relation","from":"Stages_MVP_v1","to":"NorthStar_DiscoveryMVP","relationType":"delivers_toward"}
{"type":"relation","from":"PlanA_AnalyticsFirst_Apr25","to":"NorthStar_DiscoveryMVP","relationType":"alternative_path_to"}
{"type":"relation","from":"Validation_Findings_Apr25","to":"Project_GenDesign","relationType":"validates_business_plan_for"}
{"type":"relation","from":"Validation_Findings_Apr25","to":"TechStack_v2.2","relationType":"flagged_drift_against"}
{"type":"relation","from":"Validation_Findings_Apr25","to":"NorthStar_DiscoveryMVP","relationType":"calibrates_kpi_of"}
{"type":"relation","from":"Validation_Findings_Apr25","to":"Stages_MVP_v1","relationType":"informed_scope_of"}
{"type":"relation","from":"Domain_Setup_Apr26","to":"Runbook_VPS_Setup_Beget","relationType":"configures_domain_for"}
{"type":"relation","from":"Domain_Setup_Apr26","to":"Project_GenDesign","relationType":"domain_for"}
{"type":"relation","from":"HTTPS_Live_Apr26","to":"Runbook_VPS_Setup_Beget","relationType":"milestone_of"}
{"type":"relation","from":"HTTPS_Live_Apr26","to":"DockerOps_Apr26","relationType":"completed_after"}
{"type":"relation","from":"HTTPS_Live_Apr26","to":"Project_GenDesign","relationType":"production_milestone_for"}
{"type":"relation","from":"HTTPS_Live_Apr26","to":"NorthStar_DiscoveryMVP","relationType":"infra_acceptance_for"}
{"type":"relation","from":"DataSource_Fedstat_Apr26","to":"Project_GenDesign","relationType":"baseline_pricing_for"}
{"type":"relation","from":"DataSource_Fedstat_Apr26","to":"DataSources_Analysis_Apr26","relationType":"described_in"}
{"type":"relation","from":"DataSource_Fedstat_Apr26","to":"DataSource_Rosreestr_DealsCSV_Apr26","relationType":"cross_validates_with"}
{"type":"relation","from":"DataSource_CBR_Mortgage_Apr26","to":"Project_GenDesign","relationType":"mortgage_data_for"}
{"type":"relation","from":"DataSource_CBR_Mortgage_Apr26","to":"DataSource_PerDeal_Reality_Apr26","relationType":"cross_validation_for"}
{"type":"relation","from":"DataSource_CBR_Mortgage_Apr26","to":"DomRF_Tab11_MortgageStats_Apr26","relationType":"complements_supply_side_of"}
{"type":"relation","from":"DataSource_CBR_Mortgage_Apr26","to":"DataSources_Analysis_Apr26","relationType":"described_in"}
{"type":"relation","from":"DomRF_Recon_RobotsTxt_Apr26","to":"DomRF_Architecture_Apr26","relationType":"annotates"}
{"type":"relation","from":"DomRF_Recon_RobotsTxt_Apr26","to":"DomRF_Enums_Apr26","relationType":"expands_param_list_for"}
{"type":"relation","from":"DomRF_Integration_Docs_Apr26","to":"DomRF_OfficialVsFront_Comparison_Apr26","relationType":"supports_comparison"}
{"type":"relation","from":"DomRF_Integration_Docs_Apr26","to":"DomRF_Spec_APF_v22","relationType":"documents"}
{"type":"relation","from":"DomRF_Integration_Docs_Apr26","to":"DomRF_Spec_SJS_v130","relationType":"documents"}
{"type":"relation","from":"DomRF_Integration_Docs_Apr26","to":"DomRF_Spec_NSI_v101","relationType":"documents"}
{"type":"relation","from":"DomRF_Integration_Docs_Apr26","to":"DomRF_Spec_UOPO_v102","relationType":"documents"}
{"type":"relation","from":"DomRF_OfficialAuth_Apr26","to":"DomRF_Architecture_Apr26","relationType":"official_b2b_auth_for"}
{"type":"relation","from":"DomRF_Spec_SJS_v130","to":"DomRF_OfficialVsFront_Comparison_Apr26","relationType":"compared_in"}
{"type":"relation","from":"DomRF_Spec_NSI_v101","to":"DomRF_OfficialVsFront_Comparison_Apr26","relationType":"compared_in"}
{"type":"relation","from":"DomRF_Spec_UOPO_v102","to":"DomRF_OfficialVsFront_Comparison_Apr26","relationType":"compared_in"}
{"type":"relation","from":"DomRF_Spec_APF_v22","to":"DomRF_OfficialVsFront_Comparison_Apr26","relationType":"compared_in"}
{"type":"relation","from":"DataSources_Analysis_Apr26","to":"DomRF_PlanA_Mapping_Apr26","relationType":"concretized_into"}
{"type":"relation","from":"DataSources_Analysis_Apr26","to":"DataSource_Rosreestr_DealsCSV_Apr26","relationType":"describes_priority_1"}
{"type":"relation","from":"DataSources_Analysis_Apr26","to":"DataSource_UPN_Ekb_Apr26","relationType":"lists_as_ekb_baseline"}
{"type":"relation","from":"Sentry_Setup_Apr26","to":"Project_GenDesign","relationType":"observability_for"}
{"type":"relation","from":"OpsBundle_Apr26","to":"Stages_MVP_v1","relationType":"prepares_alembic_for_stage_2a"}
{"type":"relation","from":"Domclick_DDF_Report_Nov2025","to":"Project_GenDesign","relationType":"industry_intelligence_for"}
{"type":"relation","from":"Domclick_DDF_Report_Nov2025","to":"DataSources_Analysis_Apr26","relationType":"extends"}
{"type":"relation","from":"Domclick_DDF_Report_Nov2025","to":"PlanA_AnalyticsFirst_Apr25","relationType":"validates_3_tile_thesis_for"}
{"type":"relation","from":"Affordability_Trends_DDF_Nov2025","to":"Domclick_DDF_Report_Nov2025","relationType":"is_section_of"}
{"type":"relation","from":"Affordability_Trends_DDF_Nov2025","to":"PlanA_AnalyticsFirst_Apr25","relationType":"informs_tile2_of"}
{"type":"relation","from":"Affordability_Trends_DDF_Nov2025","to":"DataSource_CBR_Mortgage_Apr26","relationType":"complements"}
{"type":"relation","from":"PriceGap_Quality_vs_Rate_Nov2025","to":"Domclick_DDF_Report_Nov2025","relationType":"is_section_of"}
{"type":"relation","from":"PriceGap_Quality_vs_Rate_Nov2025","to":"DataSource_Rosreestr_DealsCSV_Apr26","relationType":"explains_dkp_ddu_gap_in"}
{"type":"relation","from":"PriceGap_Quality_vs_Rate_Nov2025","to":"Sverdlovsk_Profile_DDF_Nov2025","relationType":"highlights_sverdlovsk_in"}
{"type":"relation","from":"AlternativeDeal_Trends_Nov2025","to":"Domclick_DDF_Report_Nov2025","relationType":"is_section_of"}
{"type":"relation","from":"AlternativeDeal_Trends_Nov2025","to":"PlanA_AnalyticsFirst_Apr25","relationType":"informs_tile2_of"}
{"type":"relation","from":"AlternativeDeal_Trends_Nov2025","to":"Sverdlovsk_Profile_DDF_Nov2025","relationType":"evaluates"}
{"type":"relation","from":"RepeatedMortgage_Nov2025","to":"Domclick_DDF_Report_Nov2025","relationType":"is_section_of"}
{"type":"relation","from":"RepeatedMortgage_Nov2025","to":"PlanA_AnalyticsFirst_Apr25","relationType":"informs_tile1_of"}
{"type":"relation","from":"RepeatedMortgage_Nov2025","to":"QualityShift_NewBuild_2021_2025","relationType":"explains_driver_of"}
{"type":"relation","from":"QualityShift_NewBuild_2021_2025","to":"Domclick_DDF_Report_Nov2025","relationType":"is_section_of"}
{"type":"relation","from":"QualityShift_NewBuild_2021_2025","to":"PlanA_AnalyticsFirst_Apr25","relationType":"redefines_tile1_for"}
{"type":"relation","from":"QualityShift_NewBuild_2021_2025","to":"DomRF_Tab8_Quartirografia_Apr26","relationType":"trend_signal_for"}
{"type":"relation","from":"QualityShift_NewBuild_2021_2025","to":"Stages_MVP_v1","relationType":"informs_unit_mix_defaults_for"}
{"type":"relation","from":"RegionGroups_BuildingDemand_Nov2025","to":"Domclick_DDF_Report_Nov2025","relationType":"is_section_of"}
{"type":"relation","from":"RegionGroups_BuildingDemand_Nov2025","to":"Sverdlovsk_Profile_DDF_Nov2025","relationType":"classifies"}
{"type":"relation","from":"RegionGroups_BuildingDemand_Nov2025","to":"Project_GenDesign","relationType":"expansion_strategy_for"}
{"type":"relation","from":"DemandIndex_Domclick_Nov2025","to":"Domclick_DDF_Report_Nov2025","relationType":"is_section_of"}
{"type":"relation","from":"DemandIndex_Domclick_Nov2025","to":"Project_GenDesign","relationType":"site_finder_blueprint_for"}
{"type":"relation","from":"DemandIndex_Domclick_Nov2025","to":"DataSource_Rosreestr_DealsCSV_Apr26","relationType":"uses_factor_from"}
{"type":"relation","from":"DemandIndex_Domclick_Nov2025","to":"DomRF_Tab7_ReadyConstruction_Apr26","relationType":"uses_velocity_from"}
{"type":"relation","from":"DemandIndex_Domclick_Nov2025","to":"Stages_MVP_v1","relationType":"informs_site_finder_scoring_for"}
{"type":"relation","from":"Regional_Migration_Buyers_Nov2025","to":"Domclick_DDF_Report_Nov2025","relationType":"is_section_of"}
{"type":"relation","from":"Regional_Migration_Buyers_Nov2025","to":"Sverdlovsk_Profile_DDF_Nov2025","relationType":"places"}
{"type":"relation","from":"Regional_Migration_Buyers_Nov2025","to":"PlanA_AnalyticsFirst_Apr25","relationType":"adds_buyer_origin_factor_to"}
{"type":"relation","from":"Sverdlovsk_Profile_DDF_Nov2025","to":"Domclick_DDF_Report_Nov2025","relationType":"is_section_of"}
{"type":"relation","from":"Sverdlovsk_Profile_DDF_Nov2025","to":"Project_GenDesign","relationType":"regional_market_profile_for"}
{"type":"relation","from":"Sverdlovsk_Profile_DDF_Nov2025","to":"DataSource_UPN_Ekb_Apr26","relationType":"complements"}
{"type":"relation","from":"Sverdlovsk_Profile_DDF_Nov2025","to":"DataSource_Rosreestr_DealsCSV_Sverdl_Q1_2026","relationType":"context_for"}
{"type":"relation","from":"Domclick_DDF_Report_Nov2025","to":"DataSource_Fedstat_Apr26","relationType":"uses_rosstat_data_via"}
{"type":"relation","from":"Rosreestr_DealsCSV_Loaded_Prod_Apr26","to":"DataSource_Rosreestr_DealsCSV_Apr26","relationType":"implements_etl_for"}
{"type":"relation","from":"Rosreestr_DealsCSV_Loaded_Prod_Apr26","to":"DataSource_Rosreestr_ETL_Plan_Apr26","relationType":"executes"}
{"type":"relation","from":"Rosreestr_DealsCSV_Loaded_Prod_Apr26","to":"Project_GenDesign","relationType":"data_layer_milestone_for"}
{"type":"relation","from":"Rosreestr_DealsCSV_Loaded_Prod_Apr26","to":"Runbook_VPS_Setup_Beget","relationType":"deployed_on"}
{"type":"relation","from":"Rosreestr_DealsCSV_Loaded_Prod_Apr26","to":"PlanA_AnalyticsFirst_Apr25","relationType":"unblocks_tile2_for"}
{"type":"relation","from":"Rosreestr_DealsCSV_Loaded_Prod_Apr26","to":"Stages_MVP_v1","relationType":"advances_stage_2a_data_layer_of"}
{"type":"relation","from":"Rosreestr_DealsCSV_Loaded_Prod_Apr26","to":"DataSource_Rosreestr_DealsCSV_Sverdl_Q1_2026","relationType":"validated_against"}
{"type":"relation","from":"Rosreestr_DealsCSV_Loaded_Prod_Apr26","to":"Domclick_DDF_Report_Nov2025","relationType":"cross_validated_with"}
{"type":"relation","from":"Rosreestr_DealsCSV_Loaded_Prod_Apr26","to":"PriceGap_Quality_vs_Rate_Nov2025","relationType":"confirms_with_real_deals"}
{"type":"relation","from":"Rosreestr_DealsCSV_Loaded_Prod_Apr26","to":"DataSource_Rosreestr_DealsCSV_Limits_Apr26","relationType":"encountered_issues_described_in"}
{"type":"relation","from":"Rosreestr_DealsCSV_Loaded_Prod_Apr26","to":"DataSource_Rosreestr_DealsCSV_Schema_Apr26","relationType":"applied_schema_from"}
{"type":"relation","from":"Rosreestr_DealsCSV_Loaded_Prod_Apr26","to":"Rosreestr_TLS_Note_Apr26","relationType":"used_workaround_from"}
{"type":"relation","from":"DomRF_Analytics_Loaded_Prod_Apr26","to":"DomRF_Architecture_Apr26","relationType":"implements_etl_for"}
{"type":"relation","from":"DomRF_Analytics_Loaded_Prod_Apr26","to":"DomRF_API_PortalAnalytics_Apr26","relationType":"executes"}
{"type":"relation","from":"DomRF_Analytics_Loaded_Prod_Apr26","to":"Project_GenDesign","relationType":"data_layer_milestone_for"}
{"type":"relation","from":"DomRF_Analytics_Loaded_Prod_Apr26","to":"Runbook_VPS_Setup_Beget","relationType":"deployed_on"}
{"type":"relation","from":"DomRF_Analytics_Loaded_Prod_Apr26","to":"PlanA_AnalyticsFirst_Apr25","relationType":"unblocks_tile1_for"}
{"type":"relation","from":"DomRF_Analytics_Loaded_Prod_Apr26","to":"Rosreestr_DealsCSV_Loaded_Prod_Apr26","relationType":"complements_pricing_with_quartirografia"}
{"type":"relation","from":"DomRF_Analytics_Loaded_Prod_Apr26","to":"DataSources_Analysis_Apr26","relationType":"validates_priority1_choice_of"}
{"type":"relation","from":"DomRF_Analytics_Loaded_Prod_Apr26","to":"QualityShift_NewBuild_2021_2025","relationType":"snapshot_confirms_trend_of"}
{"type":"relation","from":"DomRF_Analytics_Loaded_Prod_Apr26","to":"DomRF_Tab8_Quartirografia_Apr26","relationType":"concrete_implementation_of"}
{"type":"relation","from":"DomRF_Analytics_Loaded_Prod_Apr26","to":"DomRF_KeyAndLegal_Apr26","relationType":"operates_under_legal_terms_of"}
{"type":"relation","from":"DomRF_XLSX_PDF_Snapshot_Loaded_Apr26","to":"DomRF_Analytics_Loaded_Prod_Apr26","relationType":"extends_with_xlsx_pdf"}
{"type":"relation","from":"DomRF_XLSX_PDF_Snapshot_Loaded_Apr26","to":"Project_GenDesign","relationType":"data_layer_milestone_for"}
{"type":"relation","from":"DomRF_XLSX_PDF_Snapshot_Loaded_Apr26","to":"Runbook_VPS_Setup_Beget","relationType":"deployed_on"}
{"type":"relation","from":"DomRF_XLSX_PDF_Snapshot_Loaded_Apr26","to":"PlanA_AnalyticsFirst_Apr25","relationType":"unblocks_tile3_for"}
{"type":"relation","from":"DomRF_XLSX_PDF_Snapshot_Loaded_Apr26","to":"DomRF_Tab7_ReadyConstruction_Apr26","relationType":"concrete_implementation_of"}
{"type":"relation","from":"DomRF_XLSX_PDF_Snapshot_Loaded_Apr26","to":"DomRF_Tab5_Escrow_Apr26","relationType":"concrete_implementation_of"}
{"type":"relation","from":"DomRF_XLSX_PDF_Snapshot_Loaded_Apr26","to":"DomRF_Tab11_MortgageStats_Apr26","relationType":"concrete_implementation_of"}
{"type":"relation","from":"DomRF_XLSX_PDF_Snapshot_Loaded_Apr26","to":"DomRF_Tab9_BuildingCommissioning_Apr26","relationType":"concrete_implementation_of"}
{"type":"relation","from":"DomRF_XLSX_PDF_Snapshot_Loaded_Apr26","to":"DomRF_Tab2_LaunchAndCommissioning_Apr26","relationType":"concrete_implementation_of"}
{"type":"relation","from":"DomRF_XLSX_PDF_Snapshot_Loaded_Apr26","to":"Rosreestr_DealsCSV_Loaded_Prod_Apr26","relationType":"complements_with_supply_side"}
{"type":"relation","from":"DomRF_XLSX_PDF_Snapshot_Loaded_Apr26","to":"Domclick_DDF_Report_Nov2025","relationType":"confirms_industry_thesis_of"}
{"type":"relation","from":"DomRF_XLSX_PDF_Snapshot_Loaded_Apr26","to":"DataSource_CBR_Mortgage_Apr26","relationType":"complements_with_bank_rates"}
{"type":"relation","from":"DomRF_XLSX_PDF_Snapshot_Loaded_Apr26","to":"Sverdlovsk_Profile_DDF_Nov2025","relationType":"validates_with_real_market_data"}
{"type":"relation","from":"DomRF_Playwright_Scraper_Apr26","to":"Project_GenDesign","relationType":"production_etl_for"}
{"type":"relation","from":"DomRF_Playwright_Scraper_Apr26","to":"DomRF_Architecture_Apr26","relationType":"automates_scraping_of"}
{"type":"relation","from":"DomRF_Scraped_Loaded_Prod_Apr26","to":"DomRF_Playwright_Scraper_Apr26","relationType":"uses_output_of"}
{"type":"relation","from":"DomRF_Scraped_Loaded_Prod_Apr26","to":"Runbook_VPS_Setup_Beget","relationType":"deployed_on"}
{"type":"relation","from":"DomRF_Scraped_Loaded_Prod_Apr26","to":"DomRF_Tab2_LaunchAndCommissioning_Apr26","relationType":"concrete_implementation_of"}
{"type":"relation","from":"DomRF_Scraped_Loaded_Prod_Apr26","to":"DomRF_Tab7_ReadyConstruction_Apr26","relationType":"concrete_implementation_of"}
{"type":"relation","from":"DomRF_Scraped_Loaded_Prod_Apr26","to":"DomRF_Tab3_ProjectFinance_Apr26","relationType":"concrete_implementation_of"}
{"type":"relation","from":"DomRF_Scraped_Loaded_Prod_Apr26","to":"DomRF_Tab9_BuildingCommissioning_Apr26","relationType":"concrete_implementation_of"}
{"type":"relation","from":"DomRF_Scraped_Loaded_Prod_Apr26","to":"DomRF_Tab11_MortgageStats_Apr26","relationType":"concrete_implementation_of"}
{"type":"relation","from":"DomRF_Scraped_Loaded_Prod_Apr26","to":"DomRF_Analytics_Loaded_Prod_Apr26","relationType":"extends_with_normalized_endpoints"}
{"type":"relation","from":"DomRF_Scraped_Loaded_Prod_Apr26","to":"DomRF_XLSX_PDF_Snapshot_Loaded_Apr26","relationType":"extends_with_full_api_data"}
{"type":"relation","from":"DomRF_Scraped_Loaded_Prod_Apr26","to":"PlanA_AnalyticsFirst_Apr25","relationType":"unblocks_full_data_layer_for"}
{"type":"relation","from":"DomRF_Schema_Relations_Apr26","to":"Project_GenDesign","relationType":"data_layer_integration_for"}
{"type":"relation","from":"DomRF_Schema_Relations_Apr26","to":"DomRF_Scraped_Loaded_Prod_Apr26","relationType":"links_tables_of"}
{"type":"relation","from":"DomRF_Schema_Relations_Apr26","to":"DomRF_Analytics_Loaded_Prod_Apr26","relationType":"links_tables_of"}
{"type":"relation","from":"DomRF_Schema_Relations_Apr26","to":"DomRF_XLSX_PDF_Snapshot_Loaded_Apr26","relationType":"links_tables_of"}
{"type":"relation","from":"DomRF_Schema_Relations_Apr26","to":"Rosreestr_DealsCSV_Loaded_Prod_Apr26","relationType":"joins_pricing_with_quartirografia_via_view"}
{"type":"relation","from":"DomRF_Schema_Relations_Apr26","to":"PlanA_AnalyticsFirst_Apr25","relationType":"enables_unified_query_for"}
{"type":"relation","from":"Session_End_Apr26_2026","to":"Project_GenDesign","relationType":"session_summary_for"}
{"type":"relation","from":"Session_End_Apr26_2026","to":"Rosreestr_DealsCSV_Loaded_Prod_Apr26","relationType":"completed_milestone"}
{"type":"relation","from":"Session_End_Apr26_2026","to":"DomRF_Analytics_Loaded_Prod_Apr26","relationType":"completed_milestone"}
{"type":"relation","from":"Session_End_Apr26_2026","to":"DomRF_XLSX_PDF_Snapshot_Loaded_Apr26","relationType":"completed_milestone"}
{"type":"relation","from":"Session_End_Apr26_2026","to":"DomRF_Scraped_Loaded_Prod_Apr26","relationType":"completed_milestone"}
{"type":"relation","from":"Session_End_Apr26_2026","to":"DomRF_Schema_Relations_Apr26","relationType":"completed_milestone"}
{"type":"relation","from":"DomRF_History_Loaded_Apr27_2026","to":"DomRF_Tab6_Realization_Apr26","relationType":"verifies_historical_support_of"}
{"type":"relation","from":"DomRF_History_Loaded_Apr27_2026","to":"DomRF_Tab7_ReadyConstruction_Apr26","relationType":"verifies_historical_support_of"}
{"type":"relation","from":"Sverdl_Quartirography_Report_Apr27","to":"DomRF_History_Loaded_Apr27_2026","relationType":"uses_data_from"}
{"type":"relation","from":"PRINZIP_Strategy_Apr27","to":"Sverdl_Quartirography_Report_Apr27","relationType":"derived_from"}
{"type":"relation","from":"Schema_Tables_Map_Apr27","to":"Schema_FK_Map_Apr27","relationType":"complements"}
{"type":"relation","from":"Schema_Tables_Map_Apr27","to":"Schema_Views_Catalogue_Apr27","relationType":"queried_via"}
{"type":"relation","from":"Schema_FK_Map_Apr27","to":"Schema_Tables_Map_Apr27","relationType":"constrains"}
{"type":"relation","from":"Schema_Views_Catalogue_Apr27","to":"Schema_Tables_Map_Apr27","relationType":"abstracts"}
{"type":"relation","from":"Schema_ETL_Artefacts_Apr27","to":"Schema_Tables_Map_Apr27","relationType":"produces"}
{"type":"relation","from":"Schema_ETL_Artefacts_Apr27","to":"Schema_FK_Map_Apr27","relationType":"produces"}
{"type":"relation","from":"Schema_ETL_Artefacts_Apr27","to":"Schema_Views_Catalogue_Apr27","relationType":"produces"}
{"type":"relation","from":"Schema_Open_TODOs_Apr27","to":"Schema_Tables_Map_Apr27","relationType":"extends_planned"}
{"type":"relation","from":"DomRF_History_Loaded_Apr27_2026","to":"Schema_ETL_Artefacts_Apr27","relationType":"documented_in"}
{"type":"relation","from":"Sverdl_Market_Trend_Apr27","to":"DomRF_History_Loaded_Apr27_2026","relationType":"uses_data_from"}
{"type":"relation","from":"Sverdl_Market_Trend_Apr27","to":"Schema_Tables_Map_Apr27","relationType":"queries"}
{"type":"relation","from":"Sverdl_Market_Trend_Apr27","to":"Sverdl_Quartirography_Report_Apr27","relationType":"summarized_in"}
{"type":"relation","from":"Competitor_Benchmark_Brusnika_Apr27","to":"Schema_Views_Catalogue_Apr27","relationType":"uses_view"}
{"type":"relation","from":"Competitor_Benchmark_Brusnika_Apr27","to":"PRINZIP_Strategy_Apr27","relationType":"informs"}
{"type":"relation","from":"Competitor_Benchmark_ForumGroup_Apr27","to":"Schema_Views_Catalogue_Apr27","relationType":"uses_view"}
{"type":"relation","from":"Competitor_Benchmark_ForumGroup_Apr27","to":"PRINZIP_Strategy_Apr27","relationType":"informs"}
{"type":"relation","from":"Competitor_Benchmark_Brusnika_Apr27","to":"Competitor_Benchmark_ForumGroup_Apr27","relationType":"compared_with"}
{"type":"relation","from":"PRINZIP_Strategy_Apr27","to":"Sverdl_Market_Trend_Apr27","relationType":"contextualized_by"}
{"type":"relation","from":"Sverdl_Quartirography_Report_Apr27","to":"Schema_Views_Catalogue_Apr27","relationType":"queried_via"}
{"type":"relation","from":"Schema_Open_TODOs_Apr27","to":"PRINZIP_Strategy_Apr27","relationType":"blocks_completion_of"}
{"type":"relation","from":"Schema_Views_Catalogue_Apr27","to":"PRINZIP_Strategy_Apr27","relationType":"enables_analysis_for"}
{"type":"relation","from":"Schema_Views_Catalogue_Apr27","to":"Sverdl_Quartirography_Report_Apr27","relationType":"enables_analysis_for"}
{"type":"relation","from":"Session_End_Apr26_2026","to":"Schema_Tables_Map_Apr27","relationType":"predates_state_of"}
{"type":"relation","from":"DomRF_History_Loaded_Apr27_2026","to":"Schema_Tables_Map_Apr27","relationType":"extends_data_in"}
{"type":"relation","from":"PRINZIP_Strategy_Apr27","to":"Schema_Views_Catalogue_Apr27","relationType":"queries"}
{"type":"relation","from":"DomRF_Lazy_Loaded_Apr27_2026","to":"DomRF_Playwright_Scraper_Apr26","relationType":"extends"}
{"type":"relation","from":"DomRF_Lazy_Loaded_Apr27_2026","to":"Schema_Tables_Map_Apr27","relationType":"adds_tables_to"}
{"type":"relation","from":"DomRF_Lazy_Loaded_Apr27_2026","to":"DomRF_Tab1_HousingIndicators_Apr26","relationType":"implements_spec_from"}
{"type":"relation","from":"DomRF_Lazy_Loaded_Apr27_2026","to":"DomRF_Tab6_Realization_Apr26","relationType":"implements_spec_from"}
{"type":"relation","from":"DomRF_Lazy_Loaded_Apr27_2026","to":"DomRF_Tab12_StatRows_Apr26","relationType":"implements_spec_from"}
{"type":"relation","from":"DomRF_Lazy_Loaded_Apr27_2026","to":"DomRF_Scraped_Loaded_Prod_Apr26","relationType":"completes_remaining_5_pages_of"}
{"type":"relation","from":"DomRF_Lazy_Loaded_Apr27_2026","to":"DomRF_XLSX_PDF_Snapshot_Loaded_Apr26","relationType":"extends_with_full_region_coverage"}
{"type":"relation","from":"DomRF_Lazy_Loaded_Apr27_2026","to":"Schema_ETL_Artefacts_Apr27","relationType":"documented_in"}
{"type":"relation","from":"DomRF_History_Loaded_Apr27_2026","to":"DomRF_Lazy_Loaded_Apr27_2026","relationType":"extends_with_historical_data"}
{"type":"relation","from":"Anton_Imported_Apr27_2026","to":"Schema_Tables_Map_Apr27","relationType":"extends_data_in"}
{"type":"relation","from":"Anton_Imported_Apr27_2026","to":"Schema_ETL_Artefacts_Apr27","relationType":"documented_in"}
{"type":"relation","from":"Anton_Imported_Apr27_2026","to":"DomRF_History_Loaded_Apr27_2026","relationType":"complements_history_with_breadth"}
{"type":"relation","from":"PRINZIP_Strategy_Apr27","to":"Anton_Imported_Apr27_2026","relationType":"uses_data_from"}
{"type":"relation","from":"Sverdl_Quartirography_Report_Apr27","to":"Anton_Imported_Apr27_2026","relationType":"uses_data_from"}
{"type":"relation","from":"Session_End_Apr27_2026","to":"Session_End_Apr26_2026","relationType":"succeeds"}
{"type":"relation","from":"Session_End_Apr27_2026","to":"Schema_Tables_Map_Apr27","relationType":"summarizes_state_of"}
{"type":"relation","from":"Session_End_Apr27_2026","to":"Schema_Open_TODOs_Apr27","relationType":"points_to_next_actions"}
{"type":"relation","from":"Session_End_Apr27_2026","to":"PRINZIP_Strategy_Apr27","relationType":"highlights_deliverable"}
{"type":"relation","from":"Session_End_Apr27_2026","to":"Sverdl_Quartirography_Report_Apr27","relationType":"highlights_deliverable"}
{"type":"relation","from":"Session_End_Apr27_2026","to":"DomRF_Lazy_Loaded_Apr27_2026","relationType":"completed_milestone"}
{"type":"relation","from":"Session_End_Apr27_2026","to":"DomRF_History_Loaded_Apr27_2026","relationType":"completed_milestone"}
{"type":"relation","from":"Session_End_Apr27_2026","to":"Anton_Imported_Apr27_2026","relationType":"completed_milestone"}
{"type":"relation","from":"Analytics_Dashboard_Apr27","to":"PRINZIP_Strategy_Apr27","relationType":"surfaces_in_ui"}
{"type":"relation","from":"Analytics_Dashboard_Apr27","to":"Sverdl_Quartirography_Report_Apr27","relationType":"surfaces_in_ui"}
{"type":"relation","from":"Analytics_Dashboard_Apr27","to":"Schema_Open_TODOs_Apr27","relationType":"partially_resolves"}
{"type":"relation","from":"Analytics_Dashboard_Apr27","to":"Schema_Tables_Map_Apr27","relationType":"consumes_schema_from"}
{"type":"relation","from":"Session_End_Apr27_2026","to":"Analytics_Dashboard_Apr27","relationType":"spawned_followup"}
{"type":"relation","from":"DomRf_Kn_Scraper_Apr27","to":"Schema_Open_TODOs_Apr27","relationType":"resolves_todo_1"}
{"type":"relation","from":"DomRf_Kn_Scraper_Apr27","to":"PRINZIP_Strategy_Apr27","relationType":"unblocks_analysis"}
{"type":"relation","from":"DomRf_Kn_Scraper_Apr27","to":"Analytics_Dashboard_Apr27","relationType":"feeds_data_to"}
{"type":"relation","from":"Session_End_Apr27_2026","to":"DomRf_Kn_Scraper_Apr27","relationType":"spawned_followup"}
{"type":"relation","from":"Prinzip_CRM_Pipeline_Apr27","to":"DomRf_Kn_Scraper_Apr27","relationType":"complements_data_layer"}
{"type":"relation","from":"Prinzip_CRM_Pipeline_Apr27","to":"PRINZIP_Strategy_Apr27","relationType":"unblocks_conversion_analysis"}
{"type":"relation","from":"Route_Home","to":"Route_Analytics_Sverdl","relationType":"links_to"}
{"type":"relation","from":"Route_Home","to":"Route_Analytics_Prinzip","relationType":"links_to"}
{"type":"relation","from":"Route_Home","to":"Route_Analytics_Developers","relationType":"links_to"}
{"type":"relation","from":"Route_Home","to":"Route_Analytics_Object","relationType":"links_to"}
{"type":"relation","from":"Route_Home","to":"Route_Admin_Scrape","relationType":"links_to"}
{"type":"relation","from":"Route_Home","to":"Route_Admin_Leads","relationType":"links_to"}
{"type":"relation","from":"Route_Analytics_Prinzip","to":"Route_Analytics_Object","relationType":"drilldowns_into"}
{"type":"relation","from":"Route_Analytics_Developers","to":"Route_Analytics_Object","relationType":"drilldowns_into"}
{"type":"relation","from":"Route_Admin_Leads","to":"Route_Analytics_Object","relationType":"drilldowns_into"}
{"type":"relation","from":"Route_Analytics_Object","to":"Endpoint_Analytics_Object","relationType":"consumes"}
{"type":"relation","from":"Route_Analytics_Prinzip","to":"Endpoint_Analytics_Object","relationType":"consumes"}
{"type":"relation","from":"Route_Admin_Scrape","to":"Endpoint_Admin_Scrape","relationType":"consumes"}
{"type":"relation","from":"Route_Admin_Leads","to":"Endpoint_Admin_Leads","relationType":"consumes"}
{"type":"relation","from":"Route_Admin_Scrape","to":"Auth_Admin_Token","relationType":"protected_by"}
{"type":"relation","from":"Route_Admin_Leads","to":"Auth_Admin_Token","relationType":"protected_by"}
{"type":"relation","from":"Endpoint_Admin_Scrape","to":"Auth_Admin_Token","relationType":"validates"}
{"type":"relation","from":"Endpoint_Admin_Leads","to":"Auth_Admin_Token","relationType":"validates"}
{"type":"relation","from":"Endpoint_Admin_Scrape","to":"Module_Celery_App","relationType":"delegates_to"}
{"type":"relation","from":"Module_Celery_App","to":"Module_Scraper_Kn","relationType":"invokes"}
{"type":"relation","from":"Module_Scraper_Kn","to":"Module_Scraper_Stealth","relationType":"uses"}
{"type":"relation","from":"Module_Scraper_Stealth","to":"Stealth_Fingerprint_State","relationType":"loads"}
{"type":"relation","from":"Module_Scraper_Kn","to":"DomRf_Kn_Scraper_Apr27","relationType":"implements"}
{"type":"relation","from":"Endpoint_Admin_Leads","to":"PII_Compliance_152FZ","relationType":"enforces"}
{"type":"relation","from":"Prinzip_CRM_Pipeline_Apr27","to":"PII_Compliance_152FZ","relationType":"enforces"}
{"type":"relation","from":"Prinzip_CRM_Pipeline_Apr27","to":"Endpoint_Admin_Leads","relationType":"exposed_via"}
{"type":"relation","from":"Prinzip_CRM_Pipeline_Apr27","to":"Route_Admin_Leads","relationType":"rendered_in"}
{"type":"relation","from":"Docker_Multi_Target","to":"Module_Scraper_Stealth","relationType":"ships_chromium_for"}
{"type":"relation","from":"Docker_Multi_Target","to":"Module_Celery_App","relationType":"runs_worker_image"}
{"type":"relation","from":"Docker_Auto_Cleanup","to":"Docker_Multi_Target","relationType":"maintains"}
{"type":"relation","from":"GitHub_Issue_13_Closed","to":"Module_Scraper_Kn","relationType":"depends_on"}
{"type":"relation","from":"GitHub_Issue_14_Closed","to":"Prinzip_CRM_Pipeline_Apr27","relationType":"delivered_by"}
{"type":"relation","from":"GitHub_Issue_15_Closed","to":"Endpoint_Analytics_Object","relationType":"delivered_by"}
{"type":"relation","from":"GitHub_Issue_15_Closed","to":"Route_Analytics_Object","relationType":"delivered_by"}
{"type":"relation","from":"GitHub_Issue_16_Closed","to":"Docker_Multi_Target","relationType":"delivered_by"}
{"type":"relation","from":"Analytics_Dashboard_Apr27","to":"Route_Analytics_Sverdl","relationType":"rendered_as"}
{"type":"relation","from":"Analytics_Dashboard_Apr27","to":"Route_Analytics_Prinzip","relationType":"rendered_as"}
{"type":"relation","from":"Analytics_Dashboard_Apr27","to":"Route_Analytics_Developers","relationType":"rendered_as"}
{"type":"relation","from":"DomRf_Kn_Scraper_Apr27","to":"Module_Scraper_Kn","relationType":"code_at"}
{"type":"relation","from":"DomRf_Kn_Scraper_Apr27","to":"Module_Scraper_Stealth","relationType":"code_at"}
{"type":"relation","from":"DomRf_Kn_Scraper_Apr27","to":"Module_Celery_App","relationType":"scheduled_via"}
{"type":"relation","from":"DomRf_Kn_Scraper_Apr27","to":"Stealth_Fingerprint_State","relationType":"uses_cookies_from"}
{"type":"relation","from":"Endpoint_Recommend_Mix","to":"Schema_Recommend_IO","relationType":"validates_with"}
{"type":"relation","from":"Endpoint_Recommend_Mix","to":"Module_Recommend_Query","relationType":"calls"}
{"type":"relation","from":"Module_Recommend_Query","to":"Module_Bucket_Distribution","relationType":"uses"}
{"type":"relation","from":"Module_Recommend_Query","to":"Window_Auto_Extend_24mo","relationType":"applies"}
{"type":"relation","from":"Module_Recommend_Query","to":"Class_Multiplier_Yandex","relationType":"applies"}
{"type":"relation","from":"Module_Bucket_Distribution","to":"Quartirography_Filter_Fix","relationType":"applies"}
{"type":"relation","from":"Module_Recommend_Query","to":"Limit_District_Median_Null","relationType":"limited_by"}
{"type":"relation","from":"Module_Recommend_Query","to":"Limit_District_Geometry","relationType":"limited_by"}
{"type":"relation","from":"Recommend_Level1_Apr27","to":"Endpoint_Recommend_Mix","relationType":"exposed_via"}
{"type":"relation","from":"Recommend_Level1_Apr27","to":"Module_Recommend_Query","relationType":"implemented_by"}
{"type":"relation","from":"Recommend_Level1_Apr27","to":"Route_Analytics_Recommend","relationType":"rendered_at"}
{"type":"relation","from":"Route_Analytics_Recommend","to":"Endpoint_Recommend_Mix","relationType":"consumes"}
{"type":"relation","from":"Route_Analytics_Recommend","to":"Component_Recommend_Form","relationType":"renders"}
{"type":"relation","from":"Route_Analytics_Recommend","to":"Component_Recommend_Sliders","relationType":"renders"}
{"type":"relation","from":"Route_Analytics_Recommend","to":"Component_Recommend_Charts","relationType":"renders"}
{"type":"relation","from":"Route_Analytics_Recommend","to":"Component_Recommend_Comparables","relationType":"renders"}
{"type":"relation","from":"Component_Recommend_Form","to":"Hook_useRecommendMix","relationType":"uses"}
{"type":"relation","from":"Hook_useRecommendMix","to":"Endpoint_Recommend_Mix","relationType":"calls"}
{"type":"relation","from":"Component_Recommend_Sliders","to":"Component_Recommend_Charts","relationType":"drives_recompute_of"}
{"type":"relation","from":"Component_Recommend_Comparables","to":"Route_Analytics_Object","relationType":"drilldowns_into"}
{"type":"relation","from":"Route_Home","to":"Route_Analytics_Recommend","relationType":"links_to"}
{"type":"relation","from":"Recommend_Level1_Apr27","to":"Schema_Open_TODOs_Apr27","relationType":"partially_resolves"}
{"type":"relation","from":"Endpoint_Photos_Serve","to":"Module_Photo_Thumbs","relationType":"uses"}
{"type":"relation","from":"Endpoint_Photos_Serve","to":"Photo_Lazy_Fetch","relationType":"applies"}
{"type":"relation","from":"Endpoint_Photos_Serve","to":"Schema_Photo_Thumb_Path","relationType":"reads_from"}
{"type":"relation","from":"Module_Photo_Thumbs","to":"Module_Scraper_Kn","relationType":"invoked_by"}
{"type":"relation","from":"Photo_Storage_Pipeline","to":"Endpoint_Photos_Serve","relationType":"exposed_via"}
{"type":"relation","from":"Photo_Storage_Pipeline","to":"Module_Photo_Thumbs","relationType":"uses"}
{"type":"relation","from":"Photo_Storage_Pipeline","to":"Schema_Photo_Thumb_Path","relationType":"requires"}
{"type":"relation","from":"Photo_Storage_Pipeline","to":"Photo_Lazy_Fetch","relationType":"uses"}
{"type":"relation","from":"Route_Analytics_Object","to":"Endpoint_Photos_Serve","relationType":"consumes"}
{"type":"relation","from":"Endpoint_Admin_Scrape","to":"Queue_Optimised_DB","relationType":"applies"}
{"type":"relation","from":"Endpoint_Admin_Scrape","to":"Zombie_Autocleanup","relationType":"applies"}
{"type":"relation","from":"Module_Celery_App","to":"Worker_Ready_Hook","relationType":"registers"}
{"type":"relation","from":"Module_Scraper_Kn","to":"Redis_Singleton_Lock","relationType":"uses"}
{"type":"relation","from":"Task_Resume_Kn_Run","to":"Redis_Singleton_Lock","relationType":"uses"}
{"type":"relation","from":"Task_Resume_Kn_Run","to":"Module_Scraper_Kn","relationType":"invokes"}
{"type":"relation","from":"Worker_Ready_Hook","to":"Task_Resume_Kn_Run","relationType":"enqueues"}
{"type":"relation","from":"Worker_Ready_Hook","to":"Schema_Resume_Columns","relationType":"reads_from"}
{"type":"relation","from":"Resume_Checkpoint_Mechanism","to":"Schema_Resume_Columns","relationType":"writes_to"}
{"type":"relation","from":"Resume_Checkpoint_Mechanism","to":"Worker_Ready_Hook","relationType":"triggered_by"}
{"type":"relation","from":"Resume_Checkpoint_Mechanism","to":"Task_Resume_Kn_Run","relationType":"executed_via"}
{"type":"relation","from":"Resume_Checkpoint_Mechanism","to":"Module_Scraper_Kn","relationType":"embedded_in"}
{"type":"relation","from":"Module_Scraper_Kn","to":"Module_Scrape_Log","relationType":"emits_via"}
{"type":"relation","from":"Module_Scrape_Log","to":"Schema_Scrape_Log_Table","relationType":"writes_to"}
{"type":"relation","from":"Endpoint_Scrape_Logs","to":"Schema_Scrape_Log_Table","relationType":"reads_from"}
{"type":"relation","from":"Endpoint_Scrape_Logs","to":"Auth_Admin_Token","relationType":"validates_with"}
{"type":"relation","from":"UI_Scrape_Progress_Panel","to":"Endpoint_Scrape_Logs","relationType":"consumes"}
{"type":"relation","from":"Route_Admin_Scrape","to":"UI_Scrape_Progress_Panel","relationType":"renders"}
{"type":"relation","from":"Bug_Worker_SIGKILL_Lost_Run_Fixed","to":"Resume_Checkpoint_Mechanism","relationType":"resolved_by"}
{"type":"relation","from":"Bug_Worker_SIGKILL_Lost_Run_Fixed","to":"Worker_Ready_Hook","relationType":"resolved_by"}
{"type":"relation","from":"Bug_Beat_Double_Fire_Fixed","to":"Redis_Singleton_Lock","relationType":"resolved_by"}
{"type":"relation","from":"Bug_Inspect_Slow_Queue_Fixed","to":"Queue_Optimised_DB","relationType":"resolved_by"}
{"type":"relation","from":"Bug_RealEstate_Outliers_Fixed","to":"Quartirography_Filter_Fix","relationType":"resolved_by"}
{"type":"relation","from":"Session_Resume_Recommend_Apr28_2026","to":"Session_End_Apr27_2026","relationType":"follows"}
{"type":"relation","from":"Session_Resume_Recommend_Apr28_2026","to":"Recommend_Level1_Apr27","relationType":"highlights_deliverable"}
{"type":"relation","from":"Session_Resume_Recommend_Apr28_2026","to":"Photo_Storage_Pipeline","relationType":"highlights_deliverable"}
{"type":"relation","from":"Session_Resume_Recommend_Apr28_2026","to":"Resume_Checkpoint_Mechanism","relationType":"highlights_deliverable"}
{"type":"relation","from":"Session_Resume_Recommend_Apr28_2026","to":"UI_Scrape_Progress_Panel","relationType":"highlights_deliverable"}
{"type":"relation","from":"Session_Resume_Recommend_Apr28_2026","to":"Bug_Worker_SIGKILL_Lost_Run_Fixed","relationType":"closes"}
{"type":"relation","from":"Session_Resume_Recommend_Apr28_2026","to":"Bug_Beat_Double_Fire_Fixed","relationType":"closes"}
{"type":"relation","from":"Session_Resume_Recommend_Apr28_2026","to":"Bug_Inspect_Slow_Queue_Fixed","relationType":"closes"}
{"type":"relation","from":"Session_Resume_Recommend_Apr28_2026","to":"Bug_RealEstate_Outliers_Fixed","relationType":"closes"}
{"type":"relation","from":"Session_Resume_Recommend_Apr28_2026","to":"Limit_District_Median_Null","relationType":"opens_todo"}
{"type":"relation","from":"Session_Resume_Recommend_Apr28_2026","to":"Limit_District_Geometry","relationType":"opens_todo"}
{"type":"relation","from":"Session_Resume_Recommend_Apr28_2026","to":"Schema_Tables_Map_Apr27","relationType":"extends"}
{"type":"relation","from":"Module_Recommend_Query","to":"Sverdl_Quartirography_Report_Apr27","relationType":"operationalizes"}
{"type":"relation","from":"Module_Recommend_Query","to":"PRINZIP_Strategy_Apr27","relationType":"operationalizes"}
{"type":"relation","from":"Bug_SQLAlchemy_DoubleColon_Cast","to":"Pattern_CAST_AS_Type","relationType":"resolved_by"}
{"type":"relation","from":"Bug_Recommend_500_CAST_Fixed","to":"Bug_SQLAlchemy_DoubleColon_Cast","relationType":"instance_of"}
{"type":"relation","from":"Bug_Recommend_500_CAST_Fixed","to":"Pattern_CAST_AS_Type","relationType":"resolved_by"}
{"type":"relation","from":"Bug_Phase_A_INSERT_500_Fixed","to":"Bug_SQLAlchemy_DoubleColon_Cast","relationType":"instance_of"}
{"type":"relation","from":"Bug_Phase_A_INSERT_500_Fixed","to":"Pattern_CAST_AS_Type","relationType":"resolved_by"}
{"type":"relation","from":"Bug_Phase_A_INSERT_500_Fixed","to":"Resume_Checkpoint_Mechanism","relationType":"blocked"}
{"type":"relation","from":"Bug_Phase_A_INSERT_500_Fixed","to":"Module_Scrape_Log","relationType":"diagnosed_via"}
{"type":"relation","from":"Recommend_Velocity_Calculator_Apr28","to":"Recommend_Level1_Apr27","relationType":"extends"}
{"type":"relation","from":"Recommend_Velocity_Calculator_Apr28","to":"Module_Velocity_Baseline","relationType":"uses"}
{"type":"relation","from":"Recommend_Velocity_Calculator_Apr28","to":"Module_Elasticity_Coef","relationType":"uses"}
{"type":"relation","from":"Recommend_Velocity_Calculator_Apr28","to":"Module_Required_Price_Factor","relationType":"uses"}
{"type":"relation","from":"Recommend_Velocity_Calculator_Apr28","to":"Module_Liquidity_Score_24mo","relationType":"uses"}
{"type":"relation","from":"Recommend_Velocity_Calculator_Apr28","to":"Component_Recommend_Velocity_Panel","relationType":"rendered_by"}
{"type":"relation","from":"Recommend_Velocity_Calculator_Apr28","to":"Component_Recommend_Liquidity_Chart","relationType":"rendered_by"}
{"type":"relation","from":"Recommend_Velocity_Calculator_Apr28","to":"Feature_Headline_CEO","relationType":"produces"}
{"type":"relation","from":"Module_Velocity_Baseline","to":"Module_Recommend_Query","relationType":"called_by"}
{"type":"relation","from":"Module_Elasticity_Coef","to":"Module_Recommend_Query","relationType":"called_by"}
{"type":"relation","from":"Module_Required_Price_Factor","to":"Module_Recommend_Query","relationType":"embedded_in"}
{"type":"relation","from":"Module_Liquidity_Score_24mo","to":"Module_Recommend_Query","relationType":"embedded_in"}
{"type":"relation","from":"Module_Liquidity_Score_24mo","to":"Component_Recommend_Velocity_Panel","relationType":"duplicated_in"}
{"type":"relation","from":"Component_Recommend_Velocity_Panel","to":"Route_Analytics_Recommend","relationType":"rendered_at"}
{"type":"relation","from":"Component_Recommend_Liquidity_Chart","to":"Route_Analytics_Recommend","relationType":"rendered_at"}
{"type":"relation","from":"Feature_Headline_CEO","to":"Route_Analytics_Recommend","relationType":"rendered_at"}
{"type":"relation","from":"Bug_Velocity_Mix_Static_OPEN","to":"Tier_Alpha_Velocity_Overhaul_TODO","relationType":"resolved_by"}
{"type":"relation","from":"Bug_Velocity_Unrealistic_OPEN","to":"Tier_Alpha_Velocity_Overhaul_TODO","relationType":"resolved_by"}
{"type":"relation","from":"Bug_Velocity_Mix_Static_OPEN","to":"Module_Velocity_Baseline","relationType":"located_in"}
{"type":"relation","from":"Bug_Velocity_Unrealistic_OPEN","to":"Module_Velocity_Baseline","relationType":"located_in"}
{"type":"relation","from":"Tier_Alpha_Velocity_Overhaul_TODO","to":"Recommend_Velocity_Calculator_Apr28","relationType":"improves"}
{"type":"relation","from":"Bug_Lock_Held_Silent_Fixed","to":"TTL_Lock_Reduction","relationType":"resolved_by"}
{"type":"relation","from":"Bug_Lock_Held_Silent_Fixed","to":"Module_Lock_Diagnostic_Logs","relationType":"resolved_by"}
{"type":"relation","from":"Bug_Lock_Held_Silent_Fixed","to":"Endpoint_Release_Lock","relationType":"resolved_by"}
{"type":"relation","from":"Bug_Lock_Held_Silent_Fixed","to":"Param_Force_Trigger","relationType":"resolved_by"}
{"type":"relation","from":"Endpoint_Release_Lock","to":"Redis_Singleton_Lock","relationType":"operates_on"}
{"type":"relation","from":"Param_Force_Trigger","to":"Redis_Singleton_Lock","relationType":"manipulates"}
{"type":"relation","from":"Param_Force_Trigger","to":"Endpoint_Admin_Scrape","relationType":"extends"}
{"type":"relation","from":"Module_Lock_Diagnostic_Logs","to":"Module_Scrape_Log","relationType":"complements"}
{"type":"relation","from":"Module_Lock_Diagnostic_Logs","to":"UI_Scrape_Progress_Panel","relationType":"surfaces_in"}
{"type":"relation","from":"TTL_Lock_Reduction","to":"Redis_Singleton_Lock","relationType":"tunes"}
{"type":"relation","from":"Phase_A_Heartbeat_Tick","to":"Resume_Checkpoint_Mechanism","relationType":"extends"}
{"type":"relation","from":"Phase_A_Heartbeat_Tick","to":"Schema_Resume_Columns","relationType":"writes_to"}
{"type":"relation","from":"Autoclean_Heartbeat_Threshold","to":"Zombie_Autocleanup","relationType":"supersedes"}
{"type":"relation","from":"Autoclean_Heartbeat_Threshold","to":"Schema_Resume_Columns","relationType":"reads_from"}
{"type":"relation","from":"Endpoint_Release_Lock","to":"Auth_Admin_Token","relationType":"validates_with"}
{"type":"relation","from":"Deploy_Cache_State_Apr28","to":"Docker_Multi_Target","relationType":"optimizes"}
{"type":"relation","from":"Session_Apr28_Calc_Scraper_Apr28_2026","to":"Session_Resume_Recommend_Apr28_2026","relationType":"follows"}
{"type":"relation","from":"Session_Apr28_Calc_Scraper_Apr28_2026","to":"Recommend_Velocity_Calculator_Apr28","relationType":"highlights_deliverable"}
{"type":"relation","from":"Session_Apr28_Calc_Scraper_Apr28_2026","to":"Bug_Phase_A_INSERT_500_Fixed","relationType":"closes"}
{"type":"relation","from":"Session_Apr28_Calc_Scraper_Apr28_2026","to":"Bug_Recommend_500_CAST_Fixed","relationType":"closes"}
{"type":"relation","from":"Session_Apr28_Calc_Scraper_Apr28_2026","to":"Bug_Lock_Held_Silent_Fixed","relationType":"closes"}
{"type":"relation","from":"Session_Apr28_Calc_Scraper_Apr28_2026","to":"Bug_Velocity_Mix_Static_OPEN","relationType":"opens_todo"}
{"type":"relation","from":"Session_Apr28_Calc_Scraper_Apr28_2026","to":"Bug_Velocity_Unrealistic_OPEN","relationType":"opens_todo"}
{"type":"relation","from":"Session_Apr28_Calc_Scraper_Apr28_2026","to":"Tier_Alpha_Velocity_Overhaul_TODO","relationType":"opens_todo"}
{"type":"relation","from":"Session_Apr28_Calc_Scraper_Apr28_2026","to":"Deploy_Cache_State_Apr28","relationType":"highlights_deliverable"}
{"type":"relation","from":"Session_Apr28_Calc_Scraper_Apr28_2026","to":"Bug_SQLAlchemy_DoubleColon_Cast","relationType":"discovers"}
{"type":"relation","from":"Session_Apr28_Calc_Scraper_Apr28_2026","to":"Pattern_CAST_AS_Type","relationType":"establishes"}
{"type":"relation","from":"Geo_District_Mapping_Apr29","to":"Module_Fetch_Ekb_Districts","relationType":"uses"}
{"type":"relation","from":"Geo_District_Mapping_Apr29","to":"Schema_Ekb_Districts_Geom","relationType":"requires"}
{"type":"relation","from":"Geo_District_Mapping_Apr29","to":"Schema_Kn_Objects_District_Column","relationType":"requires"}
{"type":"relation","from":"Geo_District_Mapping_Apr29","to":"File_Ekb_Districts_Geojson_Cache","relationType":"produces"}
{"type":"relation","from":"Geo_District_Mapping_Apr29","to":"Module_Backfill_District_Names_Scraper","relationType":"extends_by"}
{"type":"relation","from":"Geo_District_Mapping_Apr29","to":"Pattern_OSM_Overpass_Admin_Level","relationType":"applies"}
{"type":"relation","from":"Module_Fetch_Ekb_Districts","to":"File_Ekb_Districts_Geojson_Cache","relationType":"writes_to"}
{"type":"relation","from":"Module_Fetch_Ekb_Districts","to":"Schema_Ekb_Districts_Geom","relationType":"writes_to"}
{"type":"relation","from":"Module_Fetch_Ekb_Districts","to":"Pattern_OSM_Overpass_Admin_Level","relationType":"applies"}
{"type":"relation","from":"Module_Backfill_District_Names_Scraper","to":"Schema_Ekb_Districts_Geom","relationType":"reads_from"}
{"type":"relation","from":"Module_Backfill_District_Names_Scraper","to":"Schema_Kn_Objects_District_Column","relationType":"writes_to"}
{"type":"relation","from":"Module_Backfill_District_Names_Scraper","to":"Module_Scraper_Kn","relationType":"embedded_in"}
{"type":"relation","from":"Module_Backfill_District_Names_Scraper","to":"Resume_Checkpoint_Mechanism","relationType":"runs_after"}
{"type":"relation","from":"Bug_Recommend_Addr_ILIKE_Returns_Zero_Fixed","to":"Geo_District_Mapping_Apr29","relationType":"resolved_by"}
{"type":"relation","from":"Bug_Recommend_Addr_ILIKE_Returns_Zero_Fixed","to":"Schema_Kn_Objects_District_Column","relationType":"resolved_by"}
{"type":"relation","from":"Bug_Recommend_Addr_ILIKE_Returns_Zero_Fixed","to":"Module_Recommend_Query","relationType":"located_in"}
{"type":"relation","from":"Module_Graceful_Obj_Class_Degrade","to":"Bug_Kn_API_Obj_Class_Always_Null_OPEN","relationType":"workarounds"}
{"type":"relation","from":"Module_Graceful_Obj_Class_Degrade","to":"Module_Recommend_Query","relationType":"embedded_in"}
{"type":"relation","from":"Bug_Kn_API_Obj_Class_Always_Null_OPEN","to":"Module_Scraper_Kn","relationType":"located_in"}
{"type":"relation","from":"Bug_Kn_Flats_Price_Per_M2_Sparse_OPEN","to":"Module_Scraper_Kn","relationType":"located_in"}
{"type":"relation","from":"Bug_Kn_Flats_Price_Per_M2_Sparse_OPEN","to":"Limit_District_Median_Partial","relationType":"blocks_full_resolution_of"}
{"type":"relation","from":"Backfill_District_Median_From_Kn_Flats","to":"Schema_Kn_Objects_District_Column","relationType":"depends_on"}
{"type":"relation","from":"Backfill_District_Median_From_Kn_Flats","to":"Limit_District_Median_Partial","relationType":"partially_resolves"}
{"type":"relation","from":"Limit_District_Median_Partial","to":"Limit_District_Median_Null","relationType":"supersedes"}
{"type":"relation","from":"Limit_District_Geometry_Closed","to":"Limit_District_Geometry","relationType":"supersedes"}
{"type":"relation","from":"Limit_District_Geometry_Closed","to":"Geo_District_Mapping_Apr29","relationType":"resolved_by"}
{"type":"relation","from":"Component_Recommend_Page_Reorder_Apr29","to":"Route_Analytics_Recommend","relationType":"rendered_at"}
{"type":"relation","from":"Component_Recommend_District_KPI_Strip","to":"Route_Analytics_Recommend","relationType":"rendered_at"}
{"type":"relation","from":"Component_Recommend_District_KPI_Strip","to":"Schema_Kn_Objects_District_Column","relationType":"displays_data_from"}
{"type":"relation","from":"Component_Recommend_District_KPI_Strip","to":"Module_Recommend_Query","relationType":"consumes_output_of"}
{"type":"relation","from":"Cleanup_Unused_Vars_Recommend","to":"Component_Recommend_Page_Reorder_Apr29","relationType":"complements"}
{"type":"relation","from":"Pricing_Slider_Range_Expanded_Apr29","to":"Component_Recommend_Velocity_Panel","relationType":"modifies"}
{"type":"relation","from":"Pricing_Slider_Range_Expanded_Apr29","to":"Schema_Recommend_IO","relationType":"modifies"}
{"type":"relation","from":"Module_Recommend_Query","to":"Schema_Kn_Objects_District_Column","relationType":"filters_by"}
{"type":"relation","from":"Session_GeoMapping_Apr29_2026","to":"Session_Apr28_Calc_Scraper_Apr28_2026","relationType":"follows"}
{"type":"relation","from":"Session_GeoMapping_Apr29_2026","to":"Geo_District_Mapping_Apr29","relationType":"highlights_deliverable"}
{"type":"relation","from":"Session_GeoMapping_Apr29_2026","to":"Bug_Recommend_Addr_ILIKE_Returns_Zero_Fixed","relationType":"closes"}
{"type":"relation","from":"Session_GeoMapping_Apr29_2026","to":"Limit_District_Geometry_Closed","relationType":"closes"}
{"type":"relation","from":"Session_GeoMapping_Apr29_2026","to":"Limit_District_Median_Partial","relationType":"partially_closes"}
{"type":"relation","from":"Session_GeoMapping_Apr29_2026","to":"Bug_Kn_API_Obj_Class_Always_Null_OPEN","relationType":"opens_todo"}
{"type":"relation","from":"Session_GeoMapping_Apr29_2026","to":"Bug_Kn_Flats_Price_Per_M2_Sparse_OPEN","relationType":"opens_todo"}
{"type":"relation","from":"Session_GeoMapping_Apr29_2026","to":"Component_Recommend_Page_Reorder_Apr29","relationType":"highlights_deliverable"}
{"type":"relation","from":"Session_GeoMapping_Apr29_2026","to":"Component_Recommend_District_KPI_Strip","relationType":"highlights_deliverable"}
{"type":"relation","from":"Session_GeoMapping_Apr29_2026","to":"Pricing_Slider_Range_Expanded_Apr29","relationType":"highlights_deliverable"}
{"type":"relation","from":"Session_GeoMapping_Apr29_2026","to":"Backfill_District_Median_From_Kn_Flats","relationType":"highlights_deliverable"}
{"type":"relation","from":"Session_End_Apr30_2026","to":"NSPD_Scrape_Complete_Apr30","relationType":"delivered"}
{"type":"relation","from":"Session_End_Apr30_2026","to":"Cad_Buildings_Schema_v2","relationType":"delivered"}
{"type":"relation","from":"Session_End_Apr30_2026","to":"Cad_Quarter_Backfill_Apr30","relationType":"delivered"}
{"type":"relation","from":"Session_End_Apr30_2026","to":"Sprint1_Plan_May2026","relationType":"produced"}
{"type":"relation","from":"Session_End_Apr30_2026","to":"Sprint2_Stage1_Generative","relationType":"produced"}
{"type":"relation","from":"Session_End_Apr30_2026","to":"Sprint3_Stage2_SiteFinder","relationType":"produced"}
{"type":"relation","from":"NSPD_Scrape_Complete_Apr30","to":"Cad_Quarter_Scrape_Apr29","relationType":"supersedes"}
{"type":"relation","from":"NSPD_Scrape_Complete_Apr30","to":"NSPD_API_Endpoints_Reference","relationType":"uses"}
{"type":"relation","from":"NSPD_Scrape_Complete_Apr30","to":"Cad_Buildings_Schema_v2","relationType":"populates"}
{"type":"relation","from":"Cad_Quarter_Backfill_Apr30","to":"NSPD_Scrape_Complete_Apr30","relationType":"depends_on"}
{"type":"relation","from":"NSPD_Scrape_Complete_Apr30","to":"Limit_District_Median_Partial","relationType":"closes"}
{"type":"relation","from":"Sprint1_Plan_May2026","to":"NSPD_Scrape_Complete_Apr30","relationType":"industrializes"}
{"type":"relation","from":"Sprint1_Plan_May2026","to":"Open_Limitations_Apr30","relationType":"addresses"}
{"type":"relation","from":"Sprint2_Stage1_Generative","to":"GitHub_Issues_Open_Apr30","relationType":"implements"}
{"type":"relation","from":"Sprint3_Stage2_SiteFinder","to":"GitHub_Issues_Open_Apr30","relationType":"implements"}
{"type":"relation","from":"Sprint3_Stage2_SiteFinder","to":"NSPD_Scrape_Complete_Apr30","relationType":"reuses_data_from"}
{"type":"relation","from":"Excluded_Items_User_Pref","to":"GitHub_Issues_Open_Apr30","relationType":"filters"}
{"type":"relation","from":"Session_End_Apr30_2026","to":"Session_Tier2_Apr29_2026_Late","relationType":"follows"}
{"type":"relation","from":"Open_Limitations_Apr30","to":"Bug_Velocity_Region_Wide_Rosreestr_Fixed_Apr29","relationType":"succeeds"}
{"type":"relation","from":"Module_Objective_Client","to":"Objective_Integration_May07_2026","relationType":"implements"}
{"type":"relation","from":"Module_Objective_Parser","to":"Objective_Integration_May07_2026","relationType":"implements"}
{"type":"relation","from":"Schema_Objective_v2_May07","to":"Objective_Integration_May07_2026","relationType":"backs"}
{"type":"relation","from":"Objective_API_Findings_May07","to":"Schema_Objective_v2_May07","relationType":"informs"}
{"type":"relation","from":"Objective_API_Findings_May07","to":"Module_Objective_Parser","relationType":"informs"}
{"type":"relation","from":"Module_Objective_Parser","to":"Schema_Objective_v2_May07","relationType":"writes_into"}
{"type":"relation","from":"Module_Objective_Client","to":"Module_Scraper_Stealth","relationType":"alternative_to"}
{"type":"relation","from":"Session_End_May07_2026","to":"Objective_Integration_May07_2026","relationType":"produced"}
{"type":"relation","from":"Session_End_May07_2026","to":"Session_End_Apr30_2026","relationType":"succeeds"}
{"type":"relation","from":"Objective_Integration_May07_2026","to":"DomRf_Kn_Scraper_Apr27","relationType":"complements"}
{"type":"relation","from":"Project_GenDesign","to":"SiteFinder_v0_2_May08","relationType":"deploys"}
{"type":"relation","from":"SiteFinder_v0_2_May08","to":"TechStack_v2.2","relationType":"diverges_from"}
{"type":"relation","from":"SiteFinder_v0_2_May08","to":"MVP_Scope_AreaSelect_Apr25","relationType":"contradicts"}