gendesign/README.md
Light1YT e027f0a6ea
All checks were successful
CI / changes (push) Successful in 8s
CI / frontend-tests (push) Has been skipped
CI / changes (pull_request) Successful in 6s
CI / backend-tests (push) Successful in 7m49s
CI / frontend-tests (pull_request) Has been skipped
CI / backend-tests (pull_request) Successful in 7m30s
feat(admin): freshness endpoint (#73) + README Forgejo refresh (#83) + migrations doc (#72)
#73: GET /admin/scrape/freshness — last_success/age/freshness/status для 5 источников
(kn/objective/nspd/nspd_geo/cadastre) + overall_status (worst по critical). Prod-verified
имена таблиц, FILTER/COALESCE корректны, CAST(:d AS interval). +4 теста.
#83: README — GitHub→Forgejo CI/CD, секция 6 subagents, ссылки перемаплены.
#72: docs/Schema_Migrations_vs_Alembic.md — _schema_migrations паттерн (не Alembic),
рекомендация снести пустой alembic-скелет (отдельный PR).

Closes #73
Closes #83
Closes #72
2026-06-13 23:12:28 +05:00

231 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** (автоматическая генерация концепций застройки) для девелоперов РФ. Целевой регион Discovery — Свердловская обл. (ЕКБ, ПЗЗ, МСК-66).
## North Star
К концу месяца 3: **3 платящих пилота** (≥30 тыс. ₽/мес каждый) + заявка в реестр российского ПО → право на Раунд А (2025 млн ₽).
---
## Текущий статус (июнь 2026)
**Live:** [https://gendsgn.ru/](https://gendsgn.ru/) — HTTP/2+HTTP/3, валидный TLS, [/health](https://gendsgn.ru/health) `{"status":"ok"}`. Полный CI/CD: **Forgejo Actions** ([git.gendsgn.ru](https://git.gendsgn.ru)) → GHCR → SSH-deploy на Beget VPS (миграция с GitHub Actions 16 мая 2026). Sentry/GlitchTip активен (release tracking привязан к git-sha).
| Слой | Статус |
|---|---|
| Аналитический калькулятор `/analytics/recommend` (Tier 3 per-bucket эластичность, кадастр vs рынок) | ✅ |
| DOM.РФ kn-API скрейпер (442 строящихся ЖК Свердл, sale_graph + infra + photos) | ✅ Celery beat + admin UI |
| NSPD geo bulk-fetcher (rosreestr2coord lite, без Playwright) | ✅ admin UI с per-target логами |
| Rosreestr CSV-сделки 2024Q1—2026Q1 (9 квартирных партиций, 7M строк) | ✅ |
| NSPD кадастровые кварталы + здания (709 cad-кварталов, 10 590 cad_buildings ЕКБ) | ✅ Celery beat + admin UI |
| OSM ekb_districts_geom (PostGIS-полигоны 8 районов ЕКБ) | ✅ |
| Objective ETL (Anton SQLite → PG, ports на psycopg v3) | ✅ admin UI |
| Obsidian Self-hosted LiveSync vault на `obsidian.gendsgn.ru` (268 entities из KG) | ✅ multi-device sync |
| Concept page (`/concept`) — Stage 1 Generative | 🟡 skeleton |
| Site Finder (`/site-finder`) — Stage 2 | 🔴 заглушка |
**Backlog:** [Forgejo Issues](https://git.gendsgn.ru/lekss361/gendesign/issues) (трекаемые задачи с PR-связью) + [Obsidian vault](https://obsidian.gendsgn.ru) (планы, ADR, research — см. ниже про разделение).
---
## Quick start (локально)
**Требования:** Docker Desktop, Node.js 20+, [uv](https://docs.astral.sh/uv/) для backend dev.
```bash
cp backend/.env.example backend/.env
cp frontend/.env.example frontend/.env
docker compose up -d --build
curl http://localhost:8000/health # → {"status":"ok","environment":"dev"}
# Frontend: http://localhost:3000
# Swagger: http://localhost:8000/docs
```
Полезные `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 скрипты
scripts/ утилиты (migrate_kg_to_obsidian.py, setup-couchdb.sh, cleanup_ghosts.py)
docs/ стратегические снапшоты (актуальное knowledge — в Obsidian vault)
memory/ legacy JSONL knowledge graph (deprecated, не обновляется — данные в Obsidian)
docker-compose.prod.yml main стек (backend, frontend, postgres, redis, worker, beat, caddy)
docker-compose.obsidian.yml obsidian-стек (CouchDB) — деплоится отдельно
.forgejo/workflows/ (Forgejo Actions — основной CI/CD после миграции 16.05.2026)
├── ci.yml lint (ruff) + mypy + pytest на PR
├── deploy.yml main → пересборка backend/frontend образов + auto-apply data/sql/*.sql + SSH deploy
├── deploy-tradein.yml tradein-mvp стек (отдельный пайплайн)
└── stale-claims.yml авто-снятие протухших claim-меток в bot-пайплайне
.github/workflows/ (остаточные — только obsidian-стек на GitHub)
└── deploy-obsidian.yml obsidian-стек (CouchDB compose changes + bootstrap)
```
---
## Аналитика — что доступно
В прод-БД ~50 предметных таблиц:
- **`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.
**Калькулятор `/analytics/recommend`** считает квартирографию (5 size-бакетов) с per-bucket эластичностью через регрессию sale_graph, нормировкой на район/класс/конкурентов, кадастр-vs-рынок cross-check, и инверсным режимом «требуемая цена для срока X мес».
Подробное описание схемы БД, helper-views, FK и 27.04 history — в Obsidian vault: `domains/analytics/Analytics_Dashboard_Apr27`, `domains/domrf/events/DomRF_Lazy_Loaded_Apr27_2026`, `events/Anton_Imported_Apr27_2026`, `domains/cadastre/Cad_Quarter_Backfill_Apr30`. См. также `data/sql/*.sql` (DDL артефакты).
---
## Production хостинг
**Beget Cloud, Москва, 2 vCPU / 4 GB / 40 GB NVMe.** Стоимость ~1 140 ₽/мес сервер + ~17 ₽/мес домен.
**Два изолированных стека через docker compose, общая Docker network `gendesign_shared`:**
1. **Main стек** (`docker-compose.prod.yml`, project `gendesign`):
`postgres` + `redis` + `backend` (FastAPI) + `worker` + `beat` (Celery, Chromium только в worker) + `frontend` + `caddy` (auto-TLS Let's Encrypt). Backend/frontend bind на `127.0.0.1` — наружу только Caddy.
2. **Obsidian стек** (`docker-compose.obsidian.yml`, project `gendesign-obsidian`):
`couchdb:3` — Self-hosted LiveSync remote для multi-device sync vault'а на `obsidian.gendsgn.ru`. Caddy в main-стеке маршрутизирует через `gendesign_shared` network.
**Split deploy** — изменения в main НЕ перезагружают obsidian (и наоборот). Каждый стек со своим workflow.
**SSH-only по ключу к non-root пользователю `gendesign`**, fail2ban активен. UFW: 22/80/443.
**Forgejo Actions deploys** (self-hosted `git.gendsgn.ru`, мигрировано с GitHub Actions 16.05.2026):
- [`.forgejo/workflows/ci.yml`](.forgejo/workflows/ci.yml) — на PR: ruff lint + mypy (selective strict) + pytest. Блокирует merge при провале.
- [`.forgejo/workflows/deploy.yml`](.forgejo/workflows/deploy.yml) — main: триггер на `backend/**`, `frontend/**`, `Caddyfile`, `docker-compose.prod.yml`, `data/sql/**`. Build backend lean + worker-with-chromium + frontend → push в приватный GHCR → SSH `git reset --hard`, **auto-apply pending `data/sql/NN_*.sql` через `_schema_migrations`** (idempotent, см. ниже про миграции), sed `SENTRY_RELEASE=$IMAGE_TAG` в `backend/.env.runtime`, `compose pull && up -d`, `caddy reload`, `curl /health`.
- [`.forgejo/workflows/deploy-tradein.yml`](.forgejo/workflows/deploy-tradein.yml) — tradein-mvp стек (отдельный пайплайн).
- [`.github/workflows/deploy-obsidian.yml`](.github/workflows/deploy-obsidian.yml) — obsidian (**остался на GitHub**): триггер на `docker-compose.obsidian.yml`, `scripts/setup-couchdb.sh`, `docs/obsidian-livesync.md`. Без сборки образов (couchdb:3 с DockerHub), SSH `compose up -d` + idempotent bootstrap (CORS, DB, лимиты).
**Forgejo Secrets / Variables:** `DEPLOY_HOST`, `DEPLOY_USER`, `DEPLOY_SSH_KEY`, `DEPLOY_PORT`. Сервер авторизуется в GHCR однократно через PAT с `read:packages`. `COUCHDB_USER`/`COUCHDB_PASSWORD` — в `backend/.env.runtime` на VPS (не в репе).
### Миграции БД — `_schema_migrations`, не Alembic
Схема развивается через **идемпотентные `data/sql/NN_*.sql`** (`CREATE … IF NOT EXISTS`, guarded `DO`-блоки). `deploy.yml` перед `compose up` прогоняет файлы в лексикографическом порядке, отмечая применённые в таблице-трекере `_schema_migrations` (применяется ровно один раз каждый). Каталог `backend/alembic/versions/` **пуст** — Alembic в проде не используется. Подробности и граница «raw SQL vs ORM» — [`docs/Schema_Migrations_vs_Alembic.md`](docs/Schema_Migrations_vs_Alembic.md).
**Триггеры миграции на Yandex Cloud:** 3-й платящий пилот / Раунд А / госзаказ (нужен реестр ПО) / БД >10 GB / >50 RPS. На YC ~1015 тыс ₽/мес.
### Операционные грабли
- `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`.
---
## Roadmap (12 недель)
| Stage | Сроки | Что | Acceptance |
|---|---|---|---|
| **0** ✅ | нед. 1 | Скелет монорепо, CI, прод | curl /health = ok |
| **Sprint 1** ✅ | конец апр 2026 | NSPD-скрейпер + per-bucket эластичность + кадастр cross-check + Sentry release tracking | recommend_mix Tier 3 в проде |
| **1a** | нед. 23 | Shapely-сервис, отступы, API-контракт `/concept` ([#5](https://git.gendsgn.ru/lekss361/gendesign/issues/5)) | GeoJSON → 3 заглушки |
| **1b** | нед. 45 | Greedy-алгоритм, 3 стратегии, STRtree ([#12](https://git.gendsgn.ru/lekss361/gendesign/issues/12)) | 3 варианта ≤15с на 1 га |
| **1c** | нед. 67 | ТЭП + финмодель + PDF/Excel/DXF ([#6](https://git.gendsgn.ru/lekss361/gendesign/issues/6)) | Продаваемый артефакт |
| **2a** | нед. 89 | ПКК-парсер + sales_tracker ([#7](https://git.gendsgn.ru/lekss361/gendesign/issues/7)) | ≥1000 участков ЕКБ |
| **2b** | нед. 1011 | Скоринг + API + UI Site Finder ([#8](https://git.gendsgn.ru/lekss361/gendesign/issues/8)) | Карта с цветовой градацией |
| **2c** | нед. 12 | Site Finder ↔ Generative + реестр ПО ([#9](https://git.gendsgn.ru/lekss361/gendesign/issues/9)) | 3 платящих пилота |
Аналитический backlog: [#17](https://git.gendsgn.ru/lekss361/gendesign/issues/17) velocity-anomaly, [#18](https://git.gendsgn.ru/lekss361/gendesign/issues/18) ekb_districts median refresh, [#19](https://git.gendsgn.ru/lekss361/gendesign/issues/19) competitor-360, [#20](https://git.gendsgn.ru/lekss361/gendesign/issues/20) mortgage-rate sensitivity, [#21](https://git.gendsgn.ru/lekss361/gendesign/issues/21) cad_buildings filters в Site Finder.
---
## Команда и память проекта
**2 фуллстек-разработчика, part-time 20 ч/нед**, ритм: 1 синк/нед, daily-async в Telegram, PR-review обязательный, trunk-based. Codegen TS-типов из Pydantic — `npm run codegen`.
### Knowledge base — Obsidian vault
**Источник правды** — Obsidian vault на `obsidian.gendsgn.ru` (Self-hosted LiveSync + CouchDB). Markdown-файлы с `[[wiki-links]]`, MOC-страницами, Graph View и тегами. Multi-device sync: desktop / laptop / iPhone / Android. **268 entities** мигрированы из исторического JSONL knowledge graph (`scripts/migrate_kg_to_obsidian.py`), который теперь deprecated.
Структура vault:
- `meta/` — гайды, credentials, project meta (Project_GenDesign, TechStack, NorthStar)
- `domains/{domrf,cadastre,rosreestr,analytics,ui,api,geo,infra}/` — knowledge по бизнес-доменам
- `code/{modules,schemas,patterns,hooks,tasks}/` — code-level entities
- `decisions/` — ADR / планы / политики
- `fixes/` — bug-журналы
- `sessions/`, `sprints/`, `events/` — chronological logs
- `research/`, `sources/`, `feedback/`, `github/`, `limitations/` — прочее
- `old/` — архив legacy paths (redirect-stubs)
**Подключение коллеги** — гайды в самом vault'е:
- `meta/01_connect_devices.md` — установка Obsidian + LiveSync на любую платформу (через Setup URI или 4 поля)
- `meta/03_obsidian_plugins.md` — какие плагины ставить (Local REST API, Templater, Dataview)
- `meta/04_mcp_obsidian_setup.md` — подключение Claude к vault через MCP
**Legacy:** старый knowledge graph JSONL (`memory/memory-gendesign.jsonl`) — снапшот на момент 2026-05-11, не обновляется. Все новые факты пишутся в Obsidian.
### Где вести задачи — Forgejo Issues vs Obsidian
Используем **оба**, но с чёткой ролью (трекер мигрирован с GitHub на self-hosted Forgejo 16.05.2026):
| | Forgejo Issues ([git.gendsgn.ru](https://git.gendsgn.ru/lekss361/gendesign/issues)) | Obsidian vault |
|---|---|---|
| Что сюда | Bug + Feature + Refactor — всё с **связью с кодом / PR** | Knowledge: research, ADR, planning, draft-ideas |
| Lifecycle | Open → Assigned → PR → Merged → Closed | Append-only журнал решений и контекста |
| Уведомления | Forgejo email/webhook | Никаких (читаешь когда сам пришёл) |
| Поиск | Forgejo search + labels + milestones | BM25 + tags + Graph + MOC |
| Видимость | Команде в reviewer'ах | Всем у кого есть vault password |
| Сроки | Milestones (12-week roadmap) | Frontmatter `date:`, `status:`, `due:` |
**Правило перехода:** Obsidian `fixes/Bug_X.md` со `status: OPEN` → когда требует PR — создаём **Forgejo Issue**, ссылку прописываем во frontmatter `.md` (`issue: 42`). Bug-исследование живёт в vault'е, action item — в Issues.
**Что куда:**
- `Bug_*` (vault) + Forgejo Issue с тегом `bug` → обнаружен баг, фикс через PR
- `decisions/*` (vault) — ADR, не нужен Issue
- `research/*` (vault) — анализ источников, конкуренты, метрики
- `sessions/*` (vault) — журналы рабочих сессий
- Forgejo Issues `feat/*` — фичи + PR на 1+ files, видимые в milestones
### Claude Code subagents (`.claude/agents/`)
Разработка ведётся через Claude Code с **6 кастомными subagent'ами** (path-scoped, со своими MCP-«учётками»: прод-PostgreSQL, Obsidian vault, Forgejo, GlitchTip). Полные правила — `.claude/rules/` + корневой [`CLAUDE.md`](CLAUDE.md).
| Agent | Scope / зона ответственности |
|---|---|
| `tech-analyst` | Нечёткая / cross-domain задача → план перед кодом |
| `backend-engineer` | `backend/app/**` — FastAPI, Celery, scrapers, services |
| `frontend-engineer` | `frontend/src/**` — Next.js 15, React 19, hooks |
| `database-expert` | `data/sql/**.sql`, схема, EXPLAIN ANALYZE, прод-БД через MCP |
| `devops-engineer` | `docker-compose*.yml`, `Caddyfile`, `.forgejo/workflows/**` |
| `code-reviewer` | Pre-push lint: security, correctness, conventions |
**Workflow:** тривиально (typo, 1-line) → main session; single-domain → профильный worker; cross-domain → `tech-analyst` сначала. Worker → `code-reviewer` → коммит → push → PR в Forgejo. Branch + PR обязательны, никаких direct push в main.
---
## Полезные ссылки
| | |
|---|---|
| 🌐 Production | https://gendsgn.ru/ |
| 🩺 Health | https://gendsgn.ru/health |
| 📚 OpenAPI | [Swagger UI](https://gendsgn.ru/docs) · https://gendsgn.ru/openapi.json (за Caddy basic_auth) |
| 🗂 Knowledge vault | https://obsidian.gendsgn.ru (требуется Obsidian + Self-hosted LiveSync, см. vault `meta/01_connect_devices.md`) |
| 🧰 Git / CI | [git.gendsgn.ru](https://git.gendsgn.ru/lekss361/gendesign) (Forgejo) · [`CLAUDE.md`](CLAUDE.md) — правила разработки |
| Backlog | [Issues](https://git.gendsgn.ru/lekss361/gendesign/issues) · [Milestones](https://git.gendsgn.ru/lekss361/gendesign/milestones) |
| Деплой | [Forgejo Actions](https://git.gendsgn.ru/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/), [`docs/obsidian-livesync.md`](docs/obsidian-livesync.md). При расхождении с vault'ом — доверяем vault'у.