gendesign/tradein-mvp/DEPLOY.md
bot-backend bcd035034a
Some checks failed
Deploy Trade-In / deploy (push) Blocked by required conditions
Deploy Trade-In / changes (push) Successful in 4s
Deploy Trade-In / build-frontend (push) Successful in 23s
Deploy Trade-In / test (push) Successful in 24s
Deploy Trade-In / build-backend (push) Has been cancelled
fix(tradein): SSRF host-allowlist на admin scrape + удалён dead ADMIN_TOKEN (Refs #756) (#778)
Co-authored-by: bot-backend <bot-backend@gendsgn.local>
Co-committed-by: bot-backend <bot-backend@gendsgn.local>
2026-05-30 16:27:19 +00:00

206 lines
8.9 KiB
Markdown
Raw Permalink 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.

# Trade-In MVP — деплой в gendesign репо
## Архитектура
```
lekss361/-gendesign/
├── backend/ ← gendesign Python backend (НЕ ТРОГАЕМ)
├── frontend/ ← gendesign Next.js (НЕ ТРОГАЕМ)
├── docker-compose.prod.yml ← gendesign-стек
├── Caddyfile ← основной Caddy → ВКЛЮЧАЕТ tradein-mvp/deploy/Caddyfile.tradein-fragment
├── .github/workflows/
│ ├── deploy.yml ← существующий gendesign deploy
│ └── deploy-tradein.yml ← НАШ новый, триггерится только на tradein-mvp/**
└── tradein-mvp/ ← НАША подпапка (изолированный subproject)
├── backend/
├── frontend/
├── deploy/
│ ├── Caddyfile.tradein-fragment ← импортится в основной Caddyfile
│ └── cron-scrape.sh
├── docker-compose.yml ← локальный dev
├── docker-compose.prod.yml ← production overlay (использует GHCR images)
└── .github/workflows/deploy-tradein.yml
```
## Прод URL routes
| URL | Сервис |
|----------------------------------|-------------------------|
| `gendsgn.ru/trade-in/` | tradein-frontend:3000 |
| `gendsgn.ru/trade-in/api/v1/...` | tradein-backend:8000 |
Caddy в gendesign-стеке проксирует через `handle_path /trade-in/api/*` (вырезает префикс) и `handle /trade-in/*` (Next.js basePath).
## Прод docker stacks
- `docker compose -p gendesign` — основной gendesign (postgres + backend + frontend + caddy + couchdb)
- `docker compose -p gendesign-tradein` — наш (tradein-postgres + tradein-backend + tradein-frontend)
Оба подключены к `gendesign_shared` external network — туда смотрит Caddy.
## Что нужно положить в основной Caddyfile gendesign
В блок `gendsgn.ru { ... }` **ПЕРЕД** универсальным `handle { reverse_proxy frontend:3000 }`:
```caddyfile
import /opt/gendesign/tradein-mvp/deploy/Caddyfile.tradein-fragment
```
Или вставить содержимое фрагмента inline.
## Что нужно положить в `.env.runtime` (на сервере, НЕ в git)
Два файла:
1. `/opt/gendesign/tradein-mvp/.env.runtime` — переменные для docker compose
substitution (`${TRADEIN_POSTGRES_PASSWORD}` и т.п. в compose-файле). Читается
shell-скриптом deploy через `source .env.runtime` перед `compose up`.
2. `/opt/gendesign/tradein-mvp/backend/.env.runtime` — переменные внутри
контейнера `tradein-backend` (читаются через `env_file:` в compose). Сюда
попадают `YANDEX_GEOCODER_API_KEY`, `COOKIE_ENCRYPTION_KEY`
всё, что нужно scripts/backfill_house_coords.py и application code внутри
контейнера.
```bash
# /opt/gendesign/tradein-mvp/.env.runtime
TRADEIN_POSTGRES_USER=tradein
TRADEIN_POSTGRES_PASSWORD=<сгенерировать openssl rand -hex 32>
TRADEIN_CONTACT_EMAIL=tradein@gendsgn.ru
YANDEX_GEOCODER_API_KEY= # пусто пока, Nominatim fallback работает
# Encryption key for Cian session cookies (pgp_sym_encrypt / Stage 9 Calculator).
# Empty = Valuation Calculator scraper disabled + /api/v1/cookies/upload returns 503.
# Generate once on VPS:
# openssl rand -hex 32
COOKIE_ENCRYPTION_KEY=<64-char hex>
```
```bash
# /opt/gendesign/tradein-mvp/backend/.env.runtime — те же ключи которые
# читаются ВНУТРИ container'а (scripts/backfill_house_coords.py, app/*).
# Может быть симлинком на ../.env.runtime если переменные совпадают:
# ln -s ../.env.runtime /opt/gendesign/tradein-mvp/backend/.env.runtime
YANDEX_GEOCODER_API_KEY=<key или пусто>
COOKIE_ENCRYPTION_KEY=<64-char hex>
GENDESIGN_FDW_PASSWORD=<password или пусто>
GLITCHTIP_DSN=<dsn или пусто>
# DaData on-demand enrichment в /estimate flow (PR Q1).
# Demo tier: 100 req/день. Пусто = enrichment disabled (graceful).
# Регистрация ключей: https://dadata.ru/api/clean/
DADATA_API_TOKEN=<token или пусто>
DADATA_API_SECRET=<secret или пусто>
```
Оба файла создаются вручную при первом деплое.
### После изменения `backend/.env.runtime`
```bash
# .env.runtime читается на старте container — `compose restart` НЕ перечитывает.
docker compose -p gendesign-tradein -f docker-compose.prod.yml \
up -d --force-recreate --no-deps backend
```
См. `.claude/rules/deploy.md` — main backend pattern идентичный.
### Обновление `COOKIE_ENCRYPTION_KEY` на существующем VPS
```bash
# На VPS, если COOKIE_ENCRYPTION_KEY ещё не задан:
echo "COOKIE_ENCRYPTION_KEY=$(openssl rand -hex 32)" >> /opt/gendesign/tradein-mvp/.env.runtime
# Применить без полного рестарта стека:
cd /opt/gendesign/tradein-mvp
docker compose -p gendesign-tradein -f docker-compose.prod.yml up -d --force-recreate --no-deps backend
```
## GitHub Secrets (уже должны быть от gendesign deploy)
- `DEPLOY_HOST` — IP сервера (94.228.121.73)
- `DEPLOY_USER` — root
- `DEPLOY_SSH_KEY` — приватный SSH ключ
- `DEPLOY_PORT` — 22 (или другой если меняли)
## Первый деплой — пошагово
### 1. На анто́новой машине: подготовить tradein-mvp/ к слиянию
```bash
# clone gendesign репо (с PAT)
git clone https://<PAT>@github.com/lekss361/-gendesign.git
cd -gendesign
# скопировать tradein-mvp/ как подпапку
cp -r /Users/anton/Птица/tradein-mvp ./tradein-mvp
rm -rf ./tradein-mvp/postgres-data # на всякий
rm -rf ./tradein-mvp/.git # не нужен внутри monorepo
# скопировать workflow в правильное место
mkdir -p .github/workflows
cp ./tradein-mvp/.github/workflows/deploy-tradein.yml .github/workflows/
git add tradein-mvp/ .github/workflows/deploy-tradein.yml
git commit -m "feat: add tradein-mvp subproject + deploy workflow"
git push origin main
```
### 2. На сервере: первый раз вручную добавить Caddy include
```bash
ssh -i ~/.ssh/id_bot_server root@94.228.121.73
cd /opt/gendesign
# git reset --hard origin/main подтянет tradein-mvp/ автоматически
# Добавить в Caddyfile (ровно одну строку в блок gendsgn.ru { ... })
nano Caddyfile
# вставить ПЕРЕД последним handle { ... }:
# import /opt/gendesign/tradein-mvp/deploy/Caddyfile.tradein-fragment
# Создать .env.runtime — два файла:
# 1. tradein-mvp/.env.runtime — для compose substitution на host'е
cat > tradein-mvp/.env.runtime <<EOF
TRADEIN_POSTGRES_USER=tradein
TRADEIN_POSTGRES_PASSWORD=$(openssl rand -hex 32)
TRADEIN_CONTACT_EMAIL=tradein@gendsgn.ru
YANDEX_GEOCODER_API_KEY=
EOF
chmod 600 tradein-mvp/.env.runtime
# 2. tradein-mvp/backend/.env.runtime — для env_file внутри container'а.
# Симлинк работает если переменные одни и те же; иначе создать отдельный файл.
ln -sf ../.env.runtime tradein-mvp/backend/.env.runtime
# Запустить stack первый раз вручную (после этого GitHub Actions сам)
docker network inspect gendesign_shared >/dev/null 2>&1 || docker network create gendesign_shared
cd tradein-mvp
set -a; source .env.runtime; set +a
docker compose -p gendesign-tradein -f docker-compose.prod.yml pull
docker compose -p gendesign-tradein -f docker-compose.prod.yml up -d
# Reload Caddy
cd /opt/gendesign
docker compose -p gendesign -f docker-compose.prod.yml exec -T caddy caddy reload --config /etc/caddy/Caddyfile
# Проверить
curl -sS https://gendsgn.ru/trade-in/api/health
curl -sI https://gendsgn.ru/trade-in/
```
### 3. Дальше — автодеплой
После первого ручного запуска все следующие `git push origin main` с изменениями в `tradein-mvp/**` будут:
1. Триггерить `.github/workflows/deploy-tradein.yml`
2. Билдить и пушить новые образы в `ghcr.io/lekss361/gendesign-tradein-*`
3. SSH в сервер → `docker compose pull``up -d` → Caddy reload
4. Health check
## Откат
```bash
ssh root@94.228.121.73
cd /opt/gendesign/tradein-mvp
# Откатиться на предыдущий SHA-тег
docker compose -p gendesign-tradein -f docker-compose.prod.yml down
IMAGE_TAG=<previous-sha> docker compose -p gendesign-tradein -f docker-compose.prod.yml up -d
```