# Generative Design + Site Finder Две продуктовые линии в одной воронке: **Site Finder** (AI-подбор инвестиционных земельных участков) + **Generative Design** (автоматическая генерация концепций застройки) для девелоперов РФ. ## North Star К концу месяца 3: **3 платящих пилота** (≥30 тыс. ₽/мес каждый) + заявка в реестр российского ПО → право на Раунд А (20–25 млн ₽). Acceptance criteria разбиты на 3 блока (функционально / бизнесово / технически). Правило перехода: 3/3 → Раунд А; 2/3 → продление Фазы 0 на 1–2 мес.; 1/3 или меньше → стоп проекта. --- ## Текущий статус (27 апреля 2026) **Инфраструктура: live на HTTPS.** Прод доступен по [https://gendsgn.ru/](https://gendsgn.ru/), Let's Encrypt cert получен. Полный цикл автодеплоя из GitHub Actions работает. 26.04 прод полностью пересоздан (`down -v` + redeploy) — БД свежая, backend в multi-stage образе под non-root пользователем, healthcheck-и работают, ловит ошибки в Sentry. | Что | Где | Статус | |---|---|---| | **Production URL** | [https://gendsgn.ru/](https://gendsgn.ru/) | ✅ HTTP/2 + HTTP/3, валидный TLS | | **Health endpoint** | [https://gendsgn.ru/health](https://gendsgn.ru/health) | ✅ `{"status":"ok","environment":"prod"}` | | **www → apex** | https://www.gendsgn.ru/ | ✅ 301 redirect | | Production VPS | Beget Cloud, Москва, 2 vCPU / 4 GB / 40 GB NVMe | ✅ работает | | IP сервера | `46.173.16.127` | — | | Домен | `gendsgn.ru` (Beget, до 26.04.2027, ЕСИА VERIFIED) | ✅ DNS на 8.8.8.8/1.1.1.1 | | Postgres + PostGIS 3.4 | Docker, в составе compose | ✅ Up (healthy) | | Redis 7 | Docker | ✅ Up (healthy, redis-cli ping) | | Backend FastAPI | Docker, multi-stage, non-root, 1.44 GB | ✅ Up (healthy, curl /health) | | Frontend Next.js 15 | Docker, multi-stage, npm ci | ✅ Up | | Caddy reverse proxy | Docker, ports 80/443 | ✅ Up + auto-TLS Let's Encrypt | | GitHub Actions deploy | `.github/workflows/deploy.yml` | ✅ build → push GHCR → ssh deploy → git pull → caddy reload | | GHCR пакеты | `ghcr.io/lekss361/gendesign-{backend,frontend}` | приватные, сервер авторизуется через PAT | | UFW firewall | 22 / 80 / 443 | ✅ активен | | SSH hardening | root login off, password auth off | ✅ | | Sentry | проект `gendesign-backend` (org `qqq`, free tier) | ✅ DSN на VM, события приходят | | GitHub Issues / Milestones | 12 issues, 3 milestones (Stage 1 / Stage 2 / Infra Hardening) | ✅ backlog засеян | | Бэкапы pg_dump | `ops/backup.sh` готов | ⏸ S3-бакет не настроен (Selectel/Yandex) | **Решение по плану разработки: pending.** Антон (второй разработчик) сообщил о доступе к ДДУ-данным. Решается в понедельник 27.04.2026 — выбор между: - **Plan A (Analytics First)** — Stage 1 переезжает на «3 плитки» аналитики (что строить / по какой цене / за какое время), Generative и Site Finder сдвигаются; - **Original plan** — Stage 1 = Generative MVP, Stage 2 = Site Finder, аналитика как enrichment. Зависит от 5 факторов канала ДДУ: легальность, поля, покрытие, свежесть, условия коммерческого использования. См. сущности `PlanA_AnalyticsFirst_Apr25` и `SalesTracking_Strategy_Apr25` в графе памяти. **26.04 вечер — data discovery разблокировал Plan A независимо от Антона.** Найдены три легальных канала ground-truth-данных: 1. **Росреестр CSV-датасет** (`DataSource_Rosreestr_DealsCSV_Apr26`) — per-deal цены сделок ДКП+ДДУ из ФГИС ЕГРН, 9 кварталов 2024–Q1 2026, ~898К сделок РФ/квартал. Открытые данные по 8-ФЗ, разделитель `~`, гранулярность до кадастрового квартала. 2. **ДОМ.РФ фронт-API** (`DataSources_Analysis_Apr26` + 12 вкладок) — открытые JSON без auth (либо `Basic MTpqd2U=` хардкоден), per-flat прайс-лист, реализация/готовность как velocity. 3. **НСПД MarketAnalytics** (`NSPD_MarketAnalytics_FullArchitecture_Apr26`) — индикаторы цен по кадастровым кварталам, 8 лет longitudinal, GeoJSON-полигоны для heatmap. Архитектура полностью раскрыта в debug-браузере (saveUserFilters → graphEgrn*/tableEgrn/geomDataForHeatMap, серверная сессия фильтров через userFiltersId). ⚠ `graphEgrnCandleMedian`/`LineMedian` (абсолютные ₽/м²) дают 403 для physic-аккаунта — но эти данные мы уже получаем из CSV-датасета Росреестра. **27.04 — analytical layer полностью построен.** В прод-БД 43 `domrf_*/cbr_*/yandex_*/ekb_*/sv_*/rosreestr_*` таблицы (см. блок «Аналитический пласт данных» ниже). За день: - Загружено 5 lazy-load страниц ДОМ.РФ (`DomRF_Lazy_Loaded_Apr27_2026`) — `domrf_realization` 9.7K + stat_series XLSX 809K observations + 333 raw JSONB endpoints. - Догружена история 14 месяцев (Янв 2025 - Февр 2026) для realization + sold_ready через `repYear/repMonth` параметры (`DomRF_History_Loaded_Apr27_2026`) — `domrf_realization` итого **143 963** рядов, sold_ready_breakdown расширен до 7 chart-types с типизированными колонками. - Импортирован SQLite Антона (23 МБ) — 13 новых таблиц: `domrf_kn_flats` (27 563 поквартирно), `domrf_kn_objects` (1 516 ЖК), `cbr_mortgage_series` (3 308 ЦБ), `sber_ddf_metrics`, `yandex_realty_zk`, `ekb_districts`, `rosreestr_rent_deals`. Архив девелоперов смерджен (2 734 → 8 629). См. `Anton_Imported_Apr27_2026`. - Подключён MCP `crystaldba/postgres-mcp` (`.mcp.json`) — все DDL/SELECT теперь через `mcp__postgres__execute_sql` без `docker run psql` обёртки. - FK-аудит и cleanup: добавлены 4 missing FK, дропнуты 2 дублирующих индекса и 2 устаревшие таблицы (`sold_out_by_year`, `sold_out_by_progress` ⊂ `domrf_realization`), 8 `COMMENT ON TABLE` для документации источников. - Territory aliases для stat_series ↔ regions name mapping (`v_stat_series_resolved` view): 100% покрытие 809K observations через 101 alias. - Готовы 2 стратегических отчёта: `Sverdl_Quartirography_Report_Apr27` (общий по Свердл) + `PRINZIP_Strategy_Apr27` (что строить и куда смотреть). **27.04 вечер — analytics dashboard + DOM.РФ scraper.** Поверх аналитического пласта собран интерактивный дашборд + регулярный парсер для пополнения данных: - **Веб-аналитика** (`Analytics_Dashboard_Apr27`) — 3 страницы на ECharts/React Query: `/analytics` (рынок Свердл — KPI + market-pulse + парадокс «строят vs покупают» + pipeline + treemap районов ЕКБ), `/analytics/prinzip` (drill-down PRINZIP с benchmark-velocity, gap-bar к рынку, инсайты из стратегии), `/analytics/developers` (топ-15 + scatter velocity). Backend: `/api/v1/analytics` 11 endpoints поверх `v_developer_full_metrics`. - **DOM.РФ kn-API парсер** (`DomRf_Kn_Scraper_Apr27`) — Playwright in-context fetch (httpx бьётся об ServicePipe TLS-fingerprint, проверено), правильные endpoints `/сервисы/api/kn/object` (place=66, objStatus 0/1/2 = 442+2+1072 = **1516 ЖК Свердл, точно совпало с БД**) + `/portal-kn/api/sales/portal/table` (квартиры). Auth — `Basic MTpqd2U=` (`1:qwe`, не `jwe`!). Серверная фильтрация по `regions/developers` НЕ работает — фильтруем локально по `developer.companyGroup`. - **Extras-эндпойнты** (per-ЖК, того же sweep): `/sale_graph?type=apartments|parking` (time-series продаж), `/sales_agg` (текущие агрегаты 3 типов), `/infrastructure` (POI), `/construction/progress/photo` (мета+опц. binary). PRINZIP probe: 28 ЖК → 36 sale_graph + 6 sales_agg + 5 409 POI + 5 150 фото-метаданных. - **Расписание + ручной триггер** — Celery beat (cron из `SCRAPE_KN_CRON` env, jitter 0..30мин), `POST /api/v1/admin/scrape/kn` с `X-Admin-Token`, UI `/admin/scrape` (чекбоксы extras/photos + журнал ошибок с copy-URL для ручной проверки в браузере). - **Stealth** — Playwright fingerprint снят с локальной машины в `data/playwright_state.json` (26 cookies, ServicePipe NSC + Keycloak), закоммичен в git для server-reuse без cold-bootstrap. --- ## Аналитический пласт данных (data warehouse) — 27.04.2026 В прод-БД `gendesign` живёт **43 предметных таблицы** + 5 helper views + Rosreestr partitions. Размер БД ~2.1 ГБ. ### 🔌 Подключение | Метод | Команда | |---|---| | **MCP** (рекомендуется) | конфиг в `.mcp.json` (project root) — `mcp__postgres__execute_sql`, `analyze_db_health`, `list_objects`, `explain_query` и т.д. | | **psql via SSH-туннель** | `ssh -fN -L 15432:127.0.0.1:5432 gendesign` затем `PGPASSWORD=… psql -h 127.0.0.1 -p 15432 -U gendesign gendesign` | | **DBeaver / TablePlus** | localhost:15432 после открытия SSH-туннеля | ⚠️ Туннель уже открыт на машинах команды (gendesign@46.173.16.127). `.mcp.json` в `.gitignore` (содержит пароль). ### 📊 Карта таблиц (43 предметных) **ROSREESTR per-deal (1.1 ГБ)** | Таблица | Рядов | Описание | |---|---:|---| | `rosreestr_deals` (+ 7 партиций по кварталам 2024Q3-2026Q1) | 4 975 398 | Сырые сделки ДКП+ДДУ из ФГИС ЕГРН, 89 регионов | | `rosreestr_deals_staging` | UNLOGGED | буфер для `\copy` из CSV | | `rosreestr_rent_deals` | 1 071 | Договоры аренды Свердл Q1 2026 (Антон) | **ROSREESTR materialized views (305 МБ)** | MV | Рядов | Описание | |---|---:|---| | `rr_agg_cad_quarter` | 952 799 | (region, cad_quarter, period, doc_type, area_bucket) → p10/median/p90 ₽/м² | | `rr_agg_settlement` | 422 852 | (region, settlement, period, doc_type, realestate_type) | | `rr_agg_region` | 3 549 | percentile-агрегаты по регионам | **DOM.РФ справочники / dimensions** | Таблица | Рядов | Описание | |---|---:|---| | `domrf_regions` | 90 | PK region_id (0=РФ + 89 субъектов). FK target для 4 таблиц | | `domrf_developers` | **8 629** | реестр + архив (после merge с Антоном). PK developer_id ('6208_0'=PRINZIP) | | `domrf_developers_full` | 2 563 | XLSX-выгрузка с метриками area/permits/flats/share | | `domrf_snapshots` | 18 | snapshot_date dimension (4 базовых + 14 history Янв 2025-Февр 2026) | | `domrf_federal_districts` | 8 | 8 ФО как first-class lookup | | `domrf_territory_aliases` | 101 | text→(level, region_id\|fo_id) для нормализации имён | | `domrf_stat_series_indicators` | 123 | XLSX sheet codes → indicator_name | **DOM.РФ realization & sold_ready (history)** | Таблица | Рядов | Описание | |---|---:|---| | `domrf_realization` | **143 963** | 4 endpoint_types (total/housing/ready_year/developer) × 89 регионов × 14 monthly snapshots | | `domrf_sold_ready_index` | 15 | РФ-итог helio метрики per snapshot | | `domrf_sold_ready_breakdown` | 40 044 | 7 chart_types × dim_value × 14 snapshots (regionChart/devChart/foChart/cityPopulationChart/classChart/devValueChart/readyYearChart) с типизированными колонками | | `domrf_sold_ready_dynamics` | 3 450 | timeseries 2020-period × 4 chart_types | **DOM.РФ JSON dashboard** | Таблица | Рядов | Описание | |---|---:|---| | `domrf_region_aggregates` | 439 | (region, room_count_type) → flat_count/area/percent | | `domrf_developer_aggregates` | 11 063 | (developer × region × room_count) | | `domrf_flat_area_distribution` | 40 | РФ-уровень бакеты площади | **DOM.РФ XLSX/PDF снапшоты** | Таблица | Рядов | Описание | |---|---:|---| | `domrf_developers_full` | 2 563 | реестр девелоперов из XLSX | | `domrf_escrow_banks` | 28 | банки эскроу (Сбер 61%) | | `domrf_guaranty_regions` | 99 | РФ + 8 ФО + 89 регионов разбивка | | `domrf_housing_summary` | 58 | разбивка по механизмам | | `domrf_planned_commissioning` | 10 | план ввода 2026-2035 | | `domrf_sold_out` | 9 | РФ + 8 топ-регионов (PDF, ради unique `attracted_funds_mln_rub`) | | `domrf_mortgage_rates` | 20 | ставки топ-20 банков (PDF) | **DOM.РФ launch / commissioning** | Таблица | Рядов | Описание | |---|---:|---| | `domrf_launch_top` | 1 410 | топ-N developer/region/area/fo по запускам/вводу | | `domrf_launch_obj_class` | 4 | Типовой/Комфорт/Бизнес/Элитный | | `domrf_launch_monthly` | 75 | timeseries 2020-2026 | | `domrf_commissioning` | 1 | факт ввод (multifamily/private) | | `domrf_project_finance` | 99 | ПР финансирование РФ/ФО/регионы | **DOM.РФ stat_series (parsed XLSX 254 МБ)** | Таблица | Рядов | Описание | |---|---:|---| | `domrf_stat_series_observations` | **809 236** | long-form panel: 99 территорий × 123 индикатора × ~70 месяцев (2020-2026) | | `domrf_xlsx_files` | 9 | BYTEA-архив исходных XLSX (8 МБ) | **DOM.РФ ipoteka / mortgage** | Таблица | Рядов | Описание | |---|---:|---| | `domrf_mortgage_dashboard` | 1 | агрегат рынка ипотеки РФ | | `domrf_mortgage_details` | 2 | RUB/OTH валюты | **DOM.РФ /сервисы/api/kn/* (от Антона + наш scraper)** | Таблица | Рядов | Описание | |---|---:|---| | `domrf_kn_flats` | 28 389+ | поквартирный прайс. Антоновский snapshot 2026-04-27 + наши новые snapshot'ы (UNIQUE по `(id, snapshot_date)`) | | `domrf_kn_objects` | 1 516+ | реестр ЖК Свердл (1285 ЕКБ + 28 PRINZIP) с GPS, классом, эскроу. Наш scraper подтвердил 442+2+1072=1516 для региона 66 | | `domrf_dev_growth` | 139 | динамика 2024→2025 девелоперов | | `domrf_kn_sale_graph` ⭐ | 36+ | time-series продаж per-ЖК (apartments/parking × месяц). PRINZIP Парк Победы продал 95 квартир в 2025 | | `domrf_kn_sales_agg` ⭐ | 6+ | текущие агрегаты per-ЖК (apartments/nonliv/parking × total/realised/perc). Парк Победы 145/291=49% | | `domrf_kn_infrastructure` ⭐ | 5 409 | нормализованная POI вокруг ЖК (Спорт, Продукты, Образование, Медицина, Развлечения) с lat/lon/dist_m | | `domrf_kn_photos` ⭐ | 5 150 | метаданные фото прогресса стройки (URL + period_dt + size_bytes), binary в `data/raw/domrf_photos/` опционально | | `kn_scrape_runs` | 3 | журнал прогонов парсера: regions, developers, objects_count, flats_count, requests_count, status | | `kn_scrape_failures` | 78 | per-request ошибки с full_url для ручной проверки в браузере (404 для сданных ЖК = ожидаемо) | **ЦБ РФ ипотека (от Антона)** | Таблица | Рядов | Описание | |---|---:|---| | `cbr_mortgage_series` | 3 308 | 47 серий × {rf,sverdl} × Jan 2019 - Feb 2026 | | `cbr_mortgage_files` | 19 | XLSX-источники | **Внешние источники** | Таблица | Рядов | Описание | |---|---:|---| | `sber_ddf_metrics` | 20 | Сбер ДомКлик DDF nov2025: affordability, demand index, миграция, повторные ипотечники, price gap | | `yandex_realty_zk` | 12 | Yandex Realty ЖК ЕКБ snapshot | | `yandex_realty_class_prices` | 3 | разбивка по классам econom/comfort/elite | **Geo Свердл/ЕКБ** | Таблица | Рядов | Описание | |---|---:|---| | `ekb_districts` | 9 | 9 районов ЕКБ с zk_count/flat_count/area | | `ekb_metro` | 10 | станции метро ЕКБ | | `sv_cities` | 24 | не-ЕКБ города Свердл (Н.Тагил, Первоуральск, Арамиль) | | `sv_dev_sales` | 50 | ТОП-50 Свердл девелоперы Март 2026 | **Universal raw** | Таблица | Рядов | Описание | |---|---:|---| | `domrf_raw_endpoints` | 349 | universal JSONB store: каждый /api/* response с GIN-index на payload | ### 🔍 Helper views (9 шт) **Базовые (legacy):** | View | Описание | |---|---| | `v_market_pulse_rf` | one-row live-метрика РФ: 118.7M м² стройка / sold 30.91% / Цена 216 316 ₽/м² / ставка 19.9% vs 6.83% | | `v_developer_master` | полный профиль девелопера (legacy). PRINZIP sold% 48.4% — ЛИДЕР Свердл | | `v_region_master` | one-row-per-region: квартирография + sold_out + sold_ready + project_finance + guaranty + launch | | `v_rosreestr_market_by_region` | Rosreestr p10/median/p90 + DOM.РФ имена | | `v_stat_series_resolved` | stat_series_observations + alias + indicator_name (`WHERE region_id=66` → Свердл) | **Связи квартиры↔ЖК↔застройщики (NEW 27.04 evening):** | View | Описание | |---|---| | `v_jk_with_developer` | ЖК Свердл + canonical dev_name + region_name (через FK `fk_kn_obj_developer/region`). 1 516 строк. | | `v_jk_sales_summary` | flats GROUP BY obj_name: total/sold/booked/free + sold_pct + avg_ppm + avg_area + total_value. Standalone-вид поквартирных снапшотов из `domrf_kn_flats`. | | `v_developer_portfolio` | Девелопер + все его корпуса/ЖК Свердл: count, flats_total, sqm + фильтры ekb/problem/escrow/completed/in_progress + earliest/latest ready_dt. | | `v_developer_full_metrics` | **⭐ ULTIMATE QUERY**: portfolio (ЖК) + квартирография (1к/2к/3к/4+) с процентами + realization Свердл sold%/цена. Лучший view для PRINZIP/Брусника/конкурентов сравнения. | ### 🔗 FK relationships **35 FK constraints** (после relations v2): - `domrf_snapshots`: 24 child FKs (все таблицы со snapshot_date) - `domrf_regions`: 5 (developer_aggregates, flat_area_distribution, region_aggregates, realization, kn_objects⭐, rent_deals⭐, territory_aliases) - `domrf_developers`: 3 (developer_aggregates, **kn_objects** ⭐ NEW, **sv_dev_sales** ⭐ NEW) - `domrf_federal_districts`: 1 (territory_aliases) **Цепочка анализа продаж:** ``` domrf_kn_flats (поквартирно) ─── obj_name ──→ domrf_kn_objects (ЖК) │ dev_id (FK) ▼ domrf_developers (справочник) │ developer_id (FK) ▼ domrf_realization (sold%/price 14 мес) │ │ region_code=66 ─→ domrf_regions ``` ⚠ **Известное ограничение**: `domrf_kn_flats.obj_id` НЕ имеет FK на `domrf_kn_objects.obj_id` — два API endpoint используют разные ID-системы (27 563/27 563 orphans, текстовый match по `obj_name`/`comm_name` тоже даёт только 2 совпадения). Поквартирные снапшоты обрабатываются standalone через `v_jk_sales_summary`. ### 📜 ETL artefacts (data/sql/) ``` 01_schema_rosreestr_deals.sql partitioned table + staging 02_load_all_quarters.sh \copy CSV (sep ~ и ;) 03_materialized_views.sql 3 MV для аналитики 10_schema_domrf.sql domrf_regions/developers/snapshots/aggregates 11_load_domrf.py JSON dashboard loader 20_schema_domrf_extras.sql XLSX/PDF schemas 21_load_domrf_extras.py XLSX/PDF loader 30_scrape_domrf.py Playwright headless Chromium с per-page direct API triggers 31_schema_domrf_full.sql launch/sold_ready/etc normalized 31_schema_domrf_raw.sql universal JSONB store 32_load_domrf_full.py normalize scraper output 32_load_domrf_raw.py JSONB raw store loader 33_schema_domrf_lazy.sql domrf_realization + xlsx_files (5 lazy pages) 34_load_domrf_lazy.py realization/xlsx/raw loader 35_schema_domrf_stats.sql stat_series_indicators + observations 36_parse_xlsx_stats.py parse 7 XLSX → 809K observations 37_cleanup_redundant.sql DROP sold_out_by_year/progress 38_relations_fix.sql +4 FK, миграция -1→0 RF, drop dup indexes, COMMENT'ы 39_territory_aliases.sql federal_districts + territory_aliases + v_stat_series_resolved 40_relations.sql оригинальные FK + 4 helper views (legacy) 40_scrape_history.py 14-month history scraper для realization+sold_ready 41_load_history.py loader с SNAPSHOT_DATE = end of period 42_schema_breakdown_widen.sql drop JSONB extra → 6 typed dimension columns 43_anton_import.sql 13 new tables for Anton's SQLite 44_import_anton_db.py sqlite3 → postgres migration 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) 50_schema_kn_extensions.sql UNIQUE (id, snapshot_date) для kn_flats/kn_objects + индексы (region_cd, snapshot_date) + kn_scrape_runs (журнал прогонов) 50_scrape_kn_flats.py CLI scraper для /сервисы/api/kn/object + portal/table; флаги --regions/--developers/--no-extras/--download-photos/--probe URL/--save-state/--load-state 51_schema_kn_extras.sql 4 extras-таблицы: sale_graph (time-series продаж), sales_agg (агрегаты), infrastructure (POI норм.), photos (мета+local_path) + kn_scrape_failures ``` Парсер живёт в `backend/app/services/scrapers/{stealth.py, domrf_kn.py}`, Celery-таск в `backend/app/workers/tasks/scrape_kn.py`, admin endpoint в `backend/app/api/v1/admin_scrape.py` (POST /kn + GET /runs + GET /failures с auth `X-Admin-Token`). UI ручного запуска: `frontend/src/app/admin/scrape/page.tsx`. ### 🎯 Аналитика — что делать с этими данными **Готовые отчёты в графе памяти:** - `Sverdl_Quartirography_Report_Apr27` — полный отчёт по квартирографии Свердл (что строится, что продаётся, тренды 14 мес, топ-15 девелоперов) - `PRINZIP_Strategy_Apr27` — стратегические рекомендации для PRINZIP (что строить, куда смотреть, BENCHMARK с Брусникой/Форум-групп) **Использование (паттерны):** ```sql -- Свердл realization timeseries за год SELECT TO_CHAR(snapshot_date,'YYYY-MM') AS p, 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; -- ЕКБ ДДУ-сделки по площадным сегментам SELECT CASE WHEN area<30 THEN 'studio' WHEN area<45 THEN '1k' ... END, COUNT(*), AVG(price_per_sqm) FROM rosreestr_deals WHERE region_code=66 AND city ILIKE '%катеринбург%' AND period_start_date >= '2025-04-01' AND doc_type='ДДУ'; -- Свердл stat_series (МКД 214-ФЗ, временной ряд) через resolved view SELECT obs_date, value FROM v_stat_series_resolved WHERE region_id=66 AND sheet_code='01_01_01'; -- Поквартирный прайс ЕКБ (Антон) SELECT obj_name, rooms, total_area, price_per_m2, status FROM domrf_kn_flats WHERE city='Город Екатеринбург' AND status='free'; -- Топ ЖК ЕКБ (Антон) SELECT comm_name, dev_name, flat_count, square_living, ready_dt FROM domrf_kn_objects WHERE is_ekb=true ORDER BY flat_count DESC; ``` --- ## Структура репозитория ``` gendesign/ ├── backend/ # Python 3.12 / FastAPI / PostGIS │ ├── pyproject.toml # uv-проект, ruff/mypy/pytest конфиги │ ├── Dockerfile # с системными deps под Geo + WeasyPrint │ ├── .env.example │ ├── app/ │ │ ├── main.py # FastAPI + Sentry + /health │ │ ├── core/ # config (Pydantic Settings), db (SQLAlchemy) │ │ ├── api/v1/ # concepts.py, parcels.py │ │ ├── schemas/ # Pydantic-контракты для openapi-typescript │ │ ├── services/ │ │ │ ├── generative/ # Stage 1: geometry, teap, financial │ │ │ ├── site_finder/ # Stage 2: parser, scorer, filters │ │ │ └── exporters/ # Stage 1c: pdf, excel, dxf │ │ ├── models/parcel.py # GeoAlchemy2 + PostGIS │ │ └── workers/celery_app.py # Stage 2a: daily PKK sync │ └── tests/ ├── frontend/ # Next.js 15 / React 19 / TypeScript / Leaflet │ ├── package.json # включая `npm run codegen` → openapi-typescript │ ├── Dockerfile # multi-stage, output: standalone │ ├── public/ # static assets (gitkeep пока пусто) │ └── src/app/ │ ├── page.tsx # / — главная │ ├── concept/page.tsx # /concept — Generative Design │ └── site-finder/page.tsx # /site-finder — Site Finder ├── memory/ │ └── memory-gendesign.jsonl # хард-линк на C:\mcp\.aim — общий граф памяти ├── docs/ # стратегические документы (бизнес-план, цели MVP) ├── ops/ # эксплуатация │ ├── backup.sh # pg_dump cron + опциональный S3 upload │ └── restore.sh # восстановление из дампа (RESTORE_CONFIRM=yes) ├── backend/ │ ├── alembic.ini, alembic/ # миграции БД (versions/ пуст до Stage 2a) │ └── db/init/ # init-скрипты, монтятся в /docker-entrypoint-initdb.d │ └── 99_drop_unused_extensions.sql # дроп TIGER/topology/fuzzystrmatch на свежем volume ├── .env.example # шаблон prod env (POSTGRES_*, IMAGE_TAG) ├── docker-compose.yml # dev: Postgres + Redis + backend + frontend ├── docker-compose.prod.yml # prod: образы из GHCR + Caddy + Postgres+Redis ├── Caddyfile # авто-TLS Let's Encrypt для gendsgn.ru ├── Makefile # make up / migrate / migration / test / codegen / pre-commit-install ├── .pre-commit-config.yaml # ruff + prettier + housekeeping hooks └── .github/workflows/ ├── ci.yml # ruff + mypy(core) + pytest + frontend build └── deploy.yml # build → push в GHCR → ssh: git fetch + reset --hard + caddy reload ``` --- ## Технический стек (v2.2) **Backend:** Python 3.12, FastAPI, SQLAlchemy 2.0, GeoAlchemy2, Pydantic v2, Alembic, Celery + Redis, httpx **Geo:** Shapely 2.0, GeoPandas, Pyproj (WGS84 ↔ МСК-66 для Свердловской обл.) **ML:** scikit-learn (XGBoost — отложен на Фазу 1, в Discovery эвристики) **БД:** PostgreSQL 16 + PostGIS 3.4, Redis 7 **Frontend:** Next.js 15, React 19, TypeScript 5, Tailwind 4, TanStack Query, Leaflet (Mapbox в Stage 2b), react-leaflet 5 **Экспорт:** WeasyPrint (PDF), ezdxf (DXF), openpyxl (Excel) **Dev:** uv (lockfile зафиксирован), ruff (lint+format), mypy (strict только на core), pytest, pre-commit (hooks: ruff, prettier, detect-private-key) --- ## Команда и порядок работы **2 фуллстек-разработчика, оба part-time 20 ч/нед** — итого ~40 person-hours/нед, эффективных с координацией ~33. **Ритм:** - 1 синк/нед (30 мин, понедельник) - daily-async в Telegram - PR review обязательный - Trunk-based: feature ветки ≤ 3 дней - Codegen TS-типов из Pydantic (`npm run codegen`) — без этого 2 фуллстека плодят расхождения в API-контракте --- ## Этапы MVP (12 недель, базовый план) ### 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` до Раунда А). Production VPS поднят, GHCR-деплой работает. ### Stage 1 — Generative MVP (нед. 2–7) ⏸ pending решения по Plan A - **1a (нед. 2–3):** геометрия + API-контракт. Shapely-сервис (отступы, сетка), Pydantic-схемы, `POST /api/v1/concepts` с заглушкой. Фронт: страница `/concept`, Leaflet, импорт GeoJSON, форма параметров, 3 варианта в табах. - **1b (нед. 4–5):** алгоритм размещения. Жадное заполнение, 3 стратегии (max площадь / max инсоляция / balanced), STRtree для коллизий. Цель ≤10 сек, fallback 15 сек. - **1c (нед. 6–7):** ТЭП + финмодель + экспорты. WeasyPrint PDF, ezdxf, openpyxl. UI кнопок скачивания. **Acceptance Stage 1 (конец нед. 7):** полигон → 3 варианта → ТЭП + финмодель → PDF/Excel/DXF. ### Stage 2 — Site Finder MVP (нед. 8–12) - **2a (нед. 8–9):** data pipeline. Парсер ПКК Rosreestr (httpx async, retries), модель `Parcel` с GeoAlchemy2, ≥1000 участков Екатеринбурга. Overpass API для POI, ДОМ.РФ/ЦИАН для цен м², кеш в Redis. Опционально: воркер `sales_tracker.py` — ежесуточный мониторинг шахматок застройщиков (Velocity Score). - **2b (нед. 10–11):** скоринг + API + UI. 3 критерия (расстояние до центра, плотность POI в 1 км, цена района), `POST /api/v1/parcels/search`. Карта с градацией по рейтингу, фильтры, карточка. - **2c (нед. 12):** интеграция + полировка. Кнопка «Обсчитать концепцию», демо-наполнение 50 участков, бэкапы БД, подача в реестр ПО. ### Альтернативный план A (Analytics First) Если Антон в понедельник подтвердит легальный канал ДДУ-данных — Stage 1 переезжает на **«3 плитки» аналитики** (что строить / по какой цене / за какое время), Generative переходит на Stage 2 со Smart Defaults на основе аналитики, Site Finder — на Stage 3 с Velocity Score из ДДУ. См. `PlanA_AnalyticsFirst_Apr25` в графе. ### Что урезано из v2.2 из-за part-time × 2 - XGBoost-скоринг → Фаза 1 (с реальными данными от пилотов) - JWT-auth с refresh → перед Раундом А - mypy --strict — только на core (`generative/*`, `site_finder/scorer.py`) - Время генерации ≤ 15 сек как fallback (а не 10 сек) --- ## Quick start (локально) **Требования:** Docker Desktop, Node.js 20+, [uv](https://docs.astral.sh/uv/) (для backend dev вне Docker). ```bash # 1. Скопировать env-файлы cp backend/.env.example backend/.env cp frontend/.env.example frontend/.env cp .env.example .env # опционально, для prod compose # 2. Запустить всё docker compose up -d --build # или: make up # 3. Проверить curl http://localhost:8000/health # → {"status":"ok","environment":"dev"} # Frontend → http://localhost:3000 # Swagger docs → http://localhost:8000/docs ``` **Полезное:** ```bash make logs # tail логов всех сервисов make backend-shell # bash внутри backend контейнера make migrate # alembic upgrade head (когда добавим миграции) make test # pytest make lint # ruff check make typecheck # mypy на core make codegen # обновить TS-типы из OpenAPI ``` --- ## Production хостинг — Beget VPS **Текущая live-конфигурация:** Beget Cloud, Москва, Standard 3+ GHz, 2 vCPU / 4 GB / 40 GB NVMe. **Стоимость:** ~33 ₽/день сервер + ~5 ₽/день IPv4 = **~1140 ₽/мес**. Плюс домен .ru (~17 ₽/мес). **Что крутится на VM** (`/opt/gendesign`): - 5 контейнеров через `docker-compose.prod.yml`: postgres, redis, backend, frontend, caddy - Backend и frontend образы пуллятся из приватного GHCR - Persistent volumes: `gendesign_postgres_data`, `gendesign_redis_data`, `gendesign_caddy_*` - Backend и frontend биндятся на `127.0.0.1:8000` и `127.0.0.1:3000` — наружу выходит только Caddy на `:80`/`:443` **Доступ:** SSH-only по ключу к non-root пользователю `gendesign`. Root login отключён, password auth отключён, fail2ban Beget активен. ### Триггеры миграции на Yandex Cloud Переезжаем на YC Managed PostgreSQL + Compute + Container Registry, когда: - Подписан 3-й платящий пилот (~ конец мес. 3) - Закрылся Раунд А - Идёт переговор с госзаказчиком (нужен реестр ПО + солидная инфра) - БД > 10 GB или появилось > 50 RPS Стоимость production на YC: ~10–15 тыс ₽/мес. ### Что осталось до «infra-ready» - [x] ~~Купить домен~~ — `gendsgn.ru` зарегистрирован в Beget 26.04.2026 (199₽/420₽). DNS на NS Beget, A-записи прописаны - [x] ~~ЕСИА-верификация админа домена~~ — пройдено 26.04, статус `REGISTERED, DELEGATED, VERIFIED` - [x] ~~Caddy TLS на `gendsgn.ru`~~ — Let's Encrypt cert получен, HTTPS живёт - [x] ~~Sentry DSN~~ — проект `gendesign-backend` создан в org `qqq`, DSN в `/opt/gendesign/backend/.env`, тестовое событие прошло - [x] ~~GitHub Issues / Milestones / Labels~~ — backlog засеян (см. [Issues](https://github.com/lekss361/-gendesign/issues)) - [ ] Настроить ежесуточный `pg_dump` → Object Storage. Скрипт `ops/backup.sh` готов, осталось создать Selectel/Yandex bucket и положить креды в `/etc/default/gendesign-backup` на VM ([#3](https://github.com/lekss361/-gendesign/issues/3)) - [ ] Прокинуть `SENTRY_RELEASE` в deploy.yml для tracking релизов в Sentry ([#4](https://github.com/lekss361/-gendesign/issues/4)) - [ ] Подключить Антона к knowledge-graph ([#11](https://github.com/lekss361/-gendesign/issues/11)) - [ ] При следующем wipe `down -v` — TIGER/topology/fuzzystrmatch автоматом дропнутся (init-скрипт `backend/db/init/99_drop_unused_extensions.sql`) ### Sensitive операционные грабли - **`docker compose restart` НЕ перечитывает `env_file:`** — после правки `backend/.env` всегда `docker compose -f docker-compose.prod.yml up -d --force-recreate --no-deps backend` - **`deploy.yml` использует `git reset --hard origin/main`** — любые ручные правки в `/opt/gendesign` будут стёрты при следующем деплое. `.env` файлы переживут (в `.gitignore`) - **`docker compose up` без `-f docker-compose.prod.yml`** на проде поднимет dev compose (с локальной сборкой образов и без Caddy). Признаки: `Image ... Built` в выводе и WARN про orphan caddy. Всегда указывай `-f` - **`caddy reload` не сбрасывает retry-queue.** Если Caddy пытался получить cert для несуществующего hostname (например, плейсхолдера из старого Caddyfile), фоновые попытки могут переключить его в Let's Encrypt staging fallback. Рецепт чистого старта: `docker volume rm gendesign_caddy_data && docker compose up -d caddy` --- ## GitHub Actions deploy Workflow `.github/workflows/deploy.yml`: 1. **Build** обоих Docker-образов (backend ~2.5 мин с нуля, frontend ~1 мин с нуля; повторно из кеша — секунды) 2. **Push** в GHCR (`ghcr.io/lekss361/gendesign-backend`, `gendesign-frontend`) с тегами `latest` и `` 3. **SSH deploy:** `docker compose -f docker-compose.prod.yml pull && up -d`, потом `curl /health` **GitHub Secrets (Settings → Secrets and variables → Actions):** | Имя | Значение | |---|---| | `DEPLOY_HOST` | `46.173.16.127` | | `DEPLOY_USER` | `gendesign` | | `DEPLOY_SSH_KEY` | приватный ключ `~/.ssh/gendesign_deploy` целиком | | `DEPLOY_PORT` | `22` (или другой, если поменяли) | `GITHUB_TOKEN` встроенный — отдельный secret для push в GHCR не нужен. **Авторизация сервера в GHCR (приватные пакеты):** Сервер авторизуется однократно через PAT с `read:packages`: ```bash # На сервере, как пользователь gendesign read -s GHCR_PAT && echo "$GHCR_PAT" | docker login ghcr.io -u lekss361 --password-stdin && unset GHCR_PAT ``` Auth сохраняется в `~/.docker/config.json` и переживает рестарт. Ротировать PAT раз в год. --- ## Память проекта (knowledge graph) Все решения, факты, риски, KPI, протоколы валидации хранятся **только в графе памяти**, не в .md-документах. Это решает проблему расхождения версий между документами. **Как устроено:** - MCP-сервер `mcp-knowledge-graph` пишет в `C:\mcp\.aim\memory-gendesign.jsonl` - Этот файл — **хард-линк** на `/memory/memory-gendesign.jsonl` - Изменения попадают в git автоматически - Синхронизация между коллегами — через `git pull` / `git push` **Правило проекта (`Feedback_MemoryFirst`):** - Все факты и решения сохраняем в граф (`context: "gendesign"`) - `.md` / `.docx` / `.pdf` Claude **не создаёт сам** — только по явному запросу - Источник правды = граф, документы = производные срезы **Рабочий цикл:** ```bash git pull # перед началом работы # ... сессия с Claude ... git add memory/memory-gendesign.jsonl git commit -m "Memory: <что добавили>" git push ``` Конфликты в `.jsonl` обычно простые (файл построчный): `git pull --rebase`, оставить **обе** стороны, `git rebase --continue`. ### Подключение коллеги Краткая инструкция для нового участника команды: 1. Установить Claude Desktop, Node.js 20+, Git 2. Клонировать репо в `C:\Users\<имя>\source\repos\gendesign` 3. `mkdir C:\mcp\.aim` 4. Создать хард-линк: ```powershell New-Item -ItemType HardLink ` -Path C:\mcp\.aim\memory-gendesign.jsonl ` -Value $PWD\memory\memory-gendesign.jsonl ``` 5. Добавить в `%APPDATA%\Claude\claude_desktop_config.json`: ```json "knowledge-graph": { "command": "npx", "args": ["-y", "mcp-knowledge-graph", "--memory-path", "C:\\mcp\\.aim"] } ``` 6. Перезапустить Claude Desktop полностью (через трей) 7. Проверить: «Покажи память контекста gendesign» Полная версия процедуры — в графе, сущность `Onboarding_Colleague_KG`. --- ## Документы стратегии В `docs/`: - `MVP_Goals_Python.md` — цели Discovery MVP, Python-стек (v2.2, апрель 2026) - `Бизнес-план v2.1 - Site Finder + Roadmap 12 месяцев.md` — бизнес-план ⚠️ Эти документы — **снимок состояния на момент написания**. Свежее состояние стратегии — в графе памяти. При расхождении доверяем графу. Релевантные сущности графа на 27.04.2026: **Аналитика и отчёты (27.04):** - `DomRF_Lazy_Loaded_Apr27_2026` ⭐ — итог дня: 5 lazy-load страниц + stat_series + cleanup + territory aliases + MCP - `DomRF_History_Loaded_Apr27_2026` ⭐ — 14 месяцев истории realization+sold_ready (143K рядов realization) - `Anton_Imported_Apr27_2026` ⭐ — 13 таблиц от Антона + merge developers (8 629 итого) - `Sverdl_Quartirography_Report_Apr27` 📊 — полный отчёт по Свердл квартирографии - `PRINZIP_Strategy_Apr27` 📊 — стратегия PRINZIP: что строить и куда смотреть - `Analytics_Dashboard_Apr27` ⭐ — 3 страницы /analytics с ECharts (Свердл рынок, PRINZIP drill-down, девелоперы) - `DomRf_Kn_Scraper_Apr27` ⭐ — парсер DOM.РФ kn-API + 4 extras-эндпойнта (sale_graph, sales_agg, infrastructure, photos), Playwright in-context fetch, Celery beat cron + admin trigger UI Сущности 26.04.2026: **Стратегия / план:** - `Project_GenDesign` — общая шапка - `TechStack_v2.2` — Python + Next.js стек - `NorthStar_DiscoveryMVP` — 3 пилота + реестр ПО → Раунд А - `Stages_MVP_v1` — базовая разбивка по этапам - `Team_Setup` — 2 фуллстека part-time - `WorkSplit_Generative_Stage1` — кто что делает в Generative - `PlanA_AnalyticsFirst_Apr25` — pending pivot решение (ждём 27.04 — Антон по ДДУ) - `SalesTracking_Strategy_Apr25` — шахматки застройщиков (downgrade-нуты после находок 26.04) - `DataSources_Pricing_Apr25` — источники цен и площадей (общий обзор) - `DataSources_Analysis_Apr26` — глубокий анализ ДОМ.РФ как ground truth (заменяет ожидание ДДУ-канала) - `Validation_Findings_Apr25` — валидация бизнес-плана **Источники данных (обновлено 26.04 вечер):** - `DataSource_Rosreestr_DealsCSV_Apr26` ⭐ — per-deal цены сделок ДКП+ДДУ из ФГИС ЕГРН, 9 кварталов 2024–Q1 2026, ~898К сделок РФ/квартал - `DataSource_Rosreestr_DealsCSV_Schema_Apr26` — схема CSV (разделитель `~`, 17 полей) - `DataSource_Rosreestr_DealsCSV_Sverdl_Q1_2026` — реальные цифры по Свердл.обл (ДКП median 82,594 ₽/м², ДДУ median 156,314 ₽/м²) - `DataSource_Rosreestr_DealsCSV_Limits_Apr26` — ограничения (нет покупателя, period=начало квартала) - `DataSource_Rosreestr_ETL_Plan_Apr26` — план интеграции в Stage 2a - `DataSource_PerDeal_Reality_Apr26` — иерархия источников (1. Росреестр CSV → 2. ДОМ.РФ → 3. ЦБ ипотека → 4. Fedstat → 5. УПН Екб) - `DataSource_UPN_Ekb_Apr26` — Уральская Палата Недвижимости (19 лет longitudinal по Екб) **ДОМ.РФ фронт-API (по вкладкам):** - `DomRF_Architecture_Apr26` · `DomRF_Host_Apr26` · `DomRF_API_PortalAnalytics_Apr26` · `DomRF_KeyAndLegal_Apr26` (ключ Basic MTpqd2U=) - `DomRF_PlanA_Mapping_Apr26` — маппинг endpoints на 3 плитки Plan A - 12 вкладок аналитики: `DomRF_Tab1_HousingIndicators_Apr26` ... `DomRF_Tab11_MortgageStats_Apr26` - `DomRF_Spec_APF_v22` — официальный B2B API (только для банков) - `DomRF_OfficialVsFront_Comparison_Apr26` — почему фронт незаменим даже с банк-партнёром **НСПД (nspd.gov.ru, новый портал Росреестра):** - `Rosreestr_SiteMap_Apr26` — карта ресурсов Росреестра/НСПД - `NSPD_Architecture_Apr26` — React SPA, micro-frontends, OAuth через ESIA - `NSPD_OAuth_Architecture_Apr26` — auth flow, JWT TTL=30 мин - `NSPD_PhysicAccess_Apr26` — что доступно физик-аккаунту (18 сервисов, marketAnalytics ✓) - `NSPD_MarketAnalytics_FullArchitecture_Apr26` ⭐ — полный API-флоу разобран в debug-браузере 26.04: saveUserFilters → graphEgrn*, tableEgrn, geomDataForHeatMap. Серверная сессия фильтров (userFiltersId) - `NSPD_OrgOnly_Endpoints_Apr26` — graphEgrnCandleMedian/LineMedian возвращают 403 (абсолютные ₽/м² скрыты от physic, дублируют CSV-датасет) - `NSPD_DataValue_For_GenDesign_Apr26` — value: 8 лет longitudinal, гранулярность до кадастрового квартала, GeoJSON-полигоны для heatmap - `NSPD_AEGGIS_WMTS_Apr26` — WMTS-тайлы для embed в Mapbox/Leaflet - `NSPD_PII_Leak_Apr26` · `Rosreestr_Recon_Findings_Apr26` · `Rosreestr_TLS_Note_Apr26` — security/инфра наблюдения **Инфраструктура:** - `Hosting_Pricing_Apr25` — сравнение провайдеров - `Hosting_Decision_Apr25` — решение по Yandex Cloud (для будущей миграции) - `Runbook_VPS_Setup_Beget` — пошаговая настройка production VM - `SSH_Setup_Apr25` — локальная настройка SSH - `DockerOps_Apr26` — multi-stage Dockerfile, npm ci, healthcheck fix, same-origin API - `Production_Wipe_Apr26` — clean re-deploy с нуля (event) - `Domain_Setup_Apr26` — gendsgn.ru, Beget, DNS, ESIA-правило - `Sentry_Setup_Apr26` — проект, DSN, тестовое событие - `OpsBundle_Apr26` — Alembic + TIGER cleanup + pre-commit + pg_dump - `HTTPS_Live_Apr26` — milestone: HTTPS прод заработал (включая lessons learned по ACME retry-state) **Процесс / правила:** - `Onboarding_Colleague_KG` — подключение нового участника к графу - `Feedback_MemoryFirst` — правило: память first, docs только по запросу --- ## Полезные ссылки - **🌐 Production:** https://gendsgn.ru/ - **🩺 Health:** https://gendsgn.ru/health - **📚 OpenAPI:** https://gendsgn.ru/openapi.json · [Swagger UI](https://gendsgn.ru/docs) - **Репо:** https://github.com/lekss361/-gendesign - **Issues backlog:** https://github.com/lekss361/-gendesign/issues - **Milestones:** https://github.com/lekss361/-gendesign/milestones - **GitHub Actions:** https://github.com/lekss361/-gendesign/actions - **GHCR пакеты:** https://github.com/lekss361?tab=packages - **Sentry:** https://qqq-5y.sentry.io/insights/projects/gendesign-backend/ - **Production VPS:** Beget Cloud → `cp.beget.com/cloud/servers/jolly-yakov-3` - **DNS-панель домена:** https://cp.beget.com/dns/14193206 - **Целевой регион Discovery:** Свердловская обл. (Екатеринбург, ПЗЗ, МСК-66) - **Конкуренты:** rTIM (только концепт-стадия, нет site-selection), TestFit (нет РФ-данных)