From ea516bdd6fe186738adf7376ffb7c8bcc7d05da6 Mon Sep 17 00:00:00 2001 From: infosave2007 Date: Sat, 8 Nov 2025 09:14:59 +0300 Subject: [PATCH] feat(database): add complete database schema with user, server, client, and translation tables --- migrations/init.sql | 300 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 300 insertions(+) create mode 100644 migrations/init.sql diff --git a/migrations/init.sql b/migrations/init.sql new file mode 100644 index 0000000..874d192 --- /dev/null +++ b/migrations/init.sql @@ -0,0 +1,300 @@ +-- Amnezia VPN Panel - Complete Database Schema +-- Single migration file containing all tables and initial data + +-- Users table +CREATE TABLE IF NOT EXISTS users ( + id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + email VARCHAR(255) NOT NULL UNIQUE, + password_hash VARCHAR(255) NOT NULL, + name VARCHAR(255) NOT NULL, + role ENUM('admin', 'user') DEFAULT 'user', + preferred_language VARCHAR(10) DEFAULT 'en', + status ENUM('active', 'disabled') DEFAULT 'active', + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + last_login_at TIMESTAMP NULL, + INDEX idx_email (email), + INDEX idx_role (role), + INDEX idx_language (preferred_language) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- VPN Servers table +CREATE TABLE IF NOT EXISTS vpn_servers ( + id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + user_id INT UNSIGNED NOT NULL, + name VARCHAR(255) NOT NULL, + host VARCHAR(255) NOT NULL, + port INT UNSIGNED NOT NULL, + username VARCHAR(255) NOT NULL, + password VARCHAR(255) NOT NULL, + container_name VARCHAR(255) DEFAULT 'amnezia-awg', + vpn_port INT UNSIGNED NULL, + vpn_subnet VARCHAR(50) DEFAULT '10.8.1.0/24', + server_public_key TEXT NULL, + preshared_key TEXT NULL, + awg_params JSON NULL COMMENT 'Jc, Jmin, Jmax, S1, S2, H1-H4', + status ENUM('deploying', 'active', 'stopped', 'error') DEFAULT 'deploying', + deployed_at TIMESTAMP NULL, + last_check_at TIMESTAMP NULL, + error_message TEXT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + INDEX idx_user_id (user_id), + INDEX idx_status (status), + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- VPN Clients table +CREATE TABLE IF NOT EXISTS vpn_clients ( + id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + server_id INT UNSIGNED NOT NULL, + user_id INT UNSIGNED NOT NULL, + name VARCHAR(255) NOT NULL, + client_ip VARCHAR(50) NOT NULL, + public_key TEXT NOT NULL, + private_key TEXT NOT NULL, + preshared_key TEXT NULL, + config TEXT NULL COMMENT 'Full WireGuard config file', + qr_code LONGTEXT NULL COMMENT 'Base64 encoded QR code image', + bytes_sent BIGINT UNSIGNED DEFAULT 0 COMMENT 'Total bytes sent by client', + bytes_received BIGINT UNSIGNED DEFAULT 0 COMMENT 'Total bytes received by client', + last_handshake TIMESTAMP NULL COMMENT 'Last successful WireGuard handshake', + last_sync_at TIMESTAMP NULL COMMENT 'Last time stats were synced from server', + status ENUM('active', 'disabled') DEFAULT 'active', + expires_at TIMESTAMP NULL COMMENT 'Client expiration date (NULL = never expires)', + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + INDEX idx_server_id (server_id), + INDEX idx_user_id (user_id), + INDEX idx_status (status), + INDEX idx_expires_at (expires_at), + INDEX idx_last_handshake (last_handshake), + UNIQUE KEY unique_server_client_ip (server_id, client_ip), + FOREIGN KEY (server_id) REFERENCES vpn_servers(id) ON DELETE CASCADE, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- API Tokens table +CREATE TABLE IF NOT EXISTS api_tokens ( + id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + user_id INT UNSIGNED NOT NULL, + token VARCHAR(255) NOT NULL UNIQUE, + name VARCHAR(255) NOT NULL, + last_used_at TIMESTAMP NULL, + expires_at TIMESTAMP NULL, + revoked_at TIMESTAMP NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + INDEX idx_token (token), + INDEX idx_user_id (user_id), + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- Settings table +CREATE TABLE IF NOT EXISTS settings ( + id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + user_id INT UNSIGNED NULL COMMENT 'NULL for global settings', + namespace VARCHAR(100) NOT NULL, + `key` VARCHAR(100) NOT NULL, + value JSON NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + UNIQUE KEY unique_setting (user_id, namespace, `key`), + INDEX idx_namespace (namespace) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- Languages table +CREATE TABLE IF NOT EXISTS languages ( + id INT AUTO_INCREMENT PRIMARY KEY, + code VARCHAR(10) NOT NULL UNIQUE COMMENT 'Language code (en, ru, es, de, fr, zh)', + name VARCHAR(50) NOT NULL COMMENT 'Language name in English', + native_name VARCHAR(50) NOT NULL COMMENT 'Language name in native language', + is_active TINYINT(1) DEFAULT 1, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + INDEX idx_code (code), + INDEX idx_active (is_active) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- Translations table +CREATE TABLE IF NOT EXISTS translations ( + id INT AUTO_INCREMENT PRIMARY KEY, + language_code VARCHAR(10) NOT NULL, + translation_key VARCHAR(255) NOT NULL COMMENT 'Translation key (e.g., menu.dashboard)', + translation_value TEXT NOT NULL COMMENT 'Translated text', + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + UNIQUE KEY unique_translation (language_code, translation_key), + FOREIGN KEY (language_code) REFERENCES languages(code) ON DELETE CASCADE, + INDEX idx_key (translation_key), + INDEX idx_language (language_code) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- API Keys table +CREATE TABLE IF NOT EXISTS api_keys ( + id INT AUTO_INCREMENT PRIMARY KEY, + service_name VARCHAR(50) NOT NULL UNIQUE COMMENT 'Service name (e.g., openrouter)', + api_key TEXT NOT NULL COMMENT 'API key value', + is_active TINYINT(1) DEFAULT 1, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + INDEX idx_service (service_name), + INDEX idx_active (is_active) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- Server Backups table +CREATE TABLE IF NOT EXISTS server_backups ( + id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + server_id INT UNSIGNED NOT NULL, + backup_name VARCHAR(255) NOT NULL COMMENT 'Backup file name', + backup_path VARCHAR(500) NOT NULL COMMENT 'Path to backup file', + backup_size BIGINT UNSIGNED DEFAULT 0 COMMENT 'Backup file size in bytes', + clients_count INT UNSIGNED DEFAULT 0 COMMENT 'Number of clients in backup', + backup_type ENUM('manual', 'automatic') DEFAULT 'manual', + status ENUM('creating', 'completed', 'failed') DEFAULT 'creating', + error_message TEXT NULL COMMENT 'Error message if backup failed', + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + created_by INT UNSIGNED NULL COMMENT 'User who created the backup', + INDEX idx_server_id (server_id), + INDEX idx_status (status), + INDEX idx_created_at (created_at), + FOREIGN KEY (server_id) REFERENCES vpn_servers(id) ON DELETE CASCADE, + FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- Insert default admin user +INSERT IGNORE INTO users (email, password_hash, name, role, status) +VALUES ('admin@amnez.ia', '$2y$10$SKEI6ogiWr2gsSG/nELLp.JcfpGhxsDLAAI7gdtTOI3ELz4zJzzPG', 'Administrator', 'admin', 'active'); + +-- Insert supported languages +INSERT INTO languages (code, name, native_name) VALUES +('en', 'English', 'English'), +('ru', 'Russian', 'Русский'), +('es', 'Spanish', 'Español'), +('de', 'German', 'Deutsch'), +('fr', 'French', 'Français'), +('zh', 'Chinese', '中文') +ON DUPLICATE KEY UPDATE name=VALUES(name); + +-- Insert English translations +INSERT INTO translations (language_code, translation_key, translation_value) VALUES +('en', 'auth.email', 'Email'), +('en', 'auth.login', 'Login'), +('en', 'auth.name', 'Name'), +('en', 'auth.password', 'Password'), +('en', 'auth.register', 'Register'), +('en', 'clients.actions', 'Actions'), +('en', 'clients.add', 'Add Client'), +('en', 'clients.create', 'Create Client'), +('en', 'clients.delete', 'Delete'), +('en', 'clients.download_config', 'Download Config'), +('en', 'clients.expiration', 'Expiration'), +('en', 'clients.expired', 'Expired'), +('en', 'clients.never_expires', 'Never expires'), +('en', 'clients.ip', 'IP Address'), +('en', 'clients.last_handshake', 'Last Handshake'), +('en', 'clients.name', 'Client Name'), +('en', 'clients.qr_code', 'QR Code'), +('en', 'clients.received', 'Received'), +('en', 'clients.restore', 'Restore'), +('en', 'clients.revoke', 'Revoke'), +('en', 'clients.sent', 'Sent'), +('en', 'clients.server', 'Server'), +('en', 'clients.status', 'Status'), +('en', 'clients.sync_stats', 'Sync Stats'), +('en', 'clients.title', 'Clients'), +('en', 'clients.traffic', 'Traffic'), +('en', 'backups.title', 'Server Backups'), +('en', 'backups.create', 'Create Backup'), +('en', 'backups.restore', 'Restore'), +('en', 'backups.no_backups', 'No backups yet'), +('en', 'backups.create_confirm', 'Create backup of all clients on this server?'), +('en', 'backups.restore_confirm', 'Restore clients from this backup? Existing clients will not be affected.'), +('en', 'backups.delete_confirm', 'Delete this backup permanently?'), +('en', 'backups.created_success', 'Backup created successfully'), +('en', 'backups.restored_success', 'Restored'), +('en', 'backups.deleted_success', 'Backup deleted successfully'), +('en', 'backups.login_required', 'Please login via API to manage backups'), +('en', 'common.days', 'days'), +('en', 'dashboard.active_clients', 'Active Clients'), +('en', 'dashboard.add_first_server', 'Add First Server'), +('en', 'dashboard.get_started', 'Get started by adding your first VPN server'), +('en', 'dashboard.no_servers', 'No servers yet'), +('en', 'dashboard.quick_actions', 'Quick Actions'), +('en', 'dashboard.recent_servers', 'Recent Servers'), +('en', 'dashboard.title', 'Dashboard'), +('en', 'dashboard.total_clients', 'Total Clients'), +('en', 'dashboard.total_servers', 'Total Servers'), +('en', 'dashboard.total_traffic', 'Total Traffic'), +('en', 'dashboard.welcome', 'Welcome to Amnezia VPN Management Panel'), +('en', 'form.cancel', 'Cancel'), +('en', 'form.close', 'Close'), +('en', 'form.create', 'Create'), +('en', 'form.loading', 'Loading...'), +('en', 'form.processing', 'Processing...'), +('en', 'form.save', 'Save'), +('en', 'form.submit', 'Submit'), +('en', 'form.update', 'Update'), +('en', 'menu.clients', 'Clients'), +('en', 'menu.dashboard', 'Dashboard'), +('en', 'menu.logout', 'Logout'), +('en', 'menu.servers', 'Servers'), +('en', 'menu.settings', 'Settings'), +('en', 'menu.users', 'Users'), +('en', 'message.confirm', 'Are you sure?'), +('en', 'message.deleted', 'Deleted successfully'), +('en', 'message.deployed', 'Deployed successfully'), +('en', 'message.error', 'An error occurred'), +('en', 'message.saved', 'Saved successfully'), +('en', 'message.success', 'Operation completed successfully'), +('en', 'servers.actions', 'Actions'), +('en', 'servers.add', 'Add Server'), +('en', 'servers.clients', 'Clients'), +('en', 'servers.delete', 'Delete'), +('en', 'servers.deploy', 'Deploy'), +('en', 'servers.edit', 'Edit'), +('en', 'servers.host', 'Host'), +('en', 'servers.name', 'Name'), +('en', 'servers.port', 'Port'), +('en', 'servers.status', 'Status'), +('en', 'servers.title', 'Servers'), +('en', 'servers.view', 'View'), +('en', 'settings.actions', 'Actions'), +('en', 'settings.api_keys', 'API Keys'), +('en', 'settings.api_keys_desc', 'Configure API keys for external services'), +('en', 'settings.auto_translate', 'Auto-translate'), +('en', 'settings.change_password', 'Change Password'), +('en', 'settings.confirm_password', 'Confirm Password'), +('en', 'settings.confirm_translate', 'Start automatic translation? This may take a few minutes.'), +('en', 'settings.current_password', 'Current Password'), +('en', 'settings.description', 'Manage panel configuration and API integrations'), +('en', 'settings.error_empty_key', 'API key cannot be empty'), +('en', 'settings.error_invalid_key', 'Invalid API key format'), +('en', 'settings.error_key_test', 'API key test failed'), +('en', 'settings.for_translation', 'for auto-translation'), +('en', 'settings.get_key_at', 'Get your API key at'), +('en', 'settings.key_saved', 'API key saved successfully'), +('en', 'settings.keys', 'keys'), +('en', 'settings.language', 'Language'), +('en', 'settings.min_6_chars', 'Minimum 6 characters'), +('en', 'settings.new_password', 'New Password'), +('en', 'settings.profile', 'Profile'), +('en', 'settings.progress', 'Progress'), +('en', 'settings.translations', 'Translations'), +('en', 'settings.translation_complete', 'Translation completed'), +('en', 'settings.translation_status', 'Translation Status'), +('en', 'settings.users', 'Users'), +('en', 'status.active', 'Active'), +('en', 'status.deploying', 'Deploying'), +('en', 'status.disabled', 'Disabled'), +('en', 'status.error', 'Error'), +('en', 'status.inactive', 'Inactive'), +('en', 'users.add_user', 'Add User'), +('en', 'users.all_users', 'All Users'), +('en', 'users.administrator', 'Administrator'), +('en', 'users.created', 'Created'), +('en', 'users.delete_confirm', 'Delete {0}?'), +('en', 'users.role', 'Role'), +('en', 'users.role_admin', 'Admin'), +('en', 'users.role_user', 'User'), +('en', 'settings.api_key_configured', 'API Key Configured'), +('en', 'settings.no_api_key', 'No API key configured. Auto-translation will not work.'), +('en', 'settings.skip_validation', 'Skip validation (save without testing)') +ON DUPLICATE KEY UPDATE translation_value=VALUES(translation_value);