182 lines
10 KiB
SQL
182 lines
10 KiB
SQL
-- ==============================================================================
|
|
-- 🗄️ 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;
|
|
|
|
-- 11. Multi-Stage Conversation States Table
|
|
CREATE TABLE IF NOT EXISTS `conversation_states` (
|
|
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
|
`company_id` INT NOT NULL,
|
|
`contact_phone` VARCHAR(512) NOT NULL COMMENT 'Encrypted using AES-256-GCM',
|
|
`contact_phone_hash` VARCHAR(64) NOT NULL COMMENT 'HMAC-SHA256 Blind Index',
|
|
`flow_name` VARCHAR(100) NOT NULL COMMENT 'e.g. test_flow, registration',
|
|
`current_step` VARCHAR(100) NOT NULL,
|
|
`context_data` JSON DEFAULT NULL COMMENT 'Stores transient state data',
|
|
`expires_at` TIMESTAMP NOT NULL,
|
|
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
UNIQUE KEY `unique_company_contact` (`company_id`, `contact_phone_hash`),
|
|
FOREIGN KEY (`company_id`) REFERENCES `companies` (`id`) ON DELETE CASCADE,
|
|
INDEX `idx_conv_expires` (`expires_at`)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|