🗃️ Структура базы данных

Назад к списку Редактировать
Информация
Slug:
database.html
Обновлено:
30.05.2026 15:03
Размер:
20.81 KB
Путь:
/resources/docs/developer/database.html
Ссылки
Публичная ссылка:
Ссылка в админке:
🗃️ Структура базы данных

Общая схема

        ┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
        │    currencies   │────▶│ exchange_rates  │◀────│  external_rates │
        └─────────────────┘     └─────────────────┘     └─────────────────┘
               │                         │                         │
               │                         │                         │
               ▼                         ▼                         │
        ┌─────────────────┐     ┌─────────────────┐                │
        │      cities     │◀────│    partners     │────────────────┘
        └─────────────────┘     └─────────────────┘
               │                         │
               │                         │
               ▼                         ▼
        ┌─────────────────┐     ┌─────────────────┐
        │ exchange_orders │◀────│      users      │
        └─────────────────┘     └─────────────────┘
               │
               │
               ▼
        ┌─────────────────┐     ┌─────────────────┐
        │   user_wallets  │     │     admins      │
        └─────────────────┘     └─────────────────┘
                                        │
                                        ▼
                               ┌─────────────────┐
                               │    settings     │
                               └─────────────────┘
        

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

currencies (Валюты)

CREATE TABLE currencies (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    code VARCHAR(10) UNIQUE,
    name VARCHAR(255),
    symbol VARCHAR(10),
    type ENUM('crypto', 'fiat', 'token') DEFAULT 'crypto',

    -- Настройки для USDT
    usdt_to_other_crypto_margin DECIMAL(5,2) NULL,
    usdt_to_other_crypto_min_amount DECIMAL(20,8) NULL,
    usdt_to_rub_margin DECIMAL(5,2) NULL,
    usdt_to_rub_min_amount DECIMAL(20,8) NULL,

    -- Настройки для RUB
    rub_to_usdt_margin DECIMAL(5,2) NULL,
    rub_to_usdt_min_amount DECIMAL(20,8) NULL,
    rub_to_other_crypto_margin DECIMAL(5,2) NULL,
    rub_to_other_crypto_min_amount DECIMAL(20,8) NULL,

    -- Настройки для других крипто
    other_crypto_to_rub_margin DECIMAL(5,2) NULL,
    other_crypto_to_rub_min_amount DECIMAL(20,8) NULL,
    other_crypto_to_other_crypto_margin DECIMAL(5,2) NULL,
    other_crypto_to_other_crypto_min_amount DECIMAL(20,8) NULL,

    -- Кошельки
    our_wallet VARCHAR(500) NULL,
    wallet_for_other_currencies BOOLEAN DEFAULT false,

    -- Метаданные
    icon VARCHAR(255) NULL,
    is_active BOOLEAN DEFAULT true,
    sort_order INT DEFAULT 0,
    created_at TIMESTAMP,
    updated_at TIMESTAMP
);

exchange_orders (Заявки на обмен)

CREATE TABLE exchange_orders (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    order_number VARCHAR(50) UNIQUE,
    user_id BIGINT UNSIGNED NULL,
    from_currency_id BIGINT UNSIGNED,
    to_currency_id BIGINT UNSIGNED,
    partner_id BIGINT UNSIGNED NULL,
    city_id BIGINT UNSIGNED,

    -- Финансовые данные
    amount DECIMAL(20,8),
    rate DECIMAL(20,8),
    fee_amount DECIMAL(20,8) DEFAULT 0,
    total_receive DECIMAL(20,8),
    fee_percentage DECIMAL(5,2) DEFAULT 0,

    -- Информация о клиенте
    full_name VARCHAR(255),
    email VARCHAR(255),
    phone VARCHAR(50),
    wallet_address VARCHAR(500) NULL,

    -- Статус
    status ENUM('pending', 'confirmed', 'processing', 'completed', 'cancelled', 'rejected') DEFAULT 'pending',
    transaction_type VARCHAR(100) NULL COMMENT 'Тип транзакции',

    -- Верификация
    verification_code CHAR(6) NULL,
    verification_token CHAR(64) NULL,
    verified_at TIMESTAMP NULL,
    expires_at TIMESTAMP NULL,

    -- Метаданные
    admin_notes TEXT NULL,
    user_notes TEXT NULL,
    ip_address VARCHAR(45) NULL,
    user_agent TEXT NULL,
    created_at TIMESTAMP,
    updated_at TIMESTAMP,

    -- Индексы
    INDEX orders_status_created (status, created_at),
    INDEX orders_order_number (order_number),
    INDEX orders_transaction_type (transaction_type),

    -- Внешние ключи
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE RESTRICT,
    FOREIGN KEY (from_currency_id) REFERENCES currencies(id) ON DELETE RESTRICT,
    FOREIGN KEY (to_currency_id) REFERENCES currencies(id) ON DELETE RESTRICT,
    FOREIGN KEY (partner_id) REFERENCES partners(id) ON DELETE RESTRICT,
    FOREIGN KEY (city_id) REFERENCES cities(id) ON DELETE RESTRICT
);

partners (Партнеры)

CREATE TABLE partners (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    city_id BIGINT UNSIGNED,
    name VARCHAR(255),
    address TEXT,
    phone VARCHAR(50),
    email VARCHAR(255),

    -- Геолокация
    latitude DECIMAL(10,7) NULL,
    longitude DECIMAL(10,7) NULL,

    -- Информация
    working_hours VARCHAR(255),
    description TEXT NULL,
    accepted_currencies JSON NULL,

    -- API интеграция
    api_id BIGINT UNSIGNED NULL COMMENT 'ID API конфигурации',

    -- Рейтинг
    rating DECIMAL(3,2) DEFAULT 0,
    total_reviews INT DEFAULT 0,

    -- Статус
    is_active BOOLEAN DEFAULT true,
    created_at TIMESTAMP,
    updated_at TIMESTAMP,

    -- Внешние ключи
    FOREIGN KEY (city_id) REFERENCES cities(id) ON DELETE RESTRICT,
    FOREIGN KEY (api_id) REFERENCES exchange_apis(id) ON DELETE SET NULL
);

exchange_rates (Курсы обмена)

CREATE TABLE exchange_rates (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    partner_id BIGINT UNSIGNED NULL,
    from_currency_id BIGINT UNSIGNED,
    to_currency_id BIGINT UNSIGNED,
    external_rate_id BIGINT UNSIGNED NULL,

    -- Курсы
    rate DECIMAL(20,8) NULL,
    use_external_rate BOOLEAN DEFAULT false,
    use_partner_external BOOLEAN DEFAULT false,
    manual_margin_percentage DECIMAL(5,2) NULL COMMENT 'Ручная наценка',

    -- Переопределения
    override_margin DECIMAL(5,2) NULL,
    override_min_amount DECIMAL(20,8) NULL,
    partner_external_margin DECIMAL(5,2) NULL,

    -- Лимиты
    min_amount DECIMAL(20,8) DEFAULT 0,
    max_amount DECIMAL(20,8) DEFAULT 0,

    -- Метаданные
    description TEXT NULL,
    is_active BOOLEAN DEFAULT true,
    is_hidden BOOLEAN DEFAULT false,
    priority INT DEFAULT 0,
    last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    created_at TIMESTAMP,
    updated_at TIMESTAMP,

    -- Уникальный индекс
    UNIQUE partner_currency_pair_unique (partner_id, from_currency_id, to_currency_id),

    -- Внешние ключи
    FOREIGN KEY (partner_id) REFERENCES partners(id) ON DELETE CASCADE,
    FOREIGN KEY (from_currency_id) REFERENCES currencies(id) ON DELETE RESTRICT,
    FOREIGN KEY (to_currency_id) REFERENCES currencies(id) ON DELETE RESTRICT,
    FOREIGN KEY (external_rate_id) REFERENCES external_rates(id) ON DELETE SET NULL
);

external_rates (Внешние курсы)

CREATE TABLE external_rates (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    partner_id BIGINT UNSIGNED NULL,
    from_currency_id BIGINT UNSIGNED,
    to_currency_id BIGINT UNSIGNED,
    external_rate DECIMAL(20,8),
    source VARCHAR(100) DEFAULT 'rapira.net',
    last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

    -- Стакан заявок
    order_book_buy JSON NULL,
    order_book_sell JSON NULL,

    -- Рыночные данные
    volume_24h DECIMAL(20,2) NULL,
    change_24h DECIMAL(8,2) NULL,
    bid_price DECIMAL(20,8) NULL,
    ask_price DECIMAL(20,8) NULL,
    bid_volume DECIMAL(20,8) NULL,
    ask_volume DECIMAL(20,8) NULL,
    spread DECIMAL(20,8) NULL,

    created_at TIMESTAMP,
    updated_at TIMESTAMP,

    -- Внешние ключи
    FOREIGN KEY (partner_id) REFERENCES partners(id) ON DELETE CASCADE,
    FOREIGN KEY (from_currency_id) REFERENCES currencies(id) ON DELETE CASCADE,
    FOREIGN KEY (to_currency_id) REFERENCES currencies(id) ON DELETE CASCADE,

    -- Индексы
    UNIQUE external_rates_unique_pair (from_currency_id, to_currency_id, partner_id),
    INDEX ext_rates_currency_pair_updated (from_currency_id, to_currency_id, last_updated)
);

exchange_apis (API конфигурации)

CREATE TABLE exchange_apis (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255),
    base_url VARCHAR(500),
    endpoint VARCHAR(255) DEFAULT '/',
    method VARCHAR(10) DEFAULT 'GET',

    -- Форматы
    request_format VARCHAR(50) DEFAULT 'json',
    response_format VARCHAR(50) DEFAULT 'json',
    field_mapping JSON NULL,
    pair_format JSON NULL,

    -- Аутентификация
    authentication_type VARCHAR(50) DEFAULT 'none',
    api_key TEXT NULL,
    secret_key TEXT NULL,

    -- Настройки
    is_active BOOLEAN DEFAULT true,
    priority INT DEFAULT 0,
    timeout INT DEFAULT 30,
    retry_count INT DEFAULT 3,
    description TEXT NULL,
    test_data JSON NULL,

    -- Статистика
    success_count INT DEFAULT 0,
    error_count INT DEFAULT 0,
    last_success_at TIMESTAMP NULL,
    last_error_at TIMESTAMP NULL,
    last_error_message TEXT NULL,

    created_at TIMESTAMP,
    updated_at TIMESTAMP,

    -- Индексы
    INDEX exchange_apis_active_priority (is_active, priority),
    INDEX last_success_at (last_success_at)
);

admins (Администраторы)

CREATE TABLE admins (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255),
    email VARCHAR(255) UNIQUE,
    email_verified_at TIMESTAMP NULL,
    password VARCHAR(255),

    -- Роли и права
    role VARCHAR(50) DEFAULT 'admin',
    permissions JSON NULL,

    -- Статус
    is_active BOOLEAN DEFAULT true,
    remember_token VARCHAR(100) NULL,

    created_at TIMESTAMP,
    updated_at TIMESTAMP
);

settings (Настройки)

CREATE TABLE settings (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    key VARCHAR(255) UNIQUE,
    value TEXT NULL,
    type VARCHAR(50) DEFAULT 'text',
    group VARCHAR(50) DEFAULT 'general',
    options TEXT NULL,

    -- API настройки
    default_cron_api_id BIGINT UNSIGNED NULL,
    default_cron_api_name VARCHAR(255) NULL,
    update_interval_minutes INT DEFAULT 10,
    auto_update_enabled BOOLEAN DEFAULT true,
    primary_api_id BIGINT UNSIGNED NULL,
    fallback_api_id BIGINT UNSIGNED NULL,

    -- Настройки заявок
    order_expire_minutes INT DEFAULT 1440,
    auto_confirm_orders BOOLEAN DEFAULT false,
    require_verification BOOLEAN DEFAULT true,

    -- Локализация
    site_timezone VARCHAR(50) DEFAULT 'Europe/Moscow',
    date_format VARCHAR(20) DEFAULT 'd.m.Y',

    created_at TIMESTAMP,
    updated_at TIMESTAMP
);

cities (Города)

CREATE TABLE cities (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255),
    country VARCHAR(255),
    latitude DECIMAL(10,7) NULL,
    longitude DECIMAL(10,7) NULL,
    is_active BOOLEAN DEFAULT true,
    sort_order INT DEFAULT 0,
    created_at TIMESTAMP,
    updated_at TIMESTAMP
);

users (Пользователи)

-- Модификация стандартной таблицы users
ALTER TABLE users ADD COLUMN IF NOT EXISTS (
    role VARCHAR(50) DEFAULT 'user',
    is_active BOOLEAN DEFAULT true,
    phone VARCHAR(50) NULL,
    avatar VARCHAR(255) NULL,
    telegram VARCHAR(255) NULL,
    email_verified_at TIMESTAMP NULL,
    email_verification_token VARCHAR(64) NULL,
    verification_sent_at TIMESTAMP NULL
);

user_wallets (Кошельки пользователей)

CREATE TABLE user_wallets (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    user_id BIGINT UNSIGNED,
    currency_id BIGINT UNSIGNED,
    wallet_address VARCHAR(500),
    network VARCHAR(50) NULL,
    wallet_name VARCHAR(100) NULL,
    is_default BOOLEAN DEFAULT false,
    is_active BOOLEAN DEFAULT true,
    notes TEXT NULL,
    created_at TIMESTAMP,
    updated_at TIMESTAMP,

    -- Внешние ключи
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
    FOREIGN KEY (currency_id) REFERENCES currencies(id) ON DELETE RESTRICT,

    -- Уникальный индекс
    UNIQUE user_currency_wallet_unique (user_id, currency_id, wallet_address)
);

pages (Страницы сайта)

CREATE TABLE pages (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    slug VARCHAR(255) UNIQUE,
    title VARCHAR(255),
    content TEXT,
    meta_title VARCHAR(255) NULL,
    meta_description VARCHAR(255) NULL,
    meta_keywords VARCHAR(255) NULL,
    is_active BOOLEAN DEFAULT true,
    sort_order INT DEFAULT 0,
    created_at TIMESTAMP,
    updated_at TIMESTAMP,

    -- Индексы
    INDEX pages_active_sort (is_active, sort_order),
    INDEX pages_slug (slug)
);

Связи таблиц

  • Валюта ↔ Курсы обмена: Одна валюта может быть в многих курсах
  • Город ↔ Партнеры: Один город имеет много партнеров
  • Партнер ↔ Заявки: Партнер обрабатывает много заявок
  • API ↔ Внешние курсы: API источник для многих курсов
  • Пользователь ↔ Кошельки: У пользователя может быть несколько кошельков
  • Пользователь ↔ Заявки: Пользователь создает заявки
  • Внешние курсы ↔ Курсы обмена: Внешние курсы используются в курсах обмена

Миграции

Основная миграция

Файл: 2026_01_18_000000_create_dexa_database.php

Создает все основные таблицы системы. Порядок создания важен из-за внешних ключей.

Миграция сессий админа

Файл: 2026_02_06_163437_create_admin_sessions_table.php

Создает отдельную таблицу для сессий администраторов.

Индексы и оптимизация

Критические индексы

  • exchange_orders: (status, created_at) - фильтрация заявок
  • external_rates: (from_currency_id, to_currency_id, last_updated) - поиск актуальных курсов
  • exchange_apis: (is_active, priority) - выбор активных API
  • pages: (is_active, sort_order) - отображение страниц

Уникальные ограничения

  • currencies.code: Уникальный код валюты
  • exchange_rates: Уникальная пара (partner_id, from_currency_id, to_currency_id)
  • external_rates: Уникальная пара с партнером
  • user_wallets: Уникальный кошелек пользователя для валюты

Типы данных

Денежные значения

  • DECIMAL(20,8): Для криптовалют (8 знаков после запятой)
  • DECIMAL(10,2): Для фиатных валют (2 знака)
  • DECIMAL(5,2): Для процентов и наценок

JSON поля

  • accepted_currencies: Массив ID валют партнера
  • field_mapping: Конфигурация маппинга API
  • permissions: Права доступа администратора
  • order_book_buy/sell: Данные стакана заявок

Рекомендации по производительности

Для больших таблиц

  • Регулярно архивируйте старые заявки (> 6 месяцев)
  • Используйте партиционирование для exchange_orders по дате
  • Очищайте внешние курсы старше 7 дней
  • Оптимизируйте индексы под частые запросы

Оптимизация запросов

-- Вместо N+1 запросов использовать жадную загрузку
$orders = ExchangeOrder::with(['fromCurrency', 'toCurrency', 'city', 'partner'])
    ->where('status', 'completed')
    ->get();

-- Использовать chunk для больших данных
ExchangeOrder::where('created_at', '<', now()->subMonths(6))
    ->chunk(1000, function ($orders) {
        // обработка
    });

Резервное копирование

Рекомендуемый schedule

# Ежедневный полный бэкап
0 2 * * * mysqldump -u user -p password dexa > /backups/dexa_$(date +\%Y\%m\%d).sql

# Еженедельное ротирование
0 3 * * 0 find /backups -name "*.sql" -mtime +30 -delete

# Репликация в реальном времени (рекомендуется)
-- Настройте master-slave репликацию для продакшена

Миграция данных

При обновлении схемы

  1. Создайте бэкап базы данных
  2. Запустите миграции в тестовом окружении
  3. Проверьте целостность данных
  4. Запустите в продакшене во время минимальной нагрузки
  5. Имейте план отката

Важно: Все изменения схемы должны быть через миграции Laravel. Никогда не изменяйте базу напрямую в продакшене.

Последнее обновление: 30.05.2026 в 15:03
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot;&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
    &lt;title&gt;🗃️ Структура базы данных&lt;/title&gt;
    &lt;style&gt;
        body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; padding: 20px; max-width: 1200px; margin: 0 auto; }
        h1 { color: #2c3e50; border-bottom: 2px solid #eee; padding-bottom: 10px; margin-bottom: 20px; }
        h2 { color: #34495e; border-bottom: 1px solid #eee; padding-bottom: 5px; margin-top: 30px; }
        h3 { color: #7f8c8d; margin-top: 25px; }
        p { margin-bottom: 15px; }
        ul, ol { margin-bottom: 15px; padding-left: 20px; }
        li { margin-bottom: 5px; }
        code { background-color: #f8f9fa; padding: 2px 6px; border-radius: 4px; font-family: monospace; }
        pre { background-color: #f8f9fa; padding: 15px; border-radius: 8px; overflow-x: auto; border: 1px solid #dee2e6; }
        table { border-collapse: collapse; width: 100%; margin-bottom: 20px; }
        th, td { padding: 12px; border: 1px solid #dee2e6; }
        th { background-color: #f8f9fa; }
        .diagram { background-color: #f9f9f9; padding: 20px; border-radius: 8px; border: 1px solid #ddd; margin: 20px 0; font-family: monospace; }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;h1&gt;🗃️ Структура базы данных&lt;/h1&gt;

&lt;h2&gt;Общая схема&lt;/h2&gt;
&lt;div class=&quot;diagram&quot;&gt;
        &lt;pre&gt;
        ┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
        │    currencies   │────▶│ exchange_rates  │◀────│  external_rates │
        └─────────────────┘     └─────────────────┘     └─────────────────┘
               │                         │                         │
               │                         │                         │
               ▼                         ▼                         │
        ┌─────────────────┐     ┌─────────────────┐                │
        │      cities     │◀────│    partners     │────────────────┘
        └─────────────────┘     └─────────────────┘
               │                         │
               │                         │
               ▼                         ▼
        ┌─────────────────┐     ┌─────────────────┐
        │ exchange_orders │◀────│      users      │
        └─────────────────┘     └─────────────────┘
               │
               │
               ▼
        ┌─────────────────┐     ┌─────────────────┐
        │   user_wallets  │     │     admins      │
        └─────────────────┘     └─────────────────┘
                                        │
                                        ▼
                               ┌─────────────────┐
                               │    settings     │
                               └─────────────────┘
        &lt;/pre&gt;
&lt;/div&gt;

&lt;h2&gt;Основные таблицы&lt;/h2&gt;

&lt;h3&gt;currencies (Валюты)&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;CREATE TABLE currencies (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    code VARCHAR(10) UNIQUE,
    name VARCHAR(255),
    symbol VARCHAR(10),
    type ENUM(&#039;crypto&#039;, &#039;fiat&#039;, &#039;token&#039;) DEFAULT &#039;crypto&#039;,

    -- Настройки для USDT
    usdt_to_other_crypto_margin DECIMAL(5,2) NULL,
    usdt_to_other_crypto_min_amount DECIMAL(20,8) NULL,
    usdt_to_rub_margin DECIMAL(5,2) NULL,
    usdt_to_rub_min_amount DECIMAL(20,8) NULL,

    -- Настройки для RUB
    rub_to_usdt_margin DECIMAL(5,2) NULL,
    rub_to_usdt_min_amount DECIMAL(20,8) NULL,
    rub_to_other_crypto_margin DECIMAL(5,2) NULL,
    rub_to_other_crypto_min_amount DECIMAL(20,8) NULL,

    -- Настройки для других крипто
    other_crypto_to_rub_margin DECIMAL(5,2) NULL,
    other_crypto_to_rub_min_amount DECIMAL(20,8) NULL,
    other_crypto_to_other_crypto_margin DECIMAL(5,2) NULL,
    other_crypto_to_other_crypto_min_amount DECIMAL(20,8) NULL,

    -- Кошельки
    our_wallet VARCHAR(500) NULL,
    wallet_for_other_currencies BOOLEAN DEFAULT false,

    -- Метаданные
    icon VARCHAR(255) NULL,
    is_active BOOLEAN DEFAULT true,
    sort_order INT DEFAULT 0,
    created_at TIMESTAMP,
    updated_at TIMESTAMP
);&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;exchange_orders (Заявки на обмен)&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;CREATE TABLE exchange_orders (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    order_number VARCHAR(50) UNIQUE,
    user_id BIGINT UNSIGNED NULL,
    from_currency_id BIGINT UNSIGNED,
    to_currency_id BIGINT UNSIGNED,
    partner_id BIGINT UNSIGNED NULL,
    city_id BIGINT UNSIGNED,

    -- Финансовые данные
    amount DECIMAL(20,8),
    rate DECIMAL(20,8),
    fee_amount DECIMAL(20,8) DEFAULT 0,
    total_receive DECIMAL(20,8),
    fee_percentage DECIMAL(5,2) DEFAULT 0,

    -- Информация о клиенте
    full_name VARCHAR(255),
    email VARCHAR(255),
    phone VARCHAR(50),
    wallet_address VARCHAR(500) NULL,

    -- Статус
    status ENUM(&#039;pending&#039;, &#039;confirmed&#039;, &#039;processing&#039;, &#039;completed&#039;, &#039;cancelled&#039;, &#039;rejected&#039;) DEFAULT &#039;pending&#039;,
    transaction_type VARCHAR(100) NULL COMMENT &#039;Тип транзакции&#039;,

    -- Верификация
    verification_code CHAR(6) NULL,
    verification_token CHAR(64) NULL,
    verified_at TIMESTAMP NULL,
    expires_at TIMESTAMP NULL,

    -- Метаданные
    admin_notes TEXT NULL,
    user_notes TEXT NULL,
    ip_address VARCHAR(45) NULL,
    user_agent TEXT NULL,
    created_at TIMESTAMP,
    updated_at TIMESTAMP,

    -- Индексы
    INDEX orders_status_created (status, created_at),
    INDEX orders_order_number (order_number),
    INDEX orders_transaction_type (transaction_type),

    -- Внешние ключи
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE RESTRICT,
    FOREIGN KEY (from_currency_id) REFERENCES currencies(id) ON DELETE RESTRICT,
    FOREIGN KEY (to_currency_id) REFERENCES currencies(id) ON DELETE RESTRICT,
    FOREIGN KEY (partner_id) REFERENCES partners(id) ON DELETE RESTRICT,
    FOREIGN KEY (city_id) REFERENCES cities(id) ON DELETE RESTRICT
);&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;partners (Партнеры)&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;CREATE TABLE partners (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    city_id BIGINT UNSIGNED,
    name VARCHAR(255),
    address TEXT,
    phone VARCHAR(50),
    email VARCHAR(255),

    -- Геолокация
    latitude DECIMAL(10,7) NULL,
    longitude DECIMAL(10,7) NULL,

    -- Информация
    working_hours VARCHAR(255),
    description TEXT NULL,
    accepted_currencies JSON NULL,

    -- API интеграция
    api_id BIGINT UNSIGNED NULL COMMENT &#039;ID API конфигурации&#039;,

    -- Рейтинг
    rating DECIMAL(3,2) DEFAULT 0,
    total_reviews INT DEFAULT 0,

    -- Статус
    is_active BOOLEAN DEFAULT true,
    created_at TIMESTAMP,
    updated_at TIMESTAMP,

    -- Внешние ключи
    FOREIGN KEY (city_id) REFERENCES cities(id) ON DELETE RESTRICT,
    FOREIGN KEY (api_id) REFERENCES exchange_apis(id) ON DELETE SET NULL
);&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;exchange_rates (Курсы обмена)&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;CREATE TABLE exchange_rates (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    partner_id BIGINT UNSIGNED NULL,
    from_currency_id BIGINT UNSIGNED,
    to_currency_id BIGINT UNSIGNED,
    external_rate_id BIGINT UNSIGNED NULL,

    -- Курсы
    rate DECIMAL(20,8) NULL,
    use_external_rate BOOLEAN DEFAULT false,
    use_partner_external BOOLEAN DEFAULT false,
    manual_margin_percentage DECIMAL(5,2) NULL COMMENT &#039;Ручная наценка&#039;,

    -- Переопределения
    override_margin DECIMAL(5,2) NULL,
    override_min_amount DECIMAL(20,8) NULL,
    partner_external_margin DECIMAL(5,2) NULL,

    -- Лимиты
    min_amount DECIMAL(20,8) DEFAULT 0,
    max_amount DECIMAL(20,8) DEFAULT 0,

    -- Метаданные
    description TEXT NULL,
    is_active BOOLEAN DEFAULT true,
    is_hidden BOOLEAN DEFAULT false,
    priority INT DEFAULT 0,
    last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    created_at TIMESTAMP,
    updated_at TIMESTAMP,

    -- Уникальный индекс
    UNIQUE partner_currency_pair_unique (partner_id, from_currency_id, to_currency_id),

    -- Внешние ключи
    FOREIGN KEY (partner_id) REFERENCES partners(id) ON DELETE CASCADE,
    FOREIGN KEY (from_currency_id) REFERENCES currencies(id) ON DELETE RESTRICT,
    FOREIGN KEY (to_currency_id) REFERENCES currencies(id) ON DELETE RESTRICT,
    FOREIGN KEY (external_rate_id) REFERENCES external_rates(id) ON DELETE SET NULL
);&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;external_rates (Внешние курсы)&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;CREATE TABLE external_rates (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    partner_id BIGINT UNSIGNED NULL,
    from_currency_id BIGINT UNSIGNED,
    to_currency_id BIGINT UNSIGNED,
    external_rate DECIMAL(20,8),
    source VARCHAR(100) DEFAULT &#039;rapira.net&#039;,
    last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

    -- Стакан заявок
    order_book_buy JSON NULL,
    order_book_sell JSON NULL,

    -- Рыночные данные
    volume_24h DECIMAL(20,2) NULL,
    change_24h DECIMAL(8,2) NULL,
    bid_price DECIMAL(20,8) NULL,
    ask_price DECIMAL(20,8) NULL,
    bid_volume DECIMAL(20,8) NULL,
    ask_volume DECIMAL(20,8) NULL,
    spread DECIMAL(20,8) NULL,

    created_at TIMESTAMP,
    updated_at TIMESTAMP,

    -- Внешние ключи
    FOREIGN KEY (partner_id) REFERENCES partners(id) ON DELETE CASCADE,
    FOREIGN KEY (from_currency_id) REFERENCES currencies(id) ON DELETE CASCADE,
    FOREIGN KEY (to_currency_id) REFERENCES currencies(id) ON DELETE CASCADE,

    -- Индексы
    UNIQUE external_rates_unique_pair (from_currency_id, to_currency_id, partner_id),
    INDEX ext_rates_currency_pair_updated (from_currency_id, to_currency_id, last_updated)
);&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;exchange_apis (API конфигурации)&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;CREATE TABLE exchange_apis (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255),
    base_url VARCHAR(500),
    endpoint VARCHAR(255) DEFAULT &#039;/&#039;,
    method VARCHAR(10) DEFAULT &#039;GET&#039;,

    -- Форматы
    request_format VARCHAR(50) DEFAULT &#039;json&#039;,
    response_format VARCHAR(50) DEFAULT &#039;json&#039;,
    field_mapping JSON NULL,
    pair_format JSON NULL,

    -- Аутентификация
    authentication_type VARCHAR(50) DEFAULT &#039;none&#039;,
    api_key TEXT NULL,
    secret_key TEXT NULL,

    -- Настройки
    is_active BOOLEAN DEFAULT true,
    priority INT DEFAULT 0,
    timeout INT DEFAULT 30,
    retry_count INT DEFAULT 3,
    description TEXT NULL,
    test_data JSON NULL,

    -- Статистика
    success_count INT DEFAULT 0,
    error_count INT DEFAULT 0,
    last_success_at TIMESTAMP NULL,
    last_error_at TIMESTAMP NULL,
    last_error_message TEXT NULL,

    created_at TIMESTAMP,
    updated_at TIMESTAMP,

    -- Индексы
    INDEX exchange_apis_active_priority (is_active, priority),
    INDEX last_success_at (last_success_at)
);&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;admins (Администраторы)&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;CREATE TABLE admins (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255),
    email VARCHAR(255) UNIQUE,
    email_verified_at TIMESTAMP NULL,
    password VARCHAR(255),

    -- Роли и права
    role VARCHAR(50) DEFAULT &#039;admin&#039;,
    permissions JSON NULL,

    -- Статус
    is_active BOOLEAN DEFAULT true,
    remember_token VARCHAR(100) NULL,

    created_at TIMESTAMP,
    updated_at TIMESTAMP
);&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;settings (Настройки)&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;CREATE TABLE settings (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    key VARCHAR(255) UNIQUE,
    value TEXT NULL,
    type VARCHAR(50) DEFAULT &#039;text&#039;,
    group VARCHAR(50) DEFAULT &#039;general&#039;,
    options TEXT NULL,

    -- API настройки
    default_cron_api_id BIGINT UNSIGNED NULL,
    default_cron_api_name VARCHAR(255) NULL,
    update_interval_minutes INT DEFAULT 10,
    auto_update_enabled BOOLEAN DEFAULT true,
    primary_api_id BIGINT UNSIGNED NULL,
    fallback_api_id BIGINT UNSIGNED NULL,

    -- Настройки заявок
    order_expire_minutes INT DEFAULT 1440,
    auto_confirm_orders BOOLEAN DEFAULT false,
    require_verification BOOLEAN DEFAULT true,

    -- Локализация
    site_timezone VARCHAR(50) DEFAULT &#039;Europe/Moscow&#039;,
    date_format VARCHAR(20) DEFAULT &#039;d.m.Y&#039;,

    created_at TIMESTAMP,
    updated_at TIMESTAMP
);&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;cities (Города)&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;CREATE TABLE cities (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255),
    country VARCHAR(255),
    latitude DECIMAL(10,7) NULL,
    longitude DECIMAL(10,7) NULL,
    is_active BOOLEAN DEFAULT true,
    sort_order INT DEFAULT 0,
    created_at TIMESTAMP,
    updated_at TIMESTAMP
);&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;users (Пользователи)&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;-- Модификация стандартной таблицы users
ALTER TABLE users ADD COLUMN IF NOT EXISTS (
    role VARCHAR(50) DEFAULT &#039;user&#039;,
    is_active BOOLEAN DEFAULT true,
    phone VARCHAR(50) NULL,
    avatar VARCHAR(255) NULL,
    telegram VARCHAR(255) NULL,
    email_verified_at TIMESTAMP NULL,
    email_verification_token VARCHAR(64) NULL,
    verification_sent_at TIMESTAMP NULL
);&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;user_wallets (Кошельки пользователей)&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;CREATE TABLE user_wallets (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    user_id BIGINT UNSIGNED,
    currency_id BIGINT UNSIGNED,
    wallet_address VARCHAR(500),
    network VARCHAR(50) NULL,
    wallet_name VARCHAR(100) NULL,
    is_default BOOLEAN DEFAULT false,
    is_active BOOLEAN DEFAULT true,
    notes TEXT NULL,
    created_at TIMESTAMP,
    updated_at TIMESTAMP,

    -- Внешние ключи
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
    FOREIGN KEY (currency_id) REFERENCES currencies(id) ON DELETE RESTRICT,

    -- Уникальный индекс
    UNIQUE user_currency_wallet_unique (user_id, currency_id, wallet_address)
);&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;pages (Страницы сайта)&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;CREATE TABLE pages (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    slug VARCHAR(255) UNIQUE,
    title VARCHAR(255),
    content TEXT,
    meta_title VARCHAR(255) NULL,
    meta_description VARCHAR(255) NULL,
    meta_keywords VARCHAR(255) NULL,
    is_active BOOLEAN DEFAULT true,
    sort_order INT DEFAULT 0,
    created_at TIMESTAMP,
    updated_at TIMESTAMP,

    -- Индексы
    INDEX pages_active_sort (is_active, sort_order),
    INDEX pages_slug (slug)
);&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Связи таблиц&lt;/h2&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;Валюта ↔ Курсы обмена:&lt;/strong&gt; Одна валюта может быть в многих курсах&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Город ↔ Партнеры:&lt;/strong&gt; Один город имеет много партнеров&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Партнер ↔ Заявки:&lt;/strong&gt; Партнер обрабатывает много заявок&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;API ↔ Внешние курсы:&lt;/strong&gt; API источник для многих курсов&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Пользователь ↔ Кошельки:&lt;/strong&gt; У пользователя может быть несколько кошельков&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Пользователь ↔ Заявки:&lt;/strong&gt; Пользователь создает заявки&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Внешние курсы ↔ Курсы обмена:&lt;/strong&gt; Внешние курсы используются в курсах обмена&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Миграции&lt;/h2&gt;

&lt;h3&gt;Основная миграция&lt;/h3&gt;
&lt;p&gt;Файл: &lt;code&gt;2026_01_18_000000_create_dexa_database.php&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Создает все основные таблицы системы. Порядок создания важен из-за внешних ключей.&lt;/p&gt;

&lt;h3&gt;Миграция сессий админа&lt;/h3&gt;
&lt;p&gt;Файл: &lt;code&gt;2026_02_06_163437_create_admin_sessions_table.php&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Создает отдельную таблицу для сессий администраторов.&lt;/p&gt;

&lt;h2&gt;Индексы и оптимизация&lt;/h2&gt;

&lt;h3&gt;Критические индексы&lt;/h3&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;exchange_orders:&lt;/strong&gt; (status, created_at) - фильтрация заявок&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;external_rates:&lt;/strong&gt; (from_currency_id, to_currency_id, last_updated) - поиск актуальных курсов&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;exchange_apis:&lt;/strong&gt; (is_active, priority) - выбор активных API&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;pages:&lt;/strong&gt; (is_active, sort_order) - отображение страниц&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Уникальные ограничения&lt;/h3&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;currencies.code:&lt;/strong&gt; Уникальный код валюты&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;exchange_rates:&lt;/strong&gt; Уникальная пара (partner_id, from_currency_id, to_currency_id)&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;external_rates:&lt;/strong&gt; Уникальная пара с партнером&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;user_wallets:&lt;/strong&gt; Уникальный кошелек пользователя для валюты&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Типы данных&lt;/h2&gt;

&lt;h3&gt;Денежные значения&lt;/h3&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;DECIMAL(20,8):&lt;/strong&gt; Для криптовалют (8 знаков после запятой)&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;DECIMAL(10,2):&lt;/strong&gt; Для фиатных валют (2 знака)&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;DECIMAL(5,2):&lt;/strong&gt; Для процентов и наценок&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;JSON поля&lt;/h3&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;accepted_currencies:&lt;/strong&gt; Массив ID валют партнера&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;field_mapping:&lt;/strong&gt; Конфигурация маппинга API&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;permissions:&lt;/strong&gt; Права доступа администратора&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;order_book_buy/sell:&lt;/strong&gt; Данные стакана заявок&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Рекомендации по производительности&lt;/h2&gt;

&lt;h3&gt;Для больших таблиц&lt;/h3&gt;
&lt;ul&gt;
    &lt;li&gt;Регулярно архивируйте старые заявки (&gt; 6 месяцев)&lt;/li&gt;
    &lt;li&gt;Используйте партиционирование для exchange_orders по дате&lt;/li&gt;
    &lt;li&gt;Очищайте внешние курсы старше 7 дней&lt;/li&gt;
    &lt;li&gt;Оптимизируйте индексы под частые запросы&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Оптимизация запросов&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;-- Вместо N+1 запросов использовать жадную загрузку
$orders = ExchangeOrder::with([&#039;fromCurrency&#039;, &#039;toCurrency&#039;, &#039;city&#039;, &#039;partner&#039;])
    -&gt;where(&#039;status&#039;, &#039;completed&#039;)
    -&gt;get();

-- Использовать chunk для больших данных
ExchangeOrder::where(&#039;created_at&#039;, &#039;&lt;&#039;, now()-&gt;subMonths(6))
    -&gt;chunk(1000, function ($orders) {
        // обработка
    });&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Резервное копирование&lt;/h2&gt;

&lt;h3&gt;Рекомендуемый schedule&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# Ежедневный полный бэкап
0 2 * * * mysqldump -u user -p password dexa &gt; /backups/dexa_$(date +\%Y\%m\%d).sql

# Еженедельное ротирование
0 3 * * 0 find /backups -name &quot;*.sql&quot; -mtime +30 -delete

# Репликация в реальном времени (рекомендуется)
-- Настройте master-slave репликацию для продакшена&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Миграция данных&lt;/h2&gt;

&lt;h3&gt;При обновлении схемы&lt;/h3&gt;
&lt;ol&gt;
    &lt;li&gt;Создайте бэкап базы данных&lt;/li&gt;
    &lt;li&gt;Запустите миграции в тестовом окружении&lt;/li&gt;
    &lt;li&gt;Проверьте целостность данных&lt;/li&gt;
    &lt;li&gt;Запустите в продакшене во время минимальной нагрузки&lt;/li&gt;
    &lt;li&gt;Имейте план отката&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
    &lt;p&gt;&lt;strong&gt;Важно:&lt;/strong&gt; Все изменения схемы должны быть через миграции Laravel. Никогда не изменяйте базу напрямую в продакшене.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/body&gt;
&lt;/html&gt;