Memory: catch up — hosting research, sales tracking, plan A, runbook, hardening
This commit is contained in:
parent
09b9f18d3f
commit
4bd70cde06
2 changed files with 134 additions and 42 deletions
149
README.md
149
README.md
|
|
@ -10,6 +10,34 @@ Acceptance criteria разбиты на 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` в графе памяти.
|
||||
|
||||
---
|
||||
|
||||
## Структура репозитория
|
||||
|
||||
```
|
||||
|
|
@ -33,6 +61,7 @@ gendesign/
|
|||
├── 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
|
||||
|
|
@ -40,13 +69,14 @@ gendesign/
|
|||
├── 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: образы из реестра + Caddy reverse-proxy
|
||||
├── 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 в реестр → ssh deploy на VM
|
||||
└── deploy.yml # build → push в GHCR → ssh deploy на VM
|
||||
```
|
||||
|
||||
---
|
||||
|
|
@ -57,7 +87,7 @@ gendesign/
|
|||
**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)
|
||||
**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
|
||||
|
||||
|
|
@ -74,27 +104,29 @@ gendesign/
|
|||
- Trunk-based: feature ветки ≤ 3 дней
|
||||
- Codegen TS-типов из Pydantic (`npm run codegen`) — без этого 2 фуллстека плодят расхождения в API-контракте
|
||||
|
||||
**Порядок:** строго последовательный — Generative полностью, потом Site Finder.
|
||||
|
||||
---
|
||||
|
||||
## Этапы MVP (12 недель)
|
||||
## Этапы 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` до Раунда А).
|
||||
### 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)
|
||||
### 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. Это уже **продаваемый артефакт** — можно показывать на встречах с месяца 2.
|
||||
**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.
|
||||
- **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 → перед Раундом А
|
||||
|
|
@ -111,6 +143,7 @@ gendesign/
|
|||
# 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
|
||||
|
|
@ -128,7 +161,7 @@ curl http://localhost:8000/health
|
|||
```bash
|
||||
make logs # tail логов всех сервисов
|
||||
make backend-shell # bash внутри backend контейнера
|
||||
make migrate # alembic upgrade head
|
||||
make migrate # alembic upgrade head (когда добавим миграции)
|
||||
make test # pytest
|
||||
make lint # ruff check
|
||||
make typecheck # mypy на core
|
||||
|
|
@ -137,23 +170,19 @@ make codegen # обновить TS-типы из OpenAPI
|
|||
|
||||
---
|
||||
|
||||
## Хостинг (production)
|
||||
## Production хостинг — Beget VPS
|
||||
|
||||
### Discovery MVP (мес. 1–3): минимальный режим
|
||||
**Текущая live-конфигурация:** Beget Cloud, Москва, Standard 3+ GHz, 2 vCPU / 4 GB / 40 GB NVMe.
|
||||
|
||||
**1× VPS** на Selectel / Timeweb / Beget (2 vCPU / 4 GB / 60 GB SSD), всё в Docker Compose:
|
||||
**Стоимость:** ~33 ₽/день сервер + ~5 ₽/день IPv4 = **~1140 ₽/мес**. Плюс домен .ru (~17 ₽/мес).
|
||||
|
||||
| Компонент | Сервис |
|
||||
|---|---|
|
||||
| App | backend + frontend (образы из GHCR) |
|
||||
| БД | Postgres 16 + PostGIS 3.4 (в том же compose) |
|
||||
| Кэш/очереди | Redis 7 |
|
||||
| TLS | Caddy с Let's Encrypt автоматически |
|
||||
| Бэкапы | cron pg_dump → Yandex Object Storage (free tier 1 GB) |
|
||||
**Что крутится на 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`
|
||||
|
||||
**Стоимость:** ~1300–2000 ₽/мес (VPS) + ~17 ₽/мес (домен .ru) = **~1500–2000 ₽/мес**.
|
||||
|
||||
⚠️ **Критично:** настроить ежесуточный pg_dump в первую неделю. Без бэкапа = смерть проекта при первом сбое VM.
|
||||
**Доступ:** SSH-only по ключу к non-root пользователю `gendesign`. Root login отключён, password auth отключён, fail2ban Beget активен.
|
||||
|
||||
### Триггеры миграции на Yandex Cloud
|
||||
|
||||
|
|
@ -165,17 +194,44 @@ make codegen # обновить TS-типы из OpenAPI
|
|||
|
||||
Стоимость production на YC: ~10–15 тыс ₽/мес.
|
||||
|
||||
### GitHub Actions deploy
|
||||
### Что осталось до «infra-ready»
|
||||
|
||||
Workflow `.github/workflows/deploy.yml` собирает образы и через SSH деплоит на VM:
|
||||
1. Build backend + frontend Docker образов
|
||||
2. Push в реестр (GHCR для Discovery, YCR после миграции)
|
||||
3. SSH на VM → `docker compose pull && up -d`
|
||||
- [ ] Купить домен .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`
|
||||
|
||||
**Secrets** (GitHub → Settings → Secrets and variables → Actions):
|
||||
- `DEPLOY_HOST`, `DEPLOY_USER`, `DEPLOY_SSH_KEY`, `DEPLOY_PORT` (опц.)
|
||||
- Для GHCR — `GITHUB_TOKEN` встроенный, отдельный secret не нужен
|
||||
- Для YC (после миграции) — `YC_SA_JSON_CREDENTIALS`, `YC_REGISTRY_ID`
|
||||
---
|
||||
|
||||
## 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 раз в год.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -207,7 +263,7 @@ git push
|
|||
|
||||
### Подключение коллеги
|
||||
|
||||
Краткая инструкция для нового участника команды (полная версия — у владельца репо):
|
||||
Краткая инструкция для нового участника команды:
|
||||
|
||||
1. Установить Claude Desktop, Node.js 20+, Git
|
||||
2. Клонировать репо в `C:\Users\<имя>\source\repos\gendesign`
|
||||
|
|
@ -228,6 +284,8 @@ git push
|
|||
6. Перезапустить Claude Desktop полностью (через трей)
|
||||
7. Проверить: «Покажи память контекста gendesign»
|
||||
|
||||
Полная версия процедуры — в графе, сущность `Onboarding_Colleague_KG`.
|
||||
|
||||
---
|
||||
|
||||
## Документы стратегии
|
||||
|
|
@ -238,10 +296,31 @@ git push
|
|||
|
||||
⚠️ Эти документы — **снимок состояния на момент написания**. Свежее состояние стратегии — в графе памяти. При расхождении доверяем графу.
|
||||
|
||||
Релевантные сущности графа на 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 (нет РФ-данных)
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
Loading…
Add table
Reference in a new issue