feat: staging-окружение (Docker Compose + Caddy + deploy-script)

docker-compose.staging.yml — backend-staging на порту 8001.
.env.staging.example — шаблон с отдельным SHEET_ID.
Caddyfile.staging.snippet — staging.api.wasrusgen1.pro.
scripts/deploy-staging.sh — один скрипт для деплоя staging.
app.js: BACKEND_URL читается из ?backend= параметра URL.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
wasrusgen 2026-05-18 14:22:01 +03:00
parent 6616d48c0a
commit ea04e042df
5 changed files with 152 additions and 1 deletions

View File

@ -0,0 +1,36 @@
# ============================================================
# Staging-окружение. Скопируйте в .env.staging и заполните.
# Используется только docker-compose.staging.yml.
# Не коммитить!
# ============================================================
# Telegram bot — тот же (бот не запускается в staging, токен нужен для валидации initData)
BOT_TOKEN=8281503057:AAEXmOepY8quH8E3RqOjFbgn7owV1ngnbGA
ADMIN_TG_ID=5937498515
# GigaChat — те же ключи
GIGACHAT_AUTH_KEY=ЗАМЕНИТЕ
GIGACHAT_MODEL=GigaChat-Pro
GIGACHAT_SCOPE=GIGACHAT_API_PERS
# STAGING Google Sheet — ОТДЕЛЬНАЯ копия продакшн-таблицы!
# Создать: открыть продакшн таблицу → Файл → Создать копию
SHEET_ID=ЗАМЕНИТЕ_ID_ТЕСТОВОЙ_ТАБЛИЦЫ
GOOGLE_CREDENTIALS_PATH=/app/credentials.json
# MiniApp — staging URL с параметром backend
MINIAPP_URL=https://wasrusgen.github.io/zov-tech/?backend=https://staging.api.wasrusgen1.pro
# Внутренний URL бэкенда (только в staging compose, без бота)
BACKEND_URL=http://backend-staging:8000
# Бизнес-правила (можно оставить как в prod)
ACTIVE_PERIOD_DAYS=90
GRACE_PERIOD_DAYS=14
# Внутренний секрет
INTERNAL_SECRET=ЗАМЕНИТЕ_ИЛИ_ОСТАВЬТЕ_КАК_В_PROD
# Google Drive — можно оставить prod файлы (только чтение)
SHIPMENTS_FILE_ID=1fER4NmEgSznvPKJWXOqLDDkTxH6wm78E
ARRIVALS_FILE_ID=1kgrDEIGcVMFnSdZs1Y_QHVhjqsXFQk2h

View File

@ -0,0 +1,24 @@
# Staging backend добавить в основной Caddyfile.
# После добавления: sudo systemctl reload caddy
#
# Убедиться что DNS: staging.api.wasrusgen1.pro IP этого VPS
staging.api.wasrusgen1.pro {
reverse_proxy localhost:8001
encode zstd gzip
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains"
X-Content-Type-Options "nosniff"
Referrer-Policy "strict-origin-when-cross-origin"
-Server
# Помечаем staging-ответы
X-Environment "staging"
}
log {
output file /data/zov-staging-access.log {
roll_size 5mb
roll_keep 3
}
}
}

View File

@ -0,0 +1,41 @@
# Staging-окружение — только backend, без бота и тоннеля.
# Использует отдельный .env.staging с тестовым SHEET_ID.
#
# Запуск:
# docker compose -f docker-compose.staging.yml --env-file .env.staging up -d --build
# Остановка:
# docker compose -f docker-compose.staging.yml down
services:
backend-staging:
build:
context: ../backend-py
dockerfile: Dockerfile
image: zov-tech-backend:staging
container_name: zov-backend-staging
restart: unless-stopped
env_file:
- .env.staging
environment:
- STAGING=true
volumes:
- ./credentials.json:/app/credentials.json:ro
- ./photos-staging:/app/photos
networks:
- web
- internal-staging
ports:
- "127.0.0.1:8001:8000"
healthcheck:
test: ["CMD", "python", "-c", "import urllib.request,sys; r=urllib.request.urlopen('http://127.0.0.1:8000/healthz', timeout=3); sys.exit(0 if r.status==200 else 1)"]
interval: 30s
timeout: 5s
retries: 3
start_period: 15s
networks:
web:
name: deploy_web
external: true
internal-staging:
driver: bridge

View File

@ -5,7 +5,9 @@
const tg = window.Telegram?.WebApp; const tg = window.Telegram?.WebApp;
// Cloudflare Quick Tunnel → VPS FastAPI backend (GigaChat). // Cloudflare Quick Tunnel → VPS FastAPI backend (GigaChat).
// Временный URL — пока wasrusgen1.pro в verification-hold; затем переключим на https://api.wasrusgen1.pro // Временный URL — пока wasrusgen1.pro в verification-hold; затем переключим на https://api.wasrusgen1.pro
const BACKEND_URL = "https://api.wasrusgen1.pro"; // Позволяет переключить бэкенд через ?backend=https://staging.api.wasrusgen1.pro
const BACKEND_URL = new URLSearchParams(window.location.search).get("backend")
|| "https://api.wasrusgen1.pro";
const app = document.getElementById("app"); const app = document.getElementById("app");

48
scripts/deploy-staging.sh Normal file
View File

@ -0,0 +1,48 @@
#!/bin/bash
# Деплой staging-бэкенда на VPS.
# Использует docker-compose.staging.yml + .env.staging
#
# Запуск: bash scripts/deploy-staging.sh
# Требует: SSH-ключ ~/.ssh/zov_vps_ed25519, .env.staging на VPS
set -e
VPS="root@94.241.170.144"
SSH="ssh -i $HOME/.ssh/zov_vps_ed25519"
REMOTE_DIR="/opt/zov-tech"
echo "🚀 Деплой STAGING → $VPS"
# 1. Синхронизируем код
echo " [1/3] git pull на VPS..."
$SSH $VPS "cd $REMOTE_DIR && git pull origin master"
# 2. Проверяем .env.staging
echo " [2/3] Проверка .env.staging..."
$SSH $VPS "
if [ ! -f $REMOTE_DIR/deploy/.env.staging ]; then
echo 'ERROR: .env.staging не найден!'
echo 'Скопируйте deploy/.env.staging.example → deploy/.env.staging и заполните.'
exit 1
fi
if grep -q 'ЗАМЕНИТЕ' $REMOTE_DIR/deploy/.env.staging; then
echo 'ERROR: .env.staging содержит незаполненные поля (ЗАМЕНИТЕ)!'
exit 1
fi
echo 'OK'
"
# 3. Пересобираем и запускаем
echo " [3/3] docker compose up --build..."
$SSH $VPS "
cd $REMOTE_DIR/deploy
docker compose -f docker-compose.staging.yml --env-file .env.staging up -d --build
"
echo ""
echo "✅ Staging задеплоен!"
echo " Backend: https://staging.api.wasrusgen1.pro/healthz"
echo " MiniApp: https://wasrusgen.github.io/zov-tech/?backend=https://staging.api.wasrusgen1.pro"
echo ""
echo "🧪 Запуск smoke-тестов против staging:"
echo " SMOKE_URL='https://wasrusgen.github.io/zov-tech/?backend=https://staging.api.wasrusgen1.pro' node tests/ui_smoke.js"