Демо-режим! Все данные только для просмотра. Изменения не сохраняются.
🗃️ Структура базы данных
Информация
Slug:
database.html
Обновлено:
30.05.2026 15:03
30.05.2026 15:03
Размер:
20.81 KB
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 репликацию для продакшена
Миграция данных
При обновлении схемы
- Создайте бэкап базы данных
- Запустите миграции в тестовом окружении
- Проверьте целостность данных
- Запустите в продакшене во время минимальной нагрузки
- Имейте план отката
Важно: Все изменения схемы должны быть через миграции Laravel. Никогда не изменяйте базу напрямую в продакшене.
Последнее обновление: 30.05.2026 в 15:03
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>🗃️ Структура базы данных</title>
<style>
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; }
</style>
</head>
<body>
<h1>🗃️ Структура базы данных</h1>
<h2>Общая схема</h2>
<div class="diagram">
<pre>
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ currencies │────▶│ exchange_rates │◀────│ external_rates │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
│ │ │
▼ ▼ │
┌─────────────────┐ ┌─────────────────┐ │
│ cities │◀────│ partners │────────────────┘
└─────────────────┘ └─────────────────┘
│ │
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ exchange_orders │◀────│ users │
└─────────────────┘ └─────────────────┘
│
│
▼
┌─────────────────┐ ┌─────────────────┐
│ user_wallets │ │ admins │
└─────────────────┘ └─────────────────┘
│
▼
┌─────────────────┐
│ settings │
└─────────────────┘
</pre>
</div>
<h2>Основные таблицы</h2>
<h3>currencies (Валюты)</h3>
<pre><code>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
);</code></pre>
<h3>exchange_orders (Заявки на обмен)</h3>
<pre><code>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
);</code></pre>
<h3>partners (Партнеры)</h3>
<pre><code>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
);</code></pre>
<h3>exchange_rates (Курсы обмена)</h3>
<pre><code>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
);</code></pre>
<h3>external_rates (Внешние курсы)</h3>
<pre><code>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)
);</code></pre>
<h3>exchange_apis (API конфигурации)</h3>
<pre><code>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)
);</code></pre>
<h3>admins (Администраторы)</h3>
<pre><code>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
);</code></pre>
<h3>settings (Настройки)</h3>
<pre><code>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
);</code></pre>
<h3>cities (Города)</h3>
<pre><code>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
);</code></pre>
<h3>users (Пользователи)</h3>
<pre><code>-- Модификация стандартной таблицы 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
);</code></pre>
<h3>user_wallets (Кошельки пользователей)</h3>
<pre><code>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)
);</code></pre>
<h3>pages (Страницы сайта)</h3>
<pre><code>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)
);</code></pre>
<h2>Связи таблиц</h2>
<ul>
<li><strong>Валюта ↔ Курсы обмена:</strong> Одна валюта может быть в многих курсах</li>
<li><strong>Город ↔ Партнеры:</strong> Один город имеет много партнеров</li>
<li><strong>Партнер ↔ Заявки:</strong> Партнер обрабатывает много заявок</li>
<li><strong>API ↔ Внешние курсы:</strong> API источник для многих курсов</li>
<li><strong>Пользователь ↔ Кошельки:</strong> У пользователя может быть несколько кошельков</li>
<li><strong>Пользователь ↔ Заявки:</strong> Пользователь создает заявки</li>
<li><strong>Внешние курсы ↔ Курсы обмена:</strong> Внешние курсы используются в курсах обмена</li>
</ul>
<h2>Миграции</h2>
<h3>Основная миграция</h3>
<p>Файл: <code>2026_01_18_000000_create_dexa_database.php</code></p>
<p>Создает все основные таблицы системы. Порядок создания важен из-за внешних ключей.</p>
<h3>Миграция сессий админа</h3>
<p>Файл: <code>2026_02_06_163437_create_admin_sessions_table.php</code></p>
<p>Создает отдельную таблицу для сессий администраторов.</p>
<h2>Индексы и оптимизация</h2>
<h3>Критические индексы</h3>
<ul>
<li><strong>exchange_orders:</strong> (status, created_at) - фильтрация заявок</li>
<li><strong>external_rates:</strong> (from_currency_id, to_currency_id, last_updated) - поиск актуальных курсов</li>
<li><strong>exchange_apis:</strong> (is_active, priority) - выбор активных API</li>
<li><strong>pages:</strong> (is_active, sort_order) - отображение страниц</li>
</ul>
<h3>Уникальные ограничения</h3>
<ul>
<li><strong>currencies.code:</strong> Уникальный код валюты</li>
<li><strong>exchange_rates:</strong> Уникальная пара (partner_id, from_currency_id, to_currency_id)</li>
<li><strong>external_rates:</strong> Уникальная пара с партнером</li>
<li><strong>user_wallets:</strong> Уникальный кошелек пользователя для валюты</li>
</ul>
<h2>Типы данных</h2>
<h3>Денежные значения</h3>
<ul>
<li><strong>DECIMAL(20,8):</strong> Для криптовалют (8 знаков после запятой)</li>
<li><strong>DECIMAL(10,2):</strong> Для фиатных валют (2 знака)</li>
<li><strong>DECIMAL(5,2):</strong> Для процентов и наценок</li>
</ul>
<h3>JSON поля</h3>
<ul>
<li><strong>accepted_currencies:</strong> Массив ID валют партнера</li>
<li><strong>field_mapping:</strong> Конфигурация маппинга API</li>
<li><strong>permissions:</strong> Права доступа администратора</li>
<li><strong>order_book_buy/sell:</strong> Данные стакана заявок</li>
</ul>
<h2>Рекомендации по производительности</h2>
<h3>Для больших таблиц</h3>
<ul>
<li>Регулярно архивируйте старые заявки (> 6 месяцев)</li>
<li>Используйте партиционирование для exchange_orders по дате</li>
<li>Очищайте внешние курсы старше 7 дней</li>
<li>Оптимизируйте индексы под частые запросы</li>
</ul>
<h3>Оптимизация запросов</h3>
<pre><code>-- Вместо 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) {
// обработка
});</code></pre>
<h2>Резервное копирование</h2>
<h3>Рекомендуемый schedule</h3>
<pre><code># Ежедневный полный бэкап
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 репликацию для продакшена</code></pre>
<h2>Миграция данных</h2>
<h3>При обновлении схемы</h3>
<ol>
<li>Создайте бэкап базы данных</li>
<li>Запустите миграции в тестовом окружении</li>
<li>Проверьте целостность данных</li>
<li>Запустите в продакшене во время минимальной нагрузки</li>
<li>Имейте план отката</li>
</ol>
<blockquote>
<p><strong>Важно:</strong> Все изменения схемы должны быть через миграции Laravel. Никогда не изменяйте базу напрямую в продакшене.</p>
</blockquote>
</body>
</html>