-- ============================================================================== -- 🗄️ Nabeh Multi-Tenant Database Schema -- UTF-8 Unicode (utf8mb4) is used to support Arabic text and Emojis perfectly. -- ============================================================================== -- 1. Companies (Tenants) Table CREATE TABLE IF NOT EXISTS `companies` ( `id` INT AUTO_INCREMENT PRIMARY KEY, `name` VARCHAR(255) NOT NULL, `status` ENUM('active', 'inactive', 'suspended') DEFAULT 'active', `max_sessions` INT DEFAULT 1 COMMENT 'Limit the number of WhatsApp numbers allowed', `api_key` VARCHAR(64) UNIQUE NULL COMMENT 'For external integrations (CRM/APIs)', `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, INDEX `idx_company_status` (`status`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- 2. Users Table (Multi-Tenant Staff/Admins) CREATE TABLE IF NOT EXISTS `users` ( `id` INT AUTO_INCREMENT PRIMARY KEY, `company_id` INT NOT NULL, `name` VARCHAR(255) NOT NULL, `email` VARCHAR(512) NOT NULL COMMENT 'Encrypted using AES-256-GCM', `email_hash` VARCHAR(64) NOT NULL COMMENT 'HMAC-SHA256 Blind Index for secure searching', `password` VARCHAR(255) NOT NULL, `role` ENUM('admin', 'staff') DEFAULT 'staff', `status` ENUM('active', 'inactive') DEFAULT 'active', `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, UNIQUE KEY `unique_email_hash` (`email_hash`), FOREIGN KEY (`company_id`) REFERENCES `companies` (`id`) ON DELETE CASCADE, INDEX `idx_user_company` (`company_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- 3. WhatsApp Sessions Table (Baileys Connections) CREATE TABLE IF NOT EXISTS `whatsapp_sessions` ( `id` INT AUTO_INCREMENT PRIMARY KEY, `company_id` INT NOT NULL, `name` VARCHAR(255) NOT NULL COMMENT 'e.g., Customer Support, Sales Team', `session_key` VARCHAR(100) UNIQUE NOT NULL COMMENT 'Unique identifier for Baileys node service', `phone` VARCHAR(512) DEFAULT NULL COMMENT 'Encrypted using AES-256-GCM', `phone_hash` VARCHAR(64) DEFAULT NULL COMMENT 'HMAC-SHA256 Blind Index', `status` ENUM('disconnected', 'waiting_qr', 'connected', 'connecting') DEFAULT 'disconnected', `qr_code` TEXT DEFAULT NULL COMMENT 'Encrypted using AES-256-GCM', `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, FOREIGN KEY (`company_id`) REFERENCES `companies` (`id`) ON DELETE CASCADE, INDEX `idx_session_company` (`company_id`), INDEX `idx_session_status` (`status`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- 4. Contacts Table (Customers / Leads) CREATE TABLE IF NOT EXISTS `contacts` ( `id` INT AUTO_INCREMENT PRIMARY KEY, `company_id` INT NOT NULL, `name` VARCHAR(255) NOT NULL, `phone` VARCHAR(512) NOT NULL COMMENT 'Encrypted using AES-256-GCM', `phone_hash` VARCHAR(64) NOT NULL COMMENT 'HMAC-SHA256 Blind Index', `email` VARCHAR(512) DEFAULT NULL COMMENT 'Encrypted using AES-256-GCM', `email_hash` VARCHAR(64) DEFAULT NULL COMMENT 'HMAC-SHA256 Blind Index', `notes` TEXT DEFAULT NULL COMMENT 'Encrypted using AES-256-GCM', `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, FOREIGN KEY (`company_id`) REFERENCES `companies` (`id`) ON DELETE CASCADE, UNIQUE KEY `unique_company_phone_hash` (`company_id`, `phone_hash`), INDEX `idx_contact_company` (`company_id`), INDEX `idx_contact_phone_hash` (`phone_hash`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- 5. Contact Groups Table (Lists for Broadcasts) CREATE TABLE IF NOT EXISTS `contact_groups` ( `id` INT AUTO_INCREMENT PRIMARY KEY, `company_id` INT NOT NULL, `name` VARCHAR(255) NOT NULL, `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, FOREIGN KEY (`company_id`) REFERENCES `companies` (`id`) ON DELETE CASCADE, INDEX `idx_group_company` (`company_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- 6. Contact Group Relations Table (Pivot Table) CREATE TABLE IF NOT EXISTS `contact_group_relations` ( `contact_id` INT NOT NULL, `group_id` INT NOT NULL, PRIMARY KEY (`contact_id`, `group_id`), FOREIGN KEY (`contact_id`) REFERENCES `contacts` (`id`) ON DELETE CASCADE, FOREIGN KEY (`group_id`) REFERENCES `contact_groups` (`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- 7. Predefined WhatsApp Templates Table CREATE TABLE IF NOT EXISTS `templates` ( `id` INT AUTO_INCREMENT PRIMARY KEY, `company_id` INT NOT NULL, `name` VARCHAR(255) NOT NULL, `body` TEXT NOT NULL COMMENT 'Message body. Supports variables like {{name}}', `type` ENUM('text', 'image', 'video', 'document') DEFAULT 'text', `media_url` TEXT DEFAULT NULL COMMENT 'Encrypted using AES-256-GCM', `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, FOREIGN KEY (`company_id`) REFERENCES `companies` (`id`) ON DELETE CASCADE, INDEX `idx_template_company` (`company_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- 8. Broadcast Campaigns Table CREATE TABLE IF NOT EXISTS `campaigns` ( `id` INT AUTO_INCREMENT PRIMARY KEY, `company_id` INT NOT NULL, `session_id` INT NOT NULL COMMENT 'Which WhatsApp number sends this campaign', `group_id` INT NOT NULL COMMENT 'Target contact group', `template_id` INT DEFAULT NULL, `name` VARCHAR(255) NOT NULL, `status` ENUM('pending', 'running', 'completed', 'paused', 'failed') DEFAULT 'pending', `scheduled_at` TIMESTAMP NULL DEFAULT NULL, `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, FOREIGN KEY (`company_id`) REFERENCES `companies` (`id`) ON DELETE CASCADE, FOREIGN KEY (`session_id`) REFERENCES `whatsapp_sessions` (`id`) ON DELETE CASCADE, FOREIGN KEY (`group_id`) REFERENCES `contact_groups` (`id`) ON DELETE CASCADE, FOREIGN KEY (`template_id`) REFERENCES `templates` (`id`) ON DELETE SET NULL, INDEX `idx_campaign_company` (`company_id`), INDEX `idx_campaign_status` (`status`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- 9. Message History Log Table (Inbound & Outbound) CREATE TABLE IF NOT EXISTS `messages_log` ( `id` INT AUTO_INCREMENT PRIMARY KEY, `company_id` INT NOT NULL, `session_id` INT NOT NULL COMMENT 'WhatsApp number that received or sent the message', `campaign_id` INT DEFAULT NULL COMMENT 'Null if sent individually or received', `contact_phone` VARCHAR(512) NOT NULL COMMENT 'Encrypted using AES-256-GCM', `contact_phone_hash` VARCHAR(64) NOT NULL COMMENT 'HMAC-SHA256 Blind Index', `direction` ENUM('inbound', 'outbound') NOT NULL, `message_type` ENUM('text', 'image', 'video', 'document', 'audio') DEFAULT 'text', `message_body` TEXT DEFAULT NULL COMMENT 'Encrypted using AES-256-GCM', `media_url` TEXT DEFAULT NULL COMMENT 'Encrypted using AES-256-GCM', `whatsapp_message_id` VARCHAR(100) UNIQUE NULL COMMENT 'To prevent duplicates & track receipt status', `status` ENUM('pending', 'sent', 'delivered', 'read', 'failed') DEFAULT 'pending', `error_message` VARCHAR(255) DEFAULT NULL, `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (`company_id`) REFERENCES `companies` (`id`) ON DELETE CASCADE, FOREIGN KEY (`session_id`) REFERENCES `whatsapp_sessions` (`id`) ON DELETE CASCADE, FOREIGN KEY (`campaign_id`) REFERENCES `campaigns` (`id`) ON DELETE SET NULL, INDEX `idx_msg_company` (`company_id`), INDEX `idx_msg_session` (`session_id`), INDEX `idx_msg_status` (`status`), INDEX `idx_msg_phone_hash` (`contact_phone_hash`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- 10. AI Auto-Reply & Bot Rules CREATE TABLE IF NOT EXISTS `chatbot_rules` ( `id` INT AUTO_INCREMENT PRIMARY KEY, `company_id` INT NOT NULL, `session_id` INT DEFAULT NULL COMMENT 'If NULL, applies to all company numbers', `trigger_type` ENUM('keyword', 'gemini_ai') DEFAULT 'keyword', `keyword` VARCHAR(255) DEFAULT NULL COMMENT 'Comma separated trigger words for keyword-match', `ai_prompt` TEXT DEFAULT NULL COMMENT 'Prompt instructions for Gemini AI responder', `is_active` TINYINT(1) DEFAULT 1, `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, FOREIGN KEY (`company_id`) REFERENCES `companies` (`id`) ON DELETE CASCADE, FOREIGN KEY (`session_id`) REFERENCES `whatsapp_sessions` (`id`) ON DELETE CASCADE, INDEX `idx_bot_company` (`company_id`), INDEX `idx_bot_active` (`is_active`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;