Перейти к содержанию

Database Migrations Guide

Краткое руководство по работе с миграциями PostgreSQL в Saga.

Основные принципы

  • НИКОГДА не изменяй схему БД вручную
  • ВСЕГДА создавай миграции для изменений
  • ОБРАТИМЫЕ миграции (up/down файлы)
  • ТЕСТИРУЙ на копии production данных

Quick Commands

# Применить все миграции
make migration-up

# Откатить последнюю миграцию  
make migration-down

# Проверить статус миграций
PGPASSWORD=aisee psql -U aisee -h 127.0.0.1 -d saga -c "SELECT version, dirty FROM schema_migrations"

Текущая схема

Консолидированная миграция

  • 000001_consolidated_schema.up.sql - единая схема (429 строк)
  • Все предыдущие миграции архивированы в archive_20250716_153531/

Основные таблицы

users              # Пользователи (БЕЗ wallet_address)
wallets            # Кошельки с network_id INTEGER
transactions       # Все финансовые операции (единый источник истины для балансов)
investments        # Инвестиционные позиции

Создание новой миграции

1. Планирование

  • Определи изменения: новые таблицы, колонки, индексы
  • Проверь совместимость с существующими данными
  • Спланируй rollback стратегию

2. Создание файлов

# Создать новую миграцию
make migration-create name=add_user_preferences

# Это создаст:
# 000004_add_user_preferences.up.sql
# 000004_add_user_preferences.down.sql

3. Написание миграций

UP миграция (000004_add_user_preferences.up.sql):

-- Добавление новой таблицы
CREATE TABLE user_preferences (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    preferences JSONB NOT NULL DEFAULT '{}',
    created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
);

-- Индекс для быстрого поиска
CREATE INDEX idx_user_preferences_user_id ON user_preferences(user_id);

-- Комментарии
COMMENT ON TABLE user_preferences IS 'Пользовательские настройки и предпочтения';

DOWN миграция (000004_add_user_preferences.down.sql):

-- Откат в обратном порядке
DROP INDEX IF EXISTS idx_user_preferences_user_id;
DROP TABLE IF EXISTS user_preferences;

Best Practices

Безопасные операции

  • ADD COLUMN с DEFAULT значениями
  • CREATE INDEX CONCURRENTLY для больших таблиц
  • ADD CONSTRAINT для новых данных

Опасные операции

  • DROP COLUMN - потеря данных
  • ALTER COLUMN TYPE - может блокировать таблицу
  • DROP TABLE - необратимо

Шаблон безопасной миграции

-- Добавление колонки с DEFAULT
ALTER TABLE users ADD COLUMN phone VARCHAR(20) DEFAULT '';

-- Обновление существующих данных (если нужно)
UPDATE users SET phone = '' WHERE phone IS NULL;

-- Добавление NOT NULL constraint (после заполнения данных)
ALTER TABLE users ALTER COLUMN phone SET NOT NULL;

Тестирование миграций

Локальное тестирование

# 1. Создать backup тестовой БД
pg_dump -U aisee -h 127.0.0.1 saga > backup_before_migration.sql

# 2. Применить миграцию
make migration-up

# 3. Проверить что всё работает
make test-smoke

# 4. Откатить (если проблемы)
make migration-down

# 5. Восстановить из backup (если критично)
dropdb -U aisee -h 127.0.0.1 saga
createdb -U aisee -h 127.0.0.1 saga
psql -U aisee -h 127.0.0.1 saga < backup_before_migration.sql

Production чек-лист

  • Миграция протестирована на копии production данных
  • Rollback процедура проверена
  • Backup создан перед миграцией
  • Downtime запланирован (если нужен)
  • Мониторинг настроен

Troubleshooting

"Migration failed: table already exists"

# Проверить текущее состояние
PGPASSWORD=aisee psql -U aisee -h 127.0.0.1 -d saga -c "\dt"

# Пометить миграцию как примененную (осторожно!)
PGPASSWORD=aisee psql -U aisee -h 127.0.0.1 -d saga -c "INSERT INTO schema_migrations (version, dirty) VALUES (4, false)"

"Migration stuck in dirty state"

# Очистить dirty состояние (ОСТОРОЖНО!)
PGPASSWORD=aisee psql -U aisee -h 127.0.0.1 -d saga -c "UPDATE schema_migrations SET dirty = false WHERE version = 4"

# Затем попробовать снова
make migration-down

Production миграция не применяется

  1. Проверь схему production БД
  2. Создай промежуточные миграции для приведения к консистентному состоянию
  3. НЕ форсируй миграцию - это может сломать production

Схема миграций

storage/migrations/
├── 000001_consolidated_schema.up.sql     # Основная схема
├── 000001_consolidated_schema.down.sql   # Откат основной схемы
├── 000002_add_deleted_at.up.sql          # Soft delete
├── 000003_drop_withdrawals.up.sql        # Удаление таблицы withdrawals
└── archive_20250716_153531/              # Архив старых миграций

Золотое правило: Лучше создать лишнюю миграцию, чем сломать production БД ручными изменениями.

Связанные документы

Исправления и примеры: - Template Database Schema Fix (2025-10-02) - Исправление template базы данных для изолированного тестирования (gen_random_uuid DEFAULT)