# Анализ рисков миграции на golang-migrate с baseline

## Критические риски

### 1. Потеря данных при неправильном применении baseline

**Риск**: При применении baseline миграции на существующую БД может произойти:
- Попытка создать уже существующие таблицы (ошибка)
- Потеря данных при DROP/CREATE операциях
- Конфликты с существующими данными

**Вероятность**: Средняя  
**Влияние**: Критическое

**Решения**:

1. **Обязательный backup перед применением**
   ```bash
   # Создать backup перед миграцией
   ./dump-db.sh --env-file .env baseline-migration-backup
   ```

2. **Использование `migrate force` вместо `migrate up` для существующих БД**
   ```bash
   # Для существующих БД - установить версию без применения
   migrate -path ./migrations -database "postgres://..." force 1
   ```

3. **Проверка существования таблиц в baseline миграции**
   - Использовать `CREATE TABLE IF NOT EXISTS` (но это не идеально для baseline)
   - Или создать скрипт проверки перед применением

4. **Тестирование на dev окружении**
   - Сначала применить на dev БД
   - Проверить целостность данных
   - Только потом применять на production

---

### 2. Ошибки в baseline миграции (неполная схема)

**Риск**: Baseline миграция может не включать:
- Некоторые таблицы или колонки
- Индексы или constraints
- Materialized views
- Начальные данные (словарь с id=0)
- Sequences с правильными значениями

**Вероятность**: Высокая  
**Влияние**: Критическое

**Решения**:

1. **Автоматическая проверка полноты схемы**
   ```bash
   # Создать скрипт для сравнения текущей схемы с baseline
   # Использовать pg_dump --schema-only для сравнения
   pg_dump --schema-only -h $DB_HOST -U $DB_USER -d $DB_NAME > current_schema.sql
   # Сравнить с baseline миграцией
   ```

2. **Пошаговая сборка baseline**
   - Собрать схему из всех init*DB функций
   - Добавить все миграции 012-029
   - Проверить через `pg_dump --schema-only` на актуальной БД

3. **Тестирование baseline на чистой БД**
   ```bash
   # Создать тестовую БД
   createdb test_baseline
   # Применить baseline
   migrate -path ./migrations -database "postgres://.../test_baseline" up
   # Сравнить схему с production
   ```

4. **Валидация через SQL проверки**
   - Добавить в baseline проверки существования всех таблиц
   - Использовать `DO $$ BEGIN ... END $$;` блоки для валидации

---

### 3. Проблемы с sequences и начальными данными

**Риск**: 
- Sequences могут быть не синхронизированы
- Начальные данные (словарь id=0) могут конфликтовать
- Автоинкременты могут начаться с неправильного значения

**Вероятность**: Средняя  
**Влияние**: Среднее

**Решения**:

1. **Правильная настройка sequences в baseline**
   ```sql
   -- После создания таблицы и вставки данных
   SELECT setval('dictionaries_id_seq', 
                 (SELECT MAX(id) FROM dictionaries), 
                 true);
   ```

2. **Использование ON CONFLICT для начальных данных**
   ```sql
   INSERT INTO dictionaries (id, name) 
   VALUES (0, 'Все слова')
   ON CONFLICT (id) DO NOTHING;
   ```

3. **Проверка sequences после baseline**
   ```sql
   -- Скрипт для проверки всех sequences
   SELECT schemaname, sequencename, last_value 
   FROM pg_sequences;
   ```

---

### 4. Проблемы с materialized views

**Риск**: 
- Materialized view может не создаться корректно
- Зависимости от таблиц могут быть нарушены
- Данные в MV могут быть неактуальными

**Вероятность**: Средняя  
**Влияние**: Среднее

**Решения**:

1. **Создание MV после всех таблиц**
   - Убедиться, что все таблицы созданы до создания MV
   - Использовать `DROP MATERIALIZED VIEW IF EXISTS` перед созданием

2. **Обновление данных после создания**
   ```sql
   -- После создания MV
   REFRESH MATERIALIZED VIEW weekly_report_mv;
   ```

3. **Проверка зависимостей**
   ```sql
   -- Проверить зависимости MV
   SELECT * FROM pg_depend 
   WHERE objid = 'weekly_report_mv'::regclass;
   ```

---

### 5. Конфликты версий миграций

**Риск**: 
- Таблица `schema_migrations` может быть в неправильном состоянии
- Версия может быть установлена неправильно
- Конфликт между старой и новой системой миграций

**Вероятность**: Средняя  
**Влияние**: Высокое

**Решения**:

1. **Проверка состояния schema_migrations перед применением**
   ```go
   // Проверить, существует ли таблица schema_migrations
   // Если да - проверить текущую версию
   var version uint
   err := db.QueryRow("SELECT version FROM schema_migrations LIMIT 1").Scan(&version)
   ```

2. **Очистка старой таблицы (если была)**
   ```sql
   -- Если была старая таблица миграций
   DROP TABLE IF EXISTS old_migrations_table;
   ```

3. **Использование `migrate force` только для существующих БД**
   - Новые БД должны использовать `migrate up`
   - Существующие БД - `migrate force 1`

---

### 6. Проблемы с окружениями (dev/prod различия)

**Риск**: 
- Различия в схемах между dev и prod
- Разные версии PostgreSQL
- Разные настройки БД

**Вероятность**: Средняя  
**Влияние**: Высокое

**Решения**:

1. **Проверка версии PostgreSQL**
   ```sql
   SELECT version();
   ```

2. **Тестирование на всех окружениях**
   - Dev окружение
   - Staging (если есть)
   - Production (после успешного тестирования)

3. **Документирование различий**
   - Зафиксировать версию PostgreSQL
   - Зафиксировать настройки БД

---

### 7. Проблемы с откатом (rollback)

**Риск**: 
- Baseline миграция не может быть откачена
- Ошибки при откате последующих миграций
- Потеря данных при откате

**Вероятность**: Низкая  
**Влияние**: Высокое

**Решения**:

1. **Baseline не откатывается (по дизайну)**
   - Пустой `000001_baseline.down.sql`
   - Документировать это ограничение

2. **Правильные down миграции для новых миграций**
   - Каждая новая миграция должна иметь корректный down файл
   - Тестировать откат на dev окружении

3. **Backup перед откатом**
   - Всегда создавать backup перед откатом
   - Особенно на production

---

### 8. Проблемы при старте приложения

**Риск**: 
- Миграции могут не примениться при старте
- Ошибки подключения к БД во время миграций
- Таймауты при применении миграций

**Вероятность**: Средняя  
**Влияние**: Высокое

**Решения**:

1. **Обработка ошибок миграций**
   ```go
   m, err := migrate.NewWithDatabaseInstance(
       "file://migrations",
       "postgres", driver)
   if err != nil {
       log.Fatal("Failed to initialize migrations:", err)
   }
   
   if err := m.Up(); err != nil {
       if err != migrate.ErrNoChange {
           log.Fatal("Failed to apply migrations:", err)
       }
       log.Println("Database is up to date")
   }
   ```

2. **Retry логика для подключения к БД**
   - Уже есть в коде (10 попыток)
   - Применить перед миграциями

3. **Таймауты для миграций**
   ```go
   // Установить таймаут для миграций
   ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
   defer cancel()
   ```

4. **Логирование процесса миграций**
   - Логировать каждую применяемую миграцию
   - Логировать ошибки с деталями

---

### 9. Проблемы с Docker и путями к миграциям

**Риск**: 
- Миграции могут не найтись в контейнере
- Неправильные пути к файлам миграций
- Проблемы с правами доступа

**Вероятность**: Низкая  
**Влияние**: Среднее

**Решения**:

1. **Проверка путей в Dockerfile**
   ```dockerfile
   # Убедиться, что миграции копируются
   COPY play-life-backend/migrations /migrations
   ```

2. **Использование абсолютных путей**
   ```go
   migrationsPath := "/migrations"
   if _, err := os.Stat(migrationsPath); os.IsNotExist(err) {
       // Fallback для локальной разработки
       migrationsPath = "play-life-backend/migrations"
   }
   ```

3. **Проверка доступности миграций при старте**
   ```go
   // Проверить, что папка миграций существует
   if _, err := os.Stat(migrationsPath); os.IsNotExist(err) {
       log.Fatal("Migrations directory not found:", migrationsPath)
   }
   ```

---

### 10. Проблемы с параллельным доступом

**Риск**: 
- Несколько инстансов приложения могут пытаться применить миграции одновременно
- Конфликты при применении миграций

**Вероятность**: Низкая  
**Влияние**: Высокое

**Решения**:

1. **Блокировки на уровне БД**
   - golang-migrate использует транзакции
   - PostgreSQL блокирует таблицу schema_migrations

2. **Применение миграций только в одном инстансе**
   - Использовать флаг `--migrate` для запуска миграций
   - Или применять миграции отдельным процессом

3. **Проверка версии перед применением**
   ```go
   version, dirty, err := m.Version()
   if dirty {
       log.Fatal("Database is in dirty state, manual intervention required")
   }
   ```

---

## План митигации рисков

### Этап 1: Подготовка (до применения baseline)

1. ✅ Создать backup всех БД (dev, staging, prod)
2. ✅ Собрать полную схему через `pg_dump --schema-only`
3. ✅ Создать baseline миграцию на основе схемы
4. ✅ Протестировать baseline на чистой БД
5. ✅ Сравнить схему после baseline с текущей схемой

### Этап 2: Тестирование (на dev окружении)

1. ✅ Применить baseline через `migrate force 1`
2. ✅ Проверить целостность данных
3. ✅ Проверить работу приложения
4. ✅ Проверить sequences и начальные данные
5. ✅ Проверить materialized views

### Этап 3: Применение (на production)

1. ✅ Создать backup production БД
2. ✅ Применить baseline через `migrate force 1`
3. ✅ Проверить работу приложения
4. ✅ Мониторинг в течение первых часов

### Этап 4: Мониторинг (после применения)

1. ✅ Проверить логи приложения
2. ✅ Проверить ошибки БД
3. ✅ Проверить производительность
4. ✅ Собрать обратную связь от пользователей

---

## Чеклист перед применением baseline

- [ ] Backup всех БД создан и проверен
- [ ] Baseline миграция протестирована на чистой БД
- [ ] Схема после baseline совпадает с текущей схемой
- [ ] Тестирование на dev окружении успешно
- [ ] Инструкции по применению baseline готовы
- [ ] Команда проинформирована о миграции
- [ ] Окно для миграции запланировано (для production)
- [ ] План отката подготовлен (если что-то пойдет не так)

---

## Скрипты для проверки

### Скрипт проверки схемы

```bash
#!/bin/bash
# check_schema.sh - Проверка полноты baseline миграции

DB_HOST=${DB_HOST:-localhost}
DB_PORT=${DB_PORT:-5432}
DB_USER=${DB_USER:-playeng}
DB_PASSWORD=${DB_PASSWORD:-playeng}
DB_NAME=${DB_NAME:-playeng}

echo "Проверка схемы БД..."

# Получить список всех таблиц
PGPASSWORD="$DB_PASSWORD" psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" -t -c "
SELECT tablename 
FROM pg_tables 
WHERE schemaname = 'public'
ORDER BY tablename;
" > current_tables.txt

echo "Таблицы в БД сохранены в current_tables.txt"
echo "Сравните с таблицами в baseline миграции"
```

### Скрипт применения baseline

```bash
#!/bin/bash
# apply_baseline.sh - Безопасное применение baseline

set -e

DB_HOST=${DB_HOST:-localhost}
DB_PORT=${DB_PORT:-5432}
DB_USER=${DB_USER:-playeng}
DB_PASSWORD=${DB_PASSWORD:-playeng}
DB_NAME=${DB_NAME:-playeng}

DATABASE_URL="postgres://$DB_USER:$DB_PASSWORD@$DB_HOST:$DB_PORT/$DB_NAME?sslmode=disable"

echo "⚠️  ВНИМАНИЕ: Это применит baseline миграцию!"
echo "База данных: $DB_NAME"
echo "Хост: $DB_HOST:$DB_PORT"
read -p "Вы уверены? (yes/no): " confirm

if [ "$confirm" != "yes" ]; then
    echo "Отменено"
    exit 1
fi

# Создать backup
echo "Создание backup..."
./dump-db.sh --env-file .env baseline-backup-$(date +%Y%m%d_%H%M%S)

# Применить baseline
echo "Применение baseline..."
migrate -path ./play-life-backend/migrations -database "$DATABASE_URL" force 1

echo "✅ Baseline применен успешно"
echo "Проверьте работу приложения"
```
