gendesign/README.md

326 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Generative Design + Site Finder
Две продуктовые линии в одной воронке: **Site Finder** (AI-подбор инвестиционных земельных участков) + **Generative Design** (автоматическая генерация концепций застройки) для девелоперов РФ.
## North Star
К концу месяца 3: **3 платящих пилота** (≥30 тыс. ₽/мес каждый) + заявка в реестр российского ПО → право на Раунд А (2025 млн ₽).
Acceptance criteria разбиты на 3 блока (функционально / бизнесово / технически). Правило перехода: 3/3 → Раунд А; 2/3 → продление Фазы 0 на 12 мес.; 1/3 или меньше → стоп проекта.
---
## Текущий статус (25 апреля 2026)
**Инфраструктура: live.** Полный цикл автодеплоя из GitHub Actions работает.
| Что | Где | Статус |
|---|---|---|
| Production VPS | Beget Cloud, Москва, 2 vCPU / 4 GB / 40 GB NVMe | ✅ работает |
| IP сервера | `46.173.16.127` | — |
| Postgres + PostGIS 3.4 | Docker, в составе compose | ✅ Up (healthy) |
| Redis 7 | Docker | ✅ Up |
| Backend FastAPI | Docker (образ из GHCR) | ✅ Up, `/health` отвечает |
| Frontend Next.js 15 | Docker (образ из GHCR) | ✅ Up |
| Caddy reverse proxy | Docker, ports 80/443 | ✅ Up (TLS ждёт домена) |
| GitHub Actions deploy | `.github/workflows/deploy.yml` | ✅ build → push GHCR → ssh deploy |
| GHCR пакеты | `ghcr.io/lekss361/gendesign-{backend,frontend}` | приватные, сервер авторизуется через PAT |
| UFW firewall | 22 / 80 / 443 | ✅ активен |
| SSH hardening | root login off, password auth off | ✅ |
| Домен | — | ⏸ не подключён |
| Бэкапы pg_dump | — | ⏸ не настроены |
**Решение по плану разработки: 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` в графе памяти.
---
## Структура репозитория
```
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)
├── .env.example # шаблон prod env (POSTGRES_*, IMAGE_TAG, NEXT_PUBLIC_API_BASE_URL)
├── docker-compose.yml # dev: Postgres + Redis + backend + frontend
├── docker-compose.prod.yml # prod: образы из GHCR + Caddy + Postgres+Redis
├── Caddyfile # авто-TLS Let's Encrypt
├── Makefile # make up / down / test / codegen / migrate
└── .github/workflows/
├── ci.yml # ruff + mypy(core) + pytest + frontend build
└── deploy.yml # build → push в GHCR → ssh deploy на VM
```
---
## Технический стек (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, ruff, mypy (strict только на core), pytest
---
## Команда и порядок работы
**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 (нед. 27) ⏸ pending решения по Plan A
- **1a (нед. 23):** геометрия + API-контракт. Shapely-сервис (отступы, сетка), Pydantic-схемы, `POST /api/v1/concepts` с заглушкой. Фронт: страница `/concept`, Leaflet, импорт GeoJSON, форма параметров, 3 варианта в табах.
- **1b (нед. 45):** алгоритм размещения. Жадное заполнение, 3 стратегии (max площадь / max инсоляция / balanced), STRtree для коллизий. Цель ≤10 сек, fallback 15 сек.
- **1c (нед. 67):** ТЭП + финмодель + экспорты. WeasyPrint PDF, ezdxf, openpyxl. UI кнопок скачивания.
**Acceptance Stage 1 (конец нед. 7):** полигон → 3 варианта → ТЭП + финмодель → PDF/Excel/DXF.
### Stage 2 — Site Finder MVP (нед. 812)
- **2a (нед. 89):** data pipeline. Парсер ПКК Rosreestr (httpx async, retries), модель `Parcel` с GeoAlchemy2, ≥1000 участков Екатеринбурга. Overpass API для POI, ДОМ.РФ/ЦИАН для цен м², кеш в Redis. Опционально: воркер `sales_tracker.py` — ежесуточный мониторинг шахматок застройщиков (Velocity Score).
- **2b (нед. 1011):** скоринг + 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: ~1015 тыс ₽/мес.
### Что осталось до «infra-ready»
- [ ] Купить домен .ru (REG.RU / РуЦентр), направить A-запись на `46.173.16.127`
- [ ] Обновить `Caddyfile` с реальным доменом → авто-TLS Let's Encrypt
- [ ] Задать `NEXT_PUBLIC_API_BASE_URL=https://<домен>` в `/opt/gendesign/.env` либо оставить пустым (frontend ходит через Caddy `/api/*` → backend)
- [ ] Настроить ежесуточный `pg_dump` → Object Storage (Yandex free tier 1 GB или Selectel S3)
- [ ] Sentry DSN в `backend/.env`
---
## 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` и `<sha7>`
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`
- Этот файл — **хард-линк** на `<repo>/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` — бизнес-план
⚠️ Эти документы — **снимок состояния на момент написания**. Свежее состояние стратегии — в графе памяти. При расхождении доверяем графу.
Релевантные сущности графа на 25.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 решение
- `SalesTracking_Strategy_Apr25` — шахматки застройщиков
- `DataSources_Pricing_Apr25` — источники цен и площадей
- `Hosting_Pricing_Apr25` — сравнение провайдеров
- `Hosting_Decision_Apr25` — решение по Yandex Cloud (для будущей миграции)
- `Runbook_VPS_Setup_Beget` — пошаговая настройка production VM
- `SSH_Setup_Apr25` — локальная настройка SSH
- `Onboarding_Colleague_KG` — подключение нового участника к графу
- `Feedback_MemoryFirst` — правило: память first, docs только по запросу
- `Validation_Findings_Apr25` — валидация бизнес-плана
---
## Полезные ссылки
- **Репо:** https://github.com/lekss361/-gendesign
- **GitHub Actions:** https://github.com/lekss361/-gendesign/actions
- **GHCR пакеты:** https://github.com/lekss361?tab=packages
- **Production VPS:** Beget Cloud → `cp.beget.com/cloud/servers/jolly-yakov-3`
- **Целевой регион Discovery:** Свердловская обл. (Екатеринбург, ПЗЗ, МСК-66)
- **Конкуренты:** rTIM (только концепт-стадия, нет site-selection), TestFit (нет РФ-данных)