From bb28f77f665c2443271aeb5cc275e70293896b61 Mon Sep 17 00:00:00 2001 From: lekss361 Date: Thu, 30 Apr 2026 23:04:19 +0300 Subject: [PATCH] fix+chore: NSPD migration applied to prod, README trim, analytics backlog +5 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Применена миграция 63_schema_nspd_runs.sql вручную через MCP (тянут init-скрипты только при первичной инициализации БД). Чинит 500 на /api/v1/admin/scrape/nspd/{runs,logs,coverage}. - README: 724→148 строк. Выкинута операционная история апреля, 443-sweep инструкции (теперь через admin UI), таблица 43 таблиц (есть в графе памяти), step-by-step onboarding (есть в #11). - 5 новых issues по аналитике: #17 velocity-anomaly, #18 ekb_districts median refresh (bug), #19 competitor-360, #20 mortgage-rate sensitivity, #21 cad_buildings фильтры в Site Finder. - Закрыт #4 (Sentry release tracking — реализовано в 25b7303). --- README.md | 752 +++++++----------------------------------------------- 1 file changed, 88 insertions(+), 664 deletions(-) diff --git a/README.md b/README.md index 121b5618..ea4bfc6b 100644 --- a/README.md +++ b/README.md @@ -1,724 +1,148 @@ # Generative Design + Site Finder -Две продуктовые линии в одной воронке: **Site Finder** (AI-подбор инвестиционных земельных участков) + **Generative Design** (автоматическая генерация концепций застройки) для девелоперов РФ. +Две продуктовые линии в одной воронке: **Site Finder** (AI-подбор инвестиционных земельных участков) + **Generative Design** (автоматическая генерация концепций застройки) для девелоперов РФ. Целевой регион Discovery — Свердловская обл. (ЕКБ, ПЗЗ, МСК-66). ## North Star К концу месяца 3: **3 платящих пилота** (≥30 тыс. ₽/мес каждый) + заявка в реестр российского ПО → право на Раунд А (20–25 млн ₽). -Acceptance criteria разбиты на 3 блока (функционально / бизнесово / технически). Правило перехода: 3/3 → Раунд А; 2/3 → продление Фазы 0 на 1–2 мес.; 1/3 или меньше → стоп проекта. - --- -## Текущий статус (27 апреля 2026) +## Текущий статус (апрель 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. +**Live:** [https://gendsgn.ru/](https://gendsgn.ru/) — HTTP/2+HTTP/3, валидный TLS, [/health](https://gendsgn.ru/health) `{"status":"ok"}`. Полный CI/CD: GitHub Actions → GHCR → SSH-deploy на Beget VPS. Sentry активен (release tracking привязан к git-sha). -| Что | Где | Статус | -|---|---|---| -| **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 для ручной проверки в браузере + раздел «Очередь и активные» через Celery inspect). -- **Stealth** — Playwright fingerprint снят с локальной машины в `data/playwright_state.json` (26 cookies, ServicePipe NSC + Keycloak), закоммичен в git для server-reuse без cold-bootstrap. - -### Запуск 442-sweep (все строящиеся ЖК Свердл) - -После того как PRINZIP-probe прошёл (28 ЖК), масштабируем на все 442 строящихся: - -**Через UI** (рекомендуется): -1. Открыть https://gendsgn.ru/admin/scrape, ввести `SCRAPE_ADMIN_TOKEN`. -2. Регион: 66, Девелоперы: пусто (все), чекбоксы: ✅ Квартиры, ✅ Extras, ❌ Скачать фото. -3. «Запустить сейчас» → таск уйдёт в Redis-очередь, worker подхватит. Прогон ~60 минут. - -**Через CLI на VPS** (если worker оффлайн): -```bash -ssh gendesign 'cd /opt/gendesign && \ - docker compose -f docker-compose.prod.yml run --rm worker \ - python data/sql/50_scrape_kn_flats.py --regions 66 \ - --load-state data/playwright_state.json -v' -``` - -**Sanity-чеки после прогона:** -```sql -SELECT obj_status, COUNT(*) FROM domrf_kn_objects - WHERE region_cd=66 AND snapshot_date=CURRENT_DATE GROUP BY 1; --- Ожидаем obj_status=0 (строящиеся): ~442 - -SELECT COUNT(DISTINCT obj_id) FROM domrf_kn_sale_graph - WHERE snapshot_date=CURRENT_DATE; --- Ожидаем 100-200 ЖК с активными продажами - -SELECT poi_category, COUNT(*) FROM domrf_kn_infrastructure - WHERE snapshot_date=CURRENT_DATE GROUP BY 1 ORDER BY 2 DESC; --- Ожидаем ~85 000 POI (442 ЖК × ~190 POI на ЖК) -``` - -**Возможные проблемы:** -- WAF cookie expire — обновить `data/playwright_state.json` через `python data/sql/50_scrape_kn_flats.py --regions 66 --bootstrap-only --save-state data/playwright_state.json` локально, закоммитить, redeploy. -- Rate-limit (429) — повысить `SCRAPE_KN_JITTER_SECONDS` в env или поправить `jitter_sleep(min_ms, max_ms)` в `stealth.py`. - ---- - -## Аналитический пласт данных (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-туннеля | +| Аналитический калькулятор `/analytics/recommend` (Tier 3 per-bucket эластичность, кадастр vs рынок) | ✅ | +| DOM.РФ kn-API скрейпер (442 строящихся ЖК Свердл, sale_graph + infra + photos) | ✅ Celery beat + admin UI | +| Rosreestr CSV-сделки 2024Q1—2026Q1 (9 квартирных партиций, 7M строк) | ✅ | +| NSPD кадастровые кварталы + здания (709 cad-кварталов, 10 590 cad_buildings ЕКБ) | ✅ Celery beat + admin UI | +| OSM ekb_districts_geom (PostGIS-полигоны 8 районов ЕКБ) | ✅ | +| Concept page (`/concept`) — Stage 1 Generative | 🟡 skeleton | +| Site Finder (`/site-finder`) — Stage 2 | 🔴 заглушка | -⚠️ Туннель уже открыт на машинах команды (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 для сданных ЖК = ожидаемо) | - -**PRINZIP CRM (analytics.prinzipevent.ru)** -| Таблица | Рядов | Описание | -|---|---:|---| -| `prinzip_leads` ⭐ | до 102 000 | заявки 8 лет. PII (phone/email) хешированы. Импорт через `data/sql/52_import_prinzip_crm.py --sqlite data/raw/prinzip_crm.sqlite` | -| `prinzip_deals` ⭐ | до 9 000 | сделки 8 лет, sum revenue ≈ 39.9 млрд ₽. FK к `prinzip_leads` и soft-FK к `domrf_kn_objects` | -| `prinzip_funnel_monthly` ⭐ | MV | воронка по месяцам × source (REFRESH после импорта) | -| `prinzip_funnel_by_object` ⭐ | MV | conversion per ЖК: leads → deals → revenue | - -**ЦБ РФ ипотека (от Антона)** -| Таблица | Рядов | Описание | -|---|---:|---| -| `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 -52_schema_prinzip_crm.sql prinzip_leads (102K) + prinzip_deals (9K) + 2 materialized views (funnel_monthly, funnel_by_object). PII-hashing -52_import_prinzip_crm.py SQLite → Postgres importer. Use --inspect-only для discovery колонок, потом правь LEAD_FIELD_MAP/DEAL_FIELD_MAP -``` - -Парсер живёт в `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 + GET /queue + POST /revoke с auth `X-Admin-Token`). UI ручного запуска: `frontend/src/app/admin/scrape/page.tsx`. Per-объект drill-in: `/analytics/objects/[id]` (галерея фото + POI-таблица + sale-chart) + `PrinzipObjectsTable` с sparkline на `/analytics/prinzip`. - -### 🎯 Аналитика — что делать с этими данными - -**Готовые отчёты в графе памяти:** -- `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 сек) +**Подробности и текущий backlog** — [Issues](https://github.com/lekss361/-gendesign/issues), milestones по этапам. --- ## Quick start (локально) -**Требования:** Docker Desktop, Node.js 20+, [uv](https://docs.astral.sh/uv/) (для backend dev вне Docker). +**Требования:** Docker Desktop, Node.js 20+, [uv](https://docs.astral.sh/uv/) для backend dev. ```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 +curl http://localhost:8000/health # → {"status":"ok","environment":"dev"} +# Frontend: http://localhost:3000 +# Swagger: 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 +Полезные `make`-таргеты: `logs`, `backend-shell`, `migrate`, `test`, `lint`, `typecheck`, `codegen` (TS-типы из OpenAPI). + +--- + +## Архитектура + +**Backend:** Python 3.12, FastAPI, SQLAlchemy 2.0, GeoAlchemy2, Pydantic v2, Celery + Redis, httpx, Shapely 2, scikit-learn. +**БД:** PostgreSQL 16 + PostGIS 3.4 (партиционированные `rosreestr_deals`, GIST на geom-полях, ~50 предметных таблиц). +**Frontend:** Next.js 15, React 19, TypeScript 5, Tailwind 4, TanStack Query, Leaflet/Mapbox, ECharts. +**Экспорт:** WeasyPrint (PDF), ezdxf (DXF), openpyxl (Excel). +**Dev:** uv lockfile, ruff, mypy strict (на `core` + `generative`), pytest, pre-commit hooks. + +Структура монорепо: +``` +backend/ FastAPI app, services (analytics_queries, scrapers, generative, site_finder), workers (Celery) +frontend/ Next.js app router (analytics, admin, concept, site-finder) +data/sql/ ETL артефакты — миграции схемы, загрузчики rosreestr/anton/nspd +ops/ backup.sh + deploy скрипты +docs/ стратегия (снимок) — актуальное состояние в графе памяти +memory/ hardlink на C:\mcp\.aim\memory-gendesign.jsonl (knowledge graph) +.github/workflows/ deploy.yml (build → GHCR → SSH-deploy) ``` --- -## Production хостинг — Beget VPS +## Аналитика — что доступно -**Текущая live-конфигурация:** Beget Cloud, Москва, Standard 3+ GHz, 2 vCPU / 4 GB / 40 GB NVMe. +В прод-БД ~50 предметных таблиц: -**Стоимость:** ~33 ₽/день сервер + ~5 ₽/день IPv4 = **~1140 ₽/мес**. Плюс домен .ru (~17 ₽/мес). +- **`domrf_kn_*`** — DOM.РФ объекты, квартиры, sale_graph, infrastructure, photos (1500+ ЖК Свердл). +- **`rosreestr_deals`** — партиционированные ДДУ/ДКП-сделки 2024Q1—2026Q1, ~7M строк, 27 мес истории. +- **`cad_quarters_geom` + `cad_buildings`** — NSPD кадастровые кварталы и здания (cost_value, year_built, floors, geom). +- **`ekb_districts_geom`** — PostGIS-полигоны OSM для spatial-join. +- **`cbr_mortgage_series`, `yandex_realty_zk`, `domrf_realization`, `sber_ddf_metrics`** — макро/cross-validation. -**Что крутится на 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` +**Калькулятор `/analytics/recommend`** считает квартирографию (5 size-бакетов) с per-bucket эластичностью через регрессию sale_graph, нормировкой на район/класс/конкурентов, кадастр-vs-рынок cross-check, и инверсным режимом «требуемая цена для срока X мес». -**Доступ:** 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` +Подробное описание схемы БД, helper-views, FK и 27.04 history — в графе памяти, сущности `Analytics_Dashboard_Apr27`, `DomRF_Lazy_Loaded_Apr27_2026`, `Anton_Imported_Apr27_2026`, `NSPD_Scrape_Complete_Apr30`. См. также `data/sql/*.sql` (DDL артефакты). --- -## GitHub Actions deploy +## Production хостинг -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` +**Beget Cloud, Москва, 2 vCPU / 4 GB / 40 GB NVMe.** Стоимость ~1 140 ₽/мес сервер + ~17 ₽/мес домен. -**GitHub Secrets (Settings → Secrets and variables → Actions):** +5 контейнеров через `docker-compose.prod.yml`: `postgres` + `redis` + `backend` (FastAPI) + `worker` + `beat` (Celery, Chromium только в worker) + `frontend` + `caddy` (auto-TLS Let's Encrypt). Backend/frontend bind на `127.0.0.1` — наружу только Caddy. -| Имя | Значение | -|---|---| -| `DEPLOY_HOST` | `46.173.16.127` | -| `DEPLOY_USER` | `gendesign` | -| `DEPLOY_SSH_KEY` | приватный ключ `~/.ssh/gendesign_deploy` целиком | -| `DEPLOY_PORT` | `22` (или другой, если поменяли) | +**SSH-only по ключу к non-root пользователю `gendesign`**, fail2ban активен. UFW: 22/80/443. -`GITHUB_TOKEN` встроенный — отдельный secret для push в GHCR не нужен. +**GitHub Actions deploy** ([`.github/workflows/deploy.yml`](.github/workflows/deploy.yml)): +1. Build обоих образов (backend lean + worker-with-chromium + frontend) +2. Push в приватный GHCR +3. SSH `git pull`, пишет `SENTRY_RELEASE=$IMAGE_TAG` в `backend/.env.runtime`, `compose pull && up -d`, `caddy reload`, `curl /health` -**Авторизация сервера в GHCR (приватные пакеты):** +**GitHub Secrets:** `DEPLOY_HOST`, `DEPLOY_USER`, `DEPLOY_SSH_KEY`, `DEPLOY_PORT`. Сервер авторизуется в GHCR однократно через PAT с `read:packages`. -Сервер авторизуется однократно через PAT с `read:packages`: +**Триггеры миграции на Yandex Cloud:** 3-й платящий пилот / Раунд А / госзаказ (нужен реестр ПО) / БД >10 GB / >50 RPS. На YC ~10–15 тыс ₽/мес. -```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 раз в год. +- `docker compose restart` НЕ перечитывает `env_file:` — после правки `.env` всегда `up -d --force-recreate --no-deps backend`. +- `deploy.yml` использует `git reset --hard origin/main` — ручные правки в `/opt/gendesign` будут стёрты при следующем деплое (`.env`-файлы переживут — в `.gitignore`). +- На проде всегда указывать `-f docker-compose.prod.yml` (без него поднимет dev compose без Caddy). +- `caddy reload` не сбрасывает retry-queue для ACME. При смене hostname с битым cert-state: `docker volume rm gendesign_caddy_data && up -d caddy`. --- -## Память проекта (knowledge graph) +## Roadmap (12 недель) -Все решения, факты, риски, KPI, протоколы валидации хранятся **только в графе памяти**, не в .md-документах. Это решает проблему расхождения версий между документами. +| Stage | Сроки | Что | Acceptance | +|---|---|---|---| +| **0** ✅ | нед. 1 | Скелет монорепо, CI, прод | curl /health = ok | +| **Sprint 1** ✅ | конец апр 2026 | NSPD-скрейпер + per-bucket эластичность + кадастр cross-check + Sentry release tracking | recommend_mix Tier 3 в проде | +| **1a** | нед. 2–3 | Shapely-сервис, отступы, API-контракт `/concept` ([#5](https://github.com/lekss361/-gendesign/issues/5)) | GeoJSON → 3 заглушки | +| **1b** | нед. 4–5 | Greedy-алгоритм, 3 стратегии, STRtree ([#12](https://github.com/lekss361/-gendesign/issues/12)) | 3 варианта ≤15с на 1 га | +| **1c** | нед. 6–7 | ТЭП + финмодель + PDF/Excel/DXF ([#6](https://github.com/lekss361/-gendesign/issues/6)) | Продаваемый артефакт | +| **2a** | нед. 8–9 | ПКК-парсер + sales_tracker ([#7](https://github.com/lekss361/-gendesign/issues/7)) | ≥1000 участков ЕКБ | +| **2b** | нед. 10–11 | Скоринг + API + UI Site Finder ([#8](https://github.com/lekss361/-gendesign/issues/8)) | Карта с цветовой градацией | +| **2c** | нед. 12 | Site Finder ↔ Generative + реестр ПО ([#9](https://github.com/lekss361/-gendesign/issues/9)) | 3 платящих пилота | -**Как устроено:** -- 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`. +Аналитический backlog: [#17](https://github.com/lekss361/-gendesign/issues/17) velocity-anomaly, [#18](https://github.com/lekss361/-gendesign/issues/18) ekb_districts median refresh, [#19](https://github.com/lekss361/-gendesign/issues/19) competitor-360, [#20](https://github.com/lekss361/-gendesign/issues/20) mortgage-rate sensitivity, [#21](https://github.com/lekss361/-gendesign/issues/21) cad_buildings filters в Site Finder. --- -## Документы стратегии +## Команда и память проекта -В `docs/`: -- `MVP_Goals_Python.md` — цели Discovery MVP, Python-стек (v2.2, апрель 2026) -- `Бизнес-план v2.1 - Site Finder + Roadmap 12 месяцев.md` — бизнес-план +**2 фуллстек-разработчика, part-time 20 ч/нед**, ритм: 1 синк/нед, daily-async в Telegram, PR-review обязательный, trunk-based. Codegen TS-типов из Pydantic — `npm run codegen`. -⚠️ Эти документы — **снимок состояния на момент написания**. Свежее состояние стратегии — в графе памяти. При расхождении доверяем графу. +Все решения, факты, KPI, протоколы валидации хранятся в **графе памяти** (`memory/memory-gendesign.jsonl`, hardlink на `C:\mcp\.aim\memory-gendesign.jsonl`), не в .md-документах. Правило (`Feedback_MemoryFirst`): источник правды = граф, документы = снимки. Синхронизация между коллегами — через git pull/push. -Релевантные сущности графа на 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 только по запросу +**Подключение коллеги к knowledge-graph** ([#11](https://github.com/lekss361/-gendesign/issues/11)) — пошаговая инструкция в issue. --- ## Полезные ссылки -- **🌐 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 (нет РФ-данных) +| | | +|---|---| +| 🌐 Production | https://gendsgn.ru/ | +| 🩺 Health | https://gendsgn.ru/health | +| 📚 OpenAPI | https://gendsgn.ru/openapi.json · [Swagger UI](https://gendsgn.ru/docs) | +| Backlog | [Issues](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/) | +| Инфра | Beget VPS [`cp.beget.com/cloud/...`](https://cp.beget.com/cloud/servers/jolly-yakov-3) · [DNS](https://cp.beget.com/dns/14193206) | + +**Стратегические документы (снимки):** [`docs/MVP_Goals_Python.md`](docs/MVP_Goals_Python.md), [`docs/Бизнес-план v2.1 - Site Finder + Roadmap 12 месяцев.md`](docs/). При расхождении с графом — доверяем графу.