# PostgreSQL Dev Cutover Этот runbook описывает безопасный перевод `dev`-окружения с SQLite на PostgreSQL без переноса старых данных. ## Что считается "без простоя" В этом проекте без переноса SQLite-данных безостановочный cutover означает не hot-swap одной и той же базы, а: 1. поднять новый PostgreSQL-backed stack параллельно; 2. прогнать smoke на новом stack; 3. переключить dev-трафик на новый gateway; 4. оставить старый SQLite stack живым до подтверждения GO; 5. при проблеме вернуть трафик обратно без восстановления данных. Если сейчас у dev только один instance и нет возможности держать parallel stack, нужен короткий maintenance window. ## Scope Включает: - подготовку PostgreSQL и RabbitMQ; - применение SQL migrations; - запуск сервисов в `SCHEMA_MANAGEMENT_MODE=migrations`; - smoke-проверки до и после переключения; - rollback на старый SQLite-backed dev stack. Не включает: - перенос данных из SQLite; - cleanup legacy SQLite-path; - production cutover. ## Required Inputs - `DEV_GATEWAY_OLD` - `DEV_GATEWAY_NEW` - `POSTGRES_DATABASE_URL` - `APP_TOKEN_SECRET` - `PUBLIC_SWITCH_METHOD` - DNS - reverse proxy - load balancer route - `RABBITMQ_URL` Рекомендуемые значения для локально-управляемого dev: - `POSTGRES_DATABASE_URL=postgresql://mvp:mvp@:5432/mvpcc` - `SCHEMA_MANAGEMENT_MODE=migrations` - env template: [\.env.postgres.local.template](/e:/Zhan/.env.postgres.local.template) ## Phase 0 - Preconditions Подтвердить перед началом: 1. Текущий SQLite-backed dev stack стабилен. 2. Перенос данных не нужен. 3. PostgreSQL доступен по сети с host, где запускаются сервисы. 4. RabbitMQ доступен по сети, если в dev нужен `EVENT_BUS_ENABLED=1`. 5. Новая dev-конфигурация использует: - `DATABASE_URL=postgresql://...` - `SCHEMA_MANAGEMENT_MODE=migrations` 6. Старый SQLite stack не останавливается до завершения smoke на новом stack. ## Phase 1 - Preflight На будущем PostgreSQL-backed dev host: 1. Проверить Python зависимости: ```powershell python -m pip install -r requirements.txt ``` 2. Подготовить env-файл: - скопировать [\.env.postgres.local.template](/e:/Zhan/.env.postgres.local.template) - заполнить `DATABASE_URL`, `APP_TOKEN_SECRET`, интеграционные URL и при необходимости AI/Telegram/WhatsApp переменные 3. Запустить DB-only preflight: ```powershell python scripts\postgres_dev_preflight.py --env-file .env.postgres.local.template ``` 4. Убедиться, что mode не legacy: ```text SCHEMA_MANAGEMENT_MODE=migrations ``` 5. Применить миграции в PostgreSQL: ```powershell python scripts\migrate_core_db.py ``` Ожидается: - миграции применились без ошибок; - в PostgreSQL появилась таблица `schema_migrations`; - сервисы ещё не стартовали. ## Phase 2 - Bring Up Parallel Stack Поднять новый stack параллельно старому. Если запуск локальный: ```powershell python scripts\local_stack.py start ` --runtime-dir .local_stack_pg ` --env-file .env.postgres.local.template ` --force-restart ``` Если это dev server / VM: 1. развернуть те же сервисы в отдельный deployment set; 2. прокинуть им: - `DATABASE_URL=postgresql://...` - `SCHEMA_MANAGEMENT_MODE=migrations` 3. не направлять внешний dev-трафик на новый gateway до завершения smoke. Важно: - новый stack должен использовать отдельный runtime/log directory; - старый SQLite-backed stack остаётся доступным; - нельзя смешивать новый dev-трафик со старым gateway до smoke. ## Phase 3 - Smoke Before Switch Выполнить проверки на `DEV_GATEWAY_NEW`. Сначала прогнать HTTP-aware preflight: ```powershell python scripts\postgres_dev_preflight.py ` --env-file .env.postgres.local.template ` --base-url http://127.0.0.1:8080 ``` 1. Health: ```powershell python scripts\live_smoke_gate12.py --base-url http:// --database-url ``` 2. Focused PostgreSQL smoke: ```powershell pytest -q tests/test_postgres_readiness.py ``` 3. Дополнительно проверить вручную: - `GET /proxy/auth/health` - `GET /proxy/interaction/health` - `GET /proxy/voice/health` - `GET /proxy/ai-voice-runtime/health` - открыть `http:///operator` 4. Если в dev включён event bus: - проверить подключение к RabbitMQ; - убедиться, что `event-bus-service` поднимается в `healthy`; - убедиться, что новые записи появляются в `event_outbox`. GO в следующую фазу только если: - health green; - smoke green; - новый stack не пытается auto-create schema на старте; - нет ошибок вида `run python scripts/migrate_core_db.py` после фактического применения миграций. ## Phase 4 - Traffic Switch Переключение выполняется только после успешного Phase 3. Рекомендуемый порядок: 1. уменьшить TTL у dev DNS / подготовить proxy route заранее; 2. переключить `DEV_GATEWAY` на `DEV_GATEWAY_NEW`; 3. не останавливать старый SQLite stack; 4. сразу после switch выполнить быстрый post-switch smoke. Примеры post-switch smoke: ```powershell python scripts\live_smoke_gate12.py --base-url http:// --database-url ``` Проверить руками: - логин; - создание interaction; - digital thread/message flow; - voice event ingest; - создание voice AI session. ## Phase 5 - Stabilization Window В течение первых 15-30 минут после switch: 1. наблюдать логи gateway и сервисов; 2. следить за ошибками подключения к PostgreSQL; 3. следить за ошибками `schema mismatch`; 4. следить за ошибками блокировок/unique conflict в voice transcript path; 5. сравнивать user-visible поведение со старым dev stack. Если всё стабильно: 1. объявить GO; 2. зафиксировать, что `dev` теперь PostgreSQL-backed; 3. оставить SQLite stack выключенным, но не удалённым до конца рабочего дня. ## Rollback Rollback делается только через возврат трафика на старый SQLite-backed stack. Триггеры rollback: - новый gateway не проходит smoke; - сервисы падают на startup; - критичный API path broken; - UI не работает; - ошибки подключения к PostgreSQL не устраняются быстро; - event bus / voice path деградирует. Шаги rollback: 1. вернуть `DEV_GATEWAY_PUBLIC` на `DEV_GATEWAY_OLD`; 2. убедиться, что старый SQLite stack всё ещё жив; 3. выполнить быстрый smoke на старом stack; 4. запретить новый трафик на PostgreSQL-backed stack; 5. собрать логи с нового stack. Rollback успешен, если: - dev UI снова открывается на старом gateway; - CRUD и smoke снова зелёные; - команда работает на старом dev без дополнительных действий. ## Cutover Sheet Перед cutover заполнить: - время старта; - кто выполняет switch; - `DEV_GATEWAY_OLD`; - `DEV_GATEWAY_NEW`; - `POSTGRES_DATABASE_URL`; - результат preflight; - результат smoke до switch; - время switch; - результат smoke после switch; - GO / ROLLBACK; - короткий список замечаний. ## Minimal Command Sequence Если нужен самый короткий practical path для dev: ```powershell python scripts\migrate_core_db.py python scripts\postgres_dev_preflight.py --env-file .env.postgres.local.template python scripts\local_stack.py start --runtime-dir .local_stack_pg --env-file .env.postgres.local.template --force-restart python scripts\postgres_dev_preflight.py --env-file .env.postgres.local.template --base-url http://127.0.0.1:8080 pytest -q tests/test_postgres_readiness.py python scripts\live_smoke_gate12.py --database-url postgresql://mvp:mvp@localhost:5432/mvpcc ``` После этого: 1. переключить dev gateway/public route на новый stack; 2. прогнать smoke ещё раз уже через публичный dev URL; 3. оставить старый SQLite stack как rollback target.