# 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= COOKIE_ENCRYPTION_KEY=<64-char hex> GENDESIGN_FDW_PASSWORD= GLITCHTIP_DSN= # DaData on-demand enrichment в /estimate flow (PR Q1). # Demo tier: 100 req/день. Пусто = enrichment disabled (graceful). # Регистрация ключей: https://dadata.ru/api/clean/ DADATA_API_TOKEN= DADATA_API_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://@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 </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= docker compose -p gendesign-tradein -f docker-compose.prod.yml up -d ```