Files
netrunner-backend/migrations/0001_init.sql
T
Kirill d4a57c0b6a docs
2026-07-02 23:13:13 +07:00

223 lines
11 KiB
SQL

-- =====================================================================
-- 1. ТАБЛИЦА ПОЛЬЗОВАТЕЛЕЙ (С учетом Ghost Protocol)
-- =====================================================================
CREATE TABLE IF NOT EXISTS users (
id UUID PRIMARY KEY,
tg_id BIGINT UNIQUE, -- NULL для анонимов, заходящих по Seed
tg_username VARCHAR(255),
role VARCHAR(50) NOT NULL DEFAULT 'user',
balance BIGINT NOT NULL DEFAULT 0,
game_tickets INT NOT NULL DEFAULT 0,
has_used_trial BOOLEAN NOT NULL DEFAULT FALSE,
seed_hash VARCHAR(255) UNIQUE, -- Хеш сид-фразы анонима
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
last_hack_at TIMESTAMPTZ
);
-- =====================================================================
-- 2. СИНДИКАТ И РЕФЕРАЛЫ (RevShare / CPA контур)
-- =====================================================================
CREATE TABLE IF NOT EXISTS referrals (
referrer_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
referred_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
earned_bonus BIGINT NOT NULL DEFAULT 0,
status VARCHAR(20) NOT NULL DEFAULT 'pending',
total_earned BIGINT NOT NULL DEFAULT 0,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
PRIMARY KEY (referrer_id, referred_id),
UNIQUE (referred_id)
);
-- =====================================================================
-- 3. ТАРИФНЫЕ ПЛАНЫ И РЕГИОНАЛЬНЫЕ ЦЕНЫ (Биллинг V2)
-- =====================================================================
CREATE TABLE IF NOT EXISTS plans (
name VARCHAR(50) PRIMARY KEY,
is_active BOOLEAN NOT NULL DEFAULT TRUE
);
CREATE TABLE IF NOT EXISTS plan_prices (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
plan_name VARCHAR(50) NOT NULL REFERENCES plans(name) ON DELETE CASCADE,
currency VARCHAR(10) NOT NULL, -- 'USD', 'RUB', 'EUR', 'TON'
amount BIGINT NOT NULL, -- В центах, копейках, nanoTON
is_active BOOLEAN NOT NULL DEFAULT TRUE,
UNIQUE(plan_name, currency)
);
-- =====================================================================
-- 4. ТАБЛИЦА ПОДПИСОК (Состояния Конечного Автомата)
-- =====================================================================
CREATE TABLE IF NOT EXISTS subscriptions (
user_id UUID PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE,
plan_name VARCHAR(50),
expires_at TIMESTAMPTZ,
status VARCHAR(20) NOT NULL DEFAULT 'active', -- active, grace, expired
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- =====================================================================
-- 5. ИНВОЙСЫ И ЧЕКИ ОПЛАТ
-- =====================================================================
CREATE TABLE IF NOT EXISTS invoices (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
plan_name VARCHAR(50) NOT NULL REFERENCES plans(name),
provider VARCHAR(50) NOT NULL, -- 'TON', 'STRIPE', 'YOOKASSA'
currency VARCHAR(10) NOT NULL,
amount BIGINT NOT NULL,
status VARCHAR(20) NOT NULL DEFAULT 'pending', -- pending, paid, failed, expired
external_id VARCHAR(255) UNIQUE, -- Хеш транзакции в блокчейне или ID в эквайринге
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_invoices_user ON invoices(user_id);
CREATE INDEX idx_invoices_status ON invoices(status);
-- =====================================================================
-- 6. ПРОМОКОДЫ И СИСТЕМА ИХ АКТИВИЗАЦИИ
-- =====================================================================
CREATE TABLE IF NOT EXISTS promo_codes (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
code VARCHAR(50) UNIQUE NOT NULL,
reward_amount BIGINT NOT NULL,
max_uses INT,
current_uses INT NOT NULL DEFAULT 0,
expires_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS promo_usages (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
promo_id UUID NOT NULL REFERENCES promo_codes(id) ON DELETE CASCADE,
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
used_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE(promo_id, user_id)
);
CREATE INDEX idx_promo_code ON promo_codes(code);
-- =====================================================================
-- 7. СЕССИИ АВТОРИЗАЦИИ И VPN УЗЛЫ
-- =====================================================================
-- TODO: Таблица объявлена, но нигде не используется в коде (нет ни одного
-- запроса к auth_sessions в src/). Это недореализованный флоу Magic Link
-- (одноразовый код из Telegram-бота -> обмен на JWT на сайте, см. things.txt).
-- Либо доделать флоу (repository + auth/service.rs + controller), либо убрать
-- таблицу из схемы, чтобы не вводить в заблуждение.
CREATE TABLE IF NOT EXISTS auth_sessions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID,
auth_code VARCHAR(8) NOT NULL UNIQUE,
is_verified BOOLEAN NOT NULL DEFAULT FALSE,
expires_at TIMESTAMPTZ NOT NULL
);
-- TODO: Не хватает столбцов public_key и sni_domain, необходимых для формирования
-- полноценного TunnelConfig в GET /nodes/routing (см. TODO в
-- src/modules/nodes/controller.rs::get_node_routing).
CREATE TABLE IF NOT EXISTS vpn_nodes (
id UUID PRIMARY KEY,
name VARCHAR(100) NOT NULL,
country_code VARCHAR(10) NOT NULL,
ip_address VARCHAR(50) NOT NULL,
port INT NOT NULL DEFAULT 443,
status VARCHAR(20) NOT NULL DEFAULT 'offline',
current_load INT NOT NULL DEFAULT 0,
tunnel_address VARCHAR(50) NOT NULL DEFAULT '10.0.0.1',
tunnel_prefix INT NOT NULL DEFAULT 24,
tunnel_dns VARCHAR(50) NOT NULL DEFAULT '10.0.0.2',
tunnel_mtu INT NOT NULL DEFAULT 1380,
last_seen TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- =====================================================================
-- 8. СИСТЕМНЫЙ СИД (Наполнение справочников начальными данными)
-- =====================================================================
-- Регистрируем все варианты планов по длительности (если их ещё нет)
INSERT INTO plans (name) VALUES
('GHOST_1M'), ('GHOST_6M'), ('GHOST_12M'),
('NETRUNNER_1M'), ('NETRUNNER_6M'), ('NETRUNNER_12M'),
('MAINFRAME_1M'), ('MAINFRAME_6M'), ('MAINFRAME_12M')
ON CONFLICT DO NOTHING;
-- Заливаем полную международную и региональную сетку цен
INSERT INTO plan_prices (plan_name, currency, amount) VALUES
-- =================================================================
-- ГЛОБАЛЬНЫЙ КОНТУР (USD) — Базовый прайс с сайта
-- =================================================================
('GHOST_1M', 'USD', 500), -- $5.00
('GHOST_6M', 'USD', 2400), -- $24.00
('GHOST_12M', 'USD', 3600), -- $36.00 (Сайт: $3/mo)
('NETRUNNER_1M', 'USD', 900), -- $9.00
('NETRUNNER_6M', 'USD', 4500), -- $45.00
('NETRUNNER_12M', 'USD', 6000), -- $60.00 (Сайт: $5/mo)
('MAINFRAME_1M', 'USD', 2000), -- $20.00
('MAINFRAME_6M', 'USD', 9600), -- $96.00
('MAINFRAME_12M', 'USD', 14400), -- $144.00 (Сайт: $12/mo)
-- =================================================================
-- РОССИЯ И СНГ (RUB) — Локальный прайс с сайта
-- =================================================================
('GHOST_1M', 'RUB', 24900), -- 249.00 ₽
('GHOST_6M', 'RUB', 129000), -- 1 290.00 ₽
('GHOST_12M', 'RUB', 299000), -- 2 990.00 ₽ (Сайт: 249/мес)
('NETRUNNER_1M', 'RUB', 69000), -- 690.00 ₽
('NETRUNNER_6M', 'RUB', 349000), -- 3 490.00 ₽
('NETRUNNER_12M', 'RUB', 549000), -- 5 490.00 ₽ (Сайт: 458/мес)
('MAINFRAME_1M', 'RUB', 149000), -- 1 490.00 ₽
('MAINFRAME_6M', 'RUB', 749000), -- 7 490.00 ₽
('MAINFRAME_12M', 'RUB', 1199000), -- 11 990.00 ₽ (Сайт: 999/мес)
-- =================================================================
-- КИТАЙ (CNY) — Адаптировано под конкуренцию с GFW-панелями
-- =================================================================
('GHOST_1M', 'CNY', 2200), -- 22.00 ¥
('GHOST_6M', 'CNY', 11000), -- 110.00 ¥
('GHOST_12M', 'CNY', 22000), -- 220.00 ¥
('NETRUNNER_1M', 'CNY', 4900), -- 49.00 ¥
('NETRUNNER_6M', 'CNY', 24500), -- 245.00 ¥
('NETRUNNER_12M', 'CNY', 43000), -- 430.00 ¥
('MAINFRAME_1M', 'CNY', 10000), -- 100.00 ¥
('MAINFRAME_6M', 'CNY', 49000), -- 490.00 ¥
('MAINFRAME_12M', 'CNY', 86000), -- 860.00 ¥
-- =================================================================
-- ТУРЦИЯ (TRY) — С учётом девальвации лиры
-- =================================================================
('GHOST_1M', 'TRY', 9900), -- 99.00 ₺
('GHOST_6M', 'TRY', 49900), -- 499.00 ₺
('GHOST_12M', 'TRY', 89900), -- 899.00 ₺
('NETRUNNER_1M', 'TRY', 24900), -- 249.00 ₺
('NETRUNNER_6M', 'TRY', 119900), -- 1 199.00 ₺
('NETRUNNER_12M', 'TRY', 219000), -- 2 190.00 ₺
('MAINFRAME_1M', 'TRY', 59900), -- 599.00 ₺
('MAINFRAME_6M', 'TRY', 289000), -- 2 890.00 ₺
('MAINFRAME_12M', 'TRY', 499000), -- 4 990.00 ₺
-- =================================================================
-- ИРАН (IRR / Цены указаны в РИАЛАХ, 1 Томан = 10 Риалов)
-- =================================================================
('GHOST_1M', 'IRR', 15000000), -- 1,500,000 Томанов (15 млн риалов)
('GHOST_6M', 'IRR', 75000000), -- 7,500,000 Томанов
('GHOST_12M', 'IRR', 135000000), -- 13,500,000 Томанов
('NETRUNNER_1M', 'IRR', 40000000), -- 4,000,000 Томанов
('NETRUNNER_6M', 'IRR', 190000000), -- 19,000,000 Томанов
('NETRUNNER_12M', 'IRR', 320000000), -- 32,000,000 Томанов
('MAINFRAME_1M', 'IRR', 90000000), -- 9,000,000 Томанов
('MAINFRAME_6M', 'IRR', 430000000), -- 43,000,000 Томанов
('MAINFRAME_12M', 'IRR', 750000000) -- 75,000,000 Томанов
ON CONFLICT (plan_name, currency) DO UPDATE
SET amount = EXCLUDED.amount;