UnifiedBeez Backend Architecture

Live Dashboard - Inbox Module

← Back to Index

📥 FRAME 1: Inbox Overview

🎯 Purpose

The Inbox module is the central communication hub for UnifiedBeez, enabling organizations to manage all customer conversations across multiple channels (WhatsApp, Email, Instagram, Facebook Messenger, Telegram, SMS) in a single unified interface. It supports both individual agent workflows and team collaboration with assignment, labeling, and automation capabilities.

🔄 Conversation Lifecycle

Conversation Lifecycle - 5 Stage Flow

1
NEW
  • Message received from any channel
  • Contact identified or created
  • Conversation created (unassigned)
2
ASSIGNED
  • Auto-assigned or manually assigned
  • Agent or team takes ownership
3
ACTIVE
  • Back-and-forth communication
  • Multiple messages exchanged
  • Can add labels, notes, attributes
4
RESOLVED
  • Issue solved or query answered
  • Can be reopened if customer replies
5
CLOSED
  • Permanently archived
  • Available for reporting/analytics

📡 Supported Communication Channels

Channel Features Message Types Special Constraints
WhatsApp Business API Templates, Free-form, Media, Location Text, Image, Video, Audio, Document, Location 24-hour window for free-form messages
Email (SMTP/IMAP) HTML emails, Attachments, Threading HTML, Plain text, Attachments None
Instagram Direct Text, Media, Story replies Text, Image, Video 7-day response window
Facebook Messenger Text, Quick replies, Buttons, Carousels Text, Image, Video, Audio, Templates 7-day response window
Telegram Text, Inline keyboards, Media Text, Image, Video, Audio, Document None
SMS (Twilio) Plain text messages Text only (160 chars per segment) Character limit, No media

✨ Core Inbox Features

👤 Individual Agent Features

  • Unified inbox view across all channels
  • Conversation filtering (unassigned, mine, all)
  • Real-time message notifications
  • Quick reply with canned responses
  • Contact sidebar with 360° view
  • Message templates for WhatsApp
  • Media attachments support
  • Conversation search and filtering

👥 Team Collaboration Features

  • Team inbox with shared visibility
  • Conversation assignment (user or team)
  • Auto-assignment rules (round-robin, load-balanced)
  • Collision detection (typing indicators)
  • Private notes with @mentions
  • Workload management (max conversations per agent)
  • Performance metrics (response time, resolution rate)
  • Away/Out-of-office status with auto-reassignment

🏷️ Organization & Automation

🏷️ Labels

Color-coded labels for categorization

  • Multi-label support
  • Label hierarchies
  • Auto-labeling via automation
  • Filter inbox by labels

📋 Contact Attributes

Custom fields for contact data

  • 10+ field types (text, number, date, etc.)
  • Contact-level and conversation-level
  • Validation rules
  • Use in automations

⚡ Automation Triggers

Event-based workflow execution

  • New message received
  • Conversation assigned
  • Attribute value changed
  • Auto-responses

🔧 FRAME 2: Backend Services Architecture

🏗️ Service Layer Overview

The Inbox module is built using a microservices-oriented architecture with NestJS. Core services handle conversations, messages, channel integrations, and real-time communication. Services are loosely coupled and communicate via events and dependency injection.

📊 Service Architecture Diagram

Inbox Service Layer Architecture

📨 InboxService
  • sendMessage()
  • getInbox()
  • markAsRead()
💬 ConversationService
  • create()
  • assign()
  • updateStatus()
↕️
📝 MessageService
  • create()
  • getHistory()
  • search()
👤 ContactService
  • findOrCreate()
  • update()
  • merge()
↕️
🔗 ChannelIntegrationService
📱 WhatsAppAdapter
📧 EmailAdapter
📷 InstagramAdapter
💬 MessengerAdapter
✈️ TelegramAdapter
💬 SMSAdapter
↕️
⚡ WebSocketGateway
Real-time message delivery Typing indicators Presence management

🔹 Core Services Description

1. InboxService

Responsibility: Main orchestration service for inbox operations

Key Methods:

  • getInboxView(userId, view, filters) - Retrieve conversations based on view type
  • sendMessage(conversationId, userId, content, options) - Send outgoing message
  • markConversationAsRead(conversationId, userId) - Update read status
  • searchConversations(query, filters) - Full-text search across conversations

2. ConversationService

Responsibility: Manage conversation lifecycle and metadata

Key Methods:

  • createConversation(contactId, channel, metadata) - Initialize new conversation
  • assignConversation(conversationId, assignTo) - Assign to user or team
  • updateStatus(conversationId, status) - Change lifecycle status
  • addLabel(conversationId, labelId) - Apply label for categorization
  • getConversationDetails(conversationId) - Full conversation with messages

3. MessageService

Responsibility: Handle message creation, retrieval, and search

Key Methods:

  • createMessage(conversationId, content, messageType) - Store new message
  • getMessageHistory(conversationId, pagination) - Retrieve conversation messages
  • searchMessages(query, filters) - Search message content
  • updateMessageStatus(messageId, status) - Track delivery/read receipts

4. ChannelIntegrationService

Responsibility: Normalize and route messages across all channels

Channel Adapters:

  • WhatsAppAdapter: WhatsApp Business API integration
  • EmailAdapter: SMTP sending + IMAP polling
  • InstagramAdapter: Instagram Graph API
  • MessengerAdapter: Facebook Messenger API
  • TelegramAdapter: Telegram Bot API
  • SMSAdapter: Twilio SMS API

Common Methods (per adapter):

  • sendMessage(to, content, options)
  • normalizeIncoming(payload) - Convert to unified format
  • validateWebhook(signature, payload)

5. WebSocketGateway

Responsibility: Real-time bidirectional communication

Key Features:

  • Socket.IO-based WebSocket server
  • JWT authentication on connection
  • Room-based message routing (org, user, conversation)
  • Typing indicator broadcasting
  • Presence status management
  • Multi-device synchronization

🔗 Service Dependencies

Service Depends On Emits Events
InboxService ConversationService, MessageService, ChannelIntegrationService inbox.message_sent, inbox.conversation_opened
ConversationService ContactService, MessageService conversation.created, conversation.assigned, conversation.status_changed
MessageService Database, FileStorageService (for media) message.created, message.status_updated
ChannelIntegrationService HTTP Client, External APIs channel.message_received, channel.webhook_verified
WebSocketGateway AuthService, Redis (for presence) WebSocket events (message.received, user.typing, etc.)

🔌 FRAME 3: API Endpoints

📡 REST API Overview

The Inbox module exposes 35+ RESTful API endpoints for managing conversations, messages, channel integrations, and settings. All endpoints require JWT authentication and follow RESTful conventions with proper HTTP status codes.

🔑 Core Inbox Endpoints

Conversation Management (12 endpoints)

Method Endpoint Description Request Body
GET /api/inbox/conversations Get all conversations with filters Query: view, status, assignee, labels, channel
GET /api/inbox/conversations/:id Get single conversation details -
POST /api/inbox/conversations Create new conversation { contactId, channel, initialMessage }
PATCH /api/inbox/conversations/:id/assign Assign conversation to user/team { assigneeId, assigneeType: 'user'|'team' }
PATCH /api/inbox/conversations/:id/status Update conversation status { status: 'new'|'active'|'resolved'|'closed' }
POST /api/inbox/conversations/:id/labels Add labels to conversation { labelIds: [1, 2, 3] }
DELETE /api/inbox/conversations/:id/labels/:labelId Remove label from conversation -
POST /api/inbox/conversations/:id/notes Add private note to conversation { content, mentions: [userId1, userId2] }
PATCH /api/inbox/conversations/:id/read Mark conversation as read -
GET /api/inbox/conversations/search Search conversations Query: q, filters
POST /api/inbox/conversations/bulk-assign Bulk assign conversations { conversationIds: [], assigneeId }
POST /api/inbox/conversations/bulk-label Bulk add labels { conversationIds: [], labelIds: [] }

Message Management (8 endpoints)

Method Endpoint Description Request Body
GET /api/inbox/messages/:conversationId Get message history Query: page, limit, before, after
POST /api/inbox/messages/send Send message { conversationId, content, type, attachments }
POST /api/inbox/messages/send-template Send WhatsApp template { conversationId, templateId, params }
POST /api/inbox/messages/upload Upload media attachment FormData: file, conversationId
GET /api/inbox/messages/search Search message content Query: q, conversationId, channel
PATCH /api/inbox/messages/:id/status Update message status { status: 'sent'|'delivered'|'read'|'failed' }
POST /api/inbox/messages/:id/react React to message { emoji: '👍' }
DELETE /api/inbox/messages/:id Delete message -

Channel Integration (7 endpoints)

Method Endpoint Description Request Body
GET /api/inbox/channels Get all connected channels -
POST /api/inbox/channels/whatsapp Connect WhatsApp Business API { phoneNumberId, accessToken, wabaId }
POST /api/inbox/channels/email Connect email (SMTP/IMAP) { email, smtpHost, imapHost, credentials }
POST /api/inbox/channels/social Connect social media (Instagram/FB) { platform, pageId, accessToken }
DELETE /api/inbox/channels/:id Disconnect channel -
POST /api/inbox/webhooks/:channel Handle incoming webhooks Channel-specific payload
GET /api/inbox/channels/:id/health Check channel connection health -

Templates & Settings (8 endpoints)

Method Endpoint Description Request Body
GET /api/inbox/templates Get all templates (canned responses) Query: type (general, whatsapp, preset)
POST /api/inbox/templates Create new template { name, content, type, category }
PUT /api/inbox/templates/:id Update template { name, content }
DELETE /api/inbox/templates/:id Delete template -
GET /api/inbox/attributes Get contact attributes schema -
POST /api/inbox/attributes Create custom attribute { name, type, validationRules }
GET /api/inbox/labels Get all labels -
POST /api/inbox/labels Create new label { name, color, description }

📊 Response Format

// Success Response (200 OK) { "success": true, "data": { "conversations": [...], "pagination": { "page": 1, "limit": 20, "total": 145, "hasMore": true } }, "meta": { "timestamp": "2025-10-23T10:30:00Z", "requestId": "req_abc123" } } // Error Response (400/401/403/404/500) { "success": false, "error": { "code": "CONVERSATION_NOT_FOUND", "message": "Conversation with ID 12345 not found", "details": {} }, "meta": { "timestamp": "2025-10-23T10:30:00Z", "requestId": "req_abc123" } }

💾 FRAME 4: Database Schema

🗄️ PostgreSQL Schema Overview

The Inbox module uses 8 primary tables in PostgreSQL to store conversations, messages, channel connections, templates, and settings. All tables use JSONB columns for flexible metadata storage and support full-text search via PostgreSQL's built-in capabilities.

📋 Core Database Tables

1. conversations

Purpose: Store conversation metadata and lifecycle

CREATE TABLE conversations ( id BIGSERIAL PRIMARY KEY, organization_id BIGINT NOT NULL REFERENCES organizations(id), contact_id BIGINT NOT NULL REFERENCES contacts(id), -- Conversation metadata channel VARCHAR(50) NOT NULL, -- 'whatsapp', 'email', 'instagram', etc. channel_conversation_id VARCHAR(255), -- External channel ID subject VARCHAR(500), -- For email threads -- Assignment & ownership assigned_to_user_id BIGINT REFERENCES users(id), assigned_to_team_id BIGINT REFERENCES teams(id), assigned_at TIMESTAMP, -- Status tracking status VARCHAR(50) DEFAULT 'new', -- 'new', 'active', 'resolved', 'closed' priority VARCHAR(20) DEFAULT 'normal', -- 'low', 'normal', 'high', 'urgent' -- Message counts message_count INT DEFAULT 0, unread_count INT DEFAULT 0, -- Timestamps first_message_at TIMESTAMP, last_message_at TIMESTAMP, last_customer_message_at TIMESTAMP, last_agent_message_at TIMESTAMP, resolved_at TIMESTAMP, closed_at TIMESTAMP, -- Metadata custom_attributes JSONB DEFAULT '{}', -- Flexible custom fields metadata JSONB DEFAULT '{}', -- Channel-specific metadata created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW(), -- Indexes INDEX idx_conversations_org (organization_id), INDEX idx_conversations_contact (contact_id), INDEX idx_conversations_assigned_user (assigned_to_user_id), INDEX idx_conversations_assigned_team (assigned_to_team_id), INDEX idx_conversations_status (status), INDEX idx_conversations_channel (channel), INDEX idx_conversations_last_message (last_message_at DESC) );

2. messages

Purpose: Store individual messages within conversations

CREATE TABLE messages ( id BIGSERIAL PRIMARY KEY, conversation_id BIGINT NOT NULL REFERENCES conversations(id) ON DELETE CASCADE, organization_id BIGINT NOT NULL REFERENCES organizations(id), -- Message content content TEXT, -- Message text content content_type VARCHAR(50) DEFAULT 'text', -- 'text', 'image', 'video', 'audio', 'document', 'location' -- Direction & sender direction VARCHAR(20) NOT NULL, -- 'inbound' (from customer), 'outbound' (from agent) sender_type VARCHAR(50), -- 'contact', 'user', 'system' sender_id BIGINT, -- ID of contact or user who sent -- Channel metadata channel VARCHAR(50) NOT NULL, channel_message_id VARCHAR(255), -- External message ID -- Message status status VARCHAR(50) DEFAULT 'sent', -- 'queued', 'sent', 'delivered', 'read', 'failed' delivered_at TIMESTAMP, read_at TIMESTAMP, failed_reason TEXT, -- Attachments attachments JSONB DEFAULT '[]', -- [{ type, url, filename, size, mimeType }] -- Special message types is_template BOOLEAN DEFAULT FALSE, template_id BIGINT REFERENCES message_templates(id), template_params JSONB, -- Metadata metadata JSONB DEFAULT '{}', created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW(), -- Indexes INDEX idx_messages_conversation (conversation_id, created_at DESC), INDEX idx_messages_org (organization_id), INDEX idx_messages_channel_id (channel_message_id), INDEX idx_messages_status (status), -- Full-text search INDEX idx_messages_content_fts USING GIN (to_tsvector('english', content)) );

3. channel_connections

Purpose: Store connected channel credentials and settings

CREATE TABLE channel_connections ( id BIGSERIAL PRIMARY KEY, organization_id BIGINT NOT NULL REFERENCES organizations(id), -- Channel info channel VARCHAR(50) NOT NULL, -- 'whatsapp', 'email', 'instagram', etc. name VARCHAR(255) NOT NULL, -- User-friendly name -- Connection status status VARCHAR(50) DEFAULT 'active', -- 'active', 'disconnected', 'error' is_primary BOOLEAN DEFAULT FALSE, -- Primary channel for this type -- Credentials (encrypted) credentials JSONB NOT NULL, -- { apiKey, accessToken, etc. } -- Channel-specific config config JSONB DEFAULT '{}', -- WhatsApp: { phoneNumberId, wabaId, businessAccountId } -- Email: { smtpHost, smtpPort, imapHost, imapPort } -- Social: { pageId, accountId } -- Health monitoring last_health_check_at TIMESTAMP, last_message_received_at TIMESTAMP, error_count INT DEFAULT 0, last_error TEXT, last_error_at TIMESTAMP, created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW(), -- Indexes INDEX idx_channel_connections_org (organization_id), INDEX idx_channel_connections_channel (channel), UNIQUE INDEX idx_channel_connections_org_channel_primary (organization_id, channel, is_primary) WHERE is_primary = TRUE );

4. message_templates

Purpose: Store canned responses and WhatsApp templates

CREATE TABLE message_templates ( id BIGSERIAL PRIMARY KEY, organization_id BIGINT NOT NULL REFERENCES organizations(id), -- Template info name VARCHAR(255) NOT NULL, content TEXT NOT NULL, type VARCHAR(50) NOT NULL, -- 'general', 'whatsapp', 'preset' category VARCHAR(100), -- 'greeting', 'support', 'sales', etc. -- WhatsApp-specific whatsapp_template_id VARCHAR(255), -- Meta template ID whatsapp_status VARCHAR(50), -- 'pending', 'approved', 'rejected' whatsapp_language VARCHAR(10), -- 'en', 'es', 'fr', etc. whatsapp_components JSONB, -- Template structure for Meta API -- Usage tracking usage_count INT DEFAULT 0, last_used_at TIMESTAMP, -- Variables/placeholders variables JSONB DEFAULT '[]', -- [{ name, type, example }] created_by BIGINT REFERENCES users(id), created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW(), -- Indexes INDEX idx_templates_org (organization_id), INDEX idx_templates_type (type), INDEX idx_templates_whatsapp_id (whatsapp_template_id) );

5. conversation_labels

Purpose: Many-to-many relationship for conversation categorization

CREATE TABLE conversation_labels ( id BIGSERIAL PRIMARY KEY, conversation_id BIGINT NOT NULL REFERENCES conversations(id) ON DELETE CASCADE, label_id BIGINT NOT NULL REFERENCES labels(id) ON DELETE CASCADE, applied_by BIGINT REFERENCES users(id), applied_at TIMESTAMP DEFAULT NOW(), UNIQUE INDEX idx_conversation_labels_unique (conversation_id, label_id), INDEX idx_conversation_labels_conversation (conversation_id), INDEX idx_conversation_labels_label (label_id) );

6. labels

Purpose: Store labels for conversation categorization

CREATE TABLE labels ( id BIGSERIAL PRIMARY KEY, organization_id BIGINT NOT NULL REFERENCES organizations(id), name VARCHAR(100) NOT NULL, color VARCHAR(7), -- Hex color code: #FF5733 description TEXT, -- Hierarchy parent_label_id BIGINT REFERENCES labels(id), -- Usage stats conversation_count INT DEFAULT 0, created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW(), INDEX idx_labels_org (organization_id), INDEX idx_labels_parent (parent_label_id), UNIQUE INDEX idx_labels_org_name (organization_id, name) );

7. contact_attributes_schema

Purpose: Define custom fields for contacts

CREATE TABLE contact_attributes_schema ( id BIGSERIAL PRIMARY KEY, organization_id BIGINT NOT NULL REFERENCES organizations(id), attribute_key VARCHAR(100) NOT NULL, -- Internal key: 'customer_tier' label VARCHAR(255) NOT NULL, -- Display label: 'Customer Tier' -- Data type data_type VARCHAR(50) NOT NULL, -- 'text', 'number', 'date', 'boolean', 'select', 'multiselect', 'email', 'phone', 'url' -- Validation is_required BOOLEAN DEFAULT FALSE, validation_rules JSONB DEFAULT '{}', -- { min, max, pattern, options: [] } -- Display default_value TEXT, placeholder VARCHAR(255), help_text TEXT, display_order INT DEFAULT 0, -- Usage scope scope VARCHAR(50) DEFAULT 'contact', -- 'contact', 'conversation' created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW(), INDEX idx_contact_attributes_org (organization_id), UNIQUE INDEX idx_contact_attributes_org_key (organization_id, attribute_key) );

8. conversation_notes

Purpose: Store private team notes on conversations

CREATE TABLE conversation_notes ( id BIGSERIAL PRIMARY KEY, conversation_id BIGINT NOT NULL REFERENCES conversations(id) ON DELETE CASCADE, organization_id BIGINT NOT NULL REFERENCES organizations(id), content TEXT NOT NULL, -- Author created_by BIGINT NOT NULL REFERENCES users(id), -- Mentions mentioned_users BIGINT[] DEFAULT '{}', -- Array of user IDs created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW(), INDEX idx_conversation_notes_conversation (conversation_id), INDEX idx_conversation_notes_created_by (created_by) );

📊 Entity Relationship Diagram

🔗 Inbox Entity Relationships - Database Schema

🏢 organizations
Root entity
(Parent for all data)
💬 conversations
Relationships:
• belongs to: contact
• assigned to: user
• assigned to: team
• has many: messages
• has many: labels
Key Fields:
status, channel
👤 contacts
has many:
• conversations
• messages
👨‍💼 users
assigned to:
• conversations
👥 teams
assigned to:
• conversations
📧 messages
Belongs to:
• conversation
• contact
• template (optional)
Fields:
content, direction, status
📝 message_templates
used by:
• messages
🏷️ labels
many-to-many:
• conversations
🔗 conversation_labels
Junction table
(joins labels ↔ conversations)
💡 Key Relationships:
conversations is the central hub connecting contacts, users, teams, messages, and labels
messages belong to both conversations and contacts for flexible querying
labels use a many-to-many relationship via conversation_labels junction table

💬 FRAME 5: WhatsApp Business API Integration

📱 WhatsApp Integration Overview

UnifiedBeez integrates with WhatsApp Business API (Cloud API) via Meta's official API. This integration enables sending template messages, receiving inbound messages, managing media, and tracking message delivery status. The integration handles the 24-hour messaging window constraint and template approval workflows.

🏗️ WhatsApp Architecture

📱 WhatsApp Integration Flow

👤
Customer

(WhatsApp)

☁️
Meta WhatsApp API

(Cloud API)

🔗 Webhook Handler

(NestJS Controller)

⚙️ WhatsAppAdapter Service
  • normalizeIncoming()
  • sendMessage()
  • sendTemplate()
  • uploadMedia()
  • validateWebhook()
💬
Conversation Service
✉️
Message Service
🗄️
S3 Storage

📨 Message Flow Types

Inbound Messages (Customer → Business)

  1. Customer sends WhatsApp message
  2. Meta sends webhook to UnifiedBeez
    POST /api/inbox/webhooks/whatsapp { "object": "whatsapp_business_account", "entry": [{ "changes": [{ "value": { "messaging_product": "whatsapp", "messages": [{ "from": "447123456789", "id": "wamid.xxx", "timestamp": "1729681800", "type": "text", "text": { "body": "Hello!" } }] } }] }] }
  3. WhatsAppAdapter validates webhook signature
  4. Normalize message to UnifiedBeez format
  5. Find/create contact and conversation
  6. Store message in database
  7. Emit WebSocket event to connected agents
  8. Trigger automation rules (if any)

Outbound Messages (Business → Customer)

  1. Agent sends message via inbox UI
  2. Check 24-hour window status
    • Within window: Send free-form message
    • Outside window: Require approved template
  3. WhatsAppAdapter.sendMessage() calls Meta API
    POST https://graph.facebook.com/v18.0/{phone_number_id}/messages { "messaging_product": "whatsapp", "to": "447123456789", "type": "text", "text": { "body": "Thank you for your message!" } }
  4. Store message with status = 'sent'
  5. Wait for delivery/read webhooks
  6. Update message status accordingly

📋 WhatsApp Template Management

📋 WhatsApp Template Workflow

1
CREATE TEMPLATE

(UnifiedBeez UI)

  • User designs template
  • Add variables: {{1}}, {{2}}
  • Select category, language
2
SUBMIT TO META

(API Call)

POST /v18.0/{waba_id}/message_templates
{ name, category, language, components }
3
PENDING REVIEW

(24-48 hours)

  • Meta reviews for policy compliance
  • Status: 'PENDING'
4
APPROVED / REJECTED
  • Webhook notification received
  • Status updated in database
5
USAGE (If Approved)
  • Available in inbox template selector
  • Can be sent outside 24-hour window

Template Message Example

// Template Definition (Stored in UnifiedBeez) { "name": "order_confirmation", "category": "TRANSACTIONAL", "language": "en", "components": [ { "type": "BODY", "text": "Hi {{1}}, your order {{2}} has been confirmed! Delivery in {{3}} days." }, { "type": "FOOTER", "text": "Reply STOP to unsubscribe" } ] } // Sending Template Message POST /v18.0/{phone_number_id}/messages { "messaging_product": "whatsapp", "to": "447123456789", "type": "template", "template": { "name": "order_confirmation", "language": { "code": "en" }, "components": [{ "type": "body", "parameters": [ { "type": "text", "text": "John" }, { "type": "text", "text": "#12345" }, { "type": "text", "text": "3" } ] }] } }

🖼️ Media Handling

Uploading Media (Images, Videos, Documents)

  1. User uploads file via inbox UI
  2. File uploaded to S3 with presigned URL
  3. Call Meta API to upload media
    POST https://graph.facebook.com/v18.0/{phone_number_id}/media Content-Type: multipart/form-data { "messaging_product": "whatsapp", "file": } Response: { "id": "media_id_123" }
  4. Send message with media ID
    POST /v18.0/{phone_number_id}/messages { "messaging_product": "whatsapp", "to": "447123456789", "type": "image", "image": { "id": "media_id_123", "caption": "Here's your invoice" } }

✅ Webhook Signature Verification

Security Implementation

// NestJS Webhook Handler @Post('webhooks/whatsapp') async handleWhatsAppWebhook( @Body() body: any, @Headers('x-hub-signature-256') signature: string ) { // 1. Verify webhook signature const isValid = this.whatsappAdapter.validateWebhook(body, signature); if (!isValid) { throw new UnauthorizedException('Invalid signature'); } // 2. Process webhook const webhookType = body.entry[0]?.changes[0]?.value; if (webhookType.messages) { // Incoming message await this.processIncomingMessage(webhookType.messages[0]); } else if (webhookType.statuses) { // Message status update await this.processMessageStatus(webhookType.statuses[0]); } return { success: true }; } // Signature validation validateWebhook(payload: any, signature: string): boolean { const secret = process.env.WHATSAPP_WEBHOOK_SECRET; const hash = crypto .createHmac('sha256', secret) .update(JSON.stringify(payload)) .digest('hex'); return signature === `sha256=${hash}`; }

🔔 Message Status Tracking

Status Description Webhook Event Action in UnifiedBeez
sent Message sent to Meta API - Create message record, status = 'sent'
delivered Delivered to customer's device status: 'delivered' Update message status, set delivered_at timestamp
read Customer opened message status: 'read' Update status, set read_at, show double checkmark
failed Delivery failed status: 'failed', error Update status, store error reason, notify agent

⚙️ AWS Infrastructure for WhatsApp

Infrastructure Components

  • ALB (Application Load Balancer): Receives webhooks from Meta (public endpoint)
  • ECS Fargate Tasks: Process webhooks and send messages
  • S3: Store media files (images, videos, documents)
  • CloudFront: Serve media files with CDN
  • Secrets Manager: Store WhatsApp API credentials (access tokens, phone number IDs)
  • CloudWatch: Monitor webhook processing, message delivery rates, error rates

📝 FRAME 6: Template Management System

🎯 Purpose

The Template Management system enables organizations to create, manage, and deploy reusable message templates across all communication channels. This includes WhatsApp Business API templates (requiring Meta approval), general canned responses for quick replies, and preset templates for common use cases. Templates support variable placeholders, multi-language content, and usage analytics to optimize agent productivity and message consistency.

📋 Template Types

Three Template Categories in UnifiedBeez

📱 WhatsApp Templates

Pre-approved templates by Meta for messages outside 24-hour window

  • Require Meta approval (24-48h)
  • Support rich media (images, videos)
  • Variable placeholders: {{1}}, {{2}}
  • Call-to-action buttons
  • Usage limited by messaging tier
💬 General Templates

Quick replies for agents across all channels

  • Instant approval (no waiting)
  • Use in any channel
  • Custom variables: {contactName}, {companyName}
  • Keyboard shortcuts (/greeting)
  • Unlimited usage
⚡ Preset Templates

Industry-specific templates provided by UnifiedBeez

  • Pre-built by UnifiedBeez
  • E-commerce, Healthcare, Finance, etc.
  • Customizable after import
  • Best practices included
  • Multi-language support

🔧 Backend Services

1. TemplateService

Responsibility: Manage template lifecycle and validation

Key Methods:

  • createTemplate(organizationId, templateData) - Create new template
  • updateTemplate(templateId, updates) - Modify existing template
  • deleteTemplate(templateId) - Remove template
  • getTemplates(organizationId, filters) - List templates with filtering
  • searchTemplates(query) - Full-text search across template content
  • validateVariables(content, variables) - Ensure placeholders are valid
  • trackUsage(templateId, messageId) - Log template usage for analytics

2. WhatsAppTemplateService

Responsibility: Handle WhatsApp-specific template operations with Meta API

Key Methods:

  • submitToMeta(templateData) - Submit template for approval
  • checkApprovalStatus(templateId) - Poll Meta API for status updates
  • syncTemplatesFromMeta(wabaId) - Import approved templates from Meta
  • deleteMetaTemplate(templateId) - Remove from Meta and local DB
  • handleWebhook(payload) - Process template status webhooks from Meta

🔌 API Endpoints

Template Management Endpoints (12 total)

Method Endpoint Description Request Body
GET /api/templates Get all templates Query: type (general, whatsapp, preset), category
GET /api/templates/:id Get single template details -
POST /api/templates Create new template { name, content, type, category, variables }
PUT /api/templates/:id Update template { name, content, variables }
DELETE /api/templates/:id Delete template -
POST /api/templates/whatsapp/submit Submit WhatsApp template to Meta { name, category, language, components }
GET /api/templates/whatsapp/:id/status Check Meta approval status -
POST /api/templates/whatsapp/sync Sync approved templates from Meta { wabaId }
GET /api/templates/preset Get preset template library Query: industry, category
POST /api/templates/preset/:id/import Import preset template to org -
GET /api/templates/search Search templates by content Query: q, type
GET /api/templates/:id/analytics Get template usage analytics Query: startDate, endDate

💾 Database Schema

message_templates Table

CREATE TABLE message_templates ( id BIGSERIAL PRIMARY KEY, organization_id BIGINT NOT NULL REFERENCES organizations(id), -- Template info name VARCHAR(255) NOT NULL, content TEXT NOT NULL, type VARCHAR(50) NOT NULL, -- 'general', 'whatsapp', 'preset' category VARCHAR(100), -- 'greeting', 'support', 'sales', 'appointment', etc. -- WhatsApp-specific fields whatsapp_template_id VARCHAR(255), -- Meta template ID whatsapp_status VARCHAR(50), -- 'pending', 'approved', 'rejected' whatsapp_language VARCHAR(10), -- 'en', 'es', 'fr', etc. whatsapp_components JSONB, -- Template structure for Meta API -- Example: [{ type: 'HEADER', format: 'IMAGE', ... }, { type: 'BODY', text: '...' }] -- Variables/placeholders variables JSONB DEFAULT '[]', -- [{ name: 'customerName', type: 'text', example: 'John' }] -- Usage tracking usage_count INT DEFAULT 0, last_used_at TIMESTAMP, -- Keyboard shortcuts (for general templates) shortcut VARCHAR(50), -- '/greeting', '/thankyou' -- Metadata created_by BIGINT REFERENCES users(id), is_active BOOLEAN DEFAULT TRUE, is_preset BOOLEAN DEFAULT FALSE, -- True for UnifiedBeez presets created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW(), -- Indexes INDEX idx_templates_org (organization_id), INDEX idx_templates_type (type), INDEX idx_templates_category (category), INDEX idx_templates_whatsapp_id (whatsapp_template_id), INDEX idx_templates_whatsapp_status (whatsapp_status), INDEX idx_templates_shortcut (shortcut), -- Full-text search INDEX idx_templates_content_fts USING GIN (to_tsvector('english', content)) );

🖼️ UI Screenshots Reference

Template Management Interface (8 screenshots)

  • Inbox Settings - General Templates: UnifiedBeez_UI_UX/Live Dashboard UI - Inbox/Inbox Settings - General Templates.png
  • Inbox Settings - WhatsApp Templates: UnifiedBeez_UI_UX/Live Dashboard UI - Inbox/Inbox Settings - Whatsapp Templates.png
  • Inbox Settings - Preset Templates: UnifiedBeez_UI_UX/Live Dashboard UI - Inbox/Inbox Settings - Preset Templates.png
  • Create New WhatsApp Template: UnifiedBeez_UI_UX/Live Dashboard UI - Inbox/Inbox Settings - Create new Whatsapp Templates.png
  • WhatsApp Template Builder (Step 1): UnifiedBeez_UI_UX/Live Dashboard UI - Inbox/Inbox Settings - Create new Whatsapp Templates-1.png
  • WhatsApp Template Builder (Step 2): UnifiedBeez_UI_UX/Live Dashboard UI - Inbox/Inbox Settings - Create new Whatsapp Templates-2.png
  • WhatsApp Template Builder (Step 3): UnifiedBeez_UI_UX/Live Dashboard UI - Inbox/Inbox Settings - Create new Whatsapp Templates-3.png
  • Templates Library: UnifiedBeez_UI_UX/Live Dashboard UI - Internal Operations and Admin/Internal Operations & Admin - Templates Libraries.png

🔐 GDPR Compliance

Data Protection Measures

  • Variable Data Handling: Template variables may contain PII (customer names, emails) - encrypted at rest
  • Usage Analytics: Track which templates are used, but anonymize customer identifiers in analytics
  • Data Retention: Deleted templates permanently removed after 30 days (soft delete with grace period)
  • Meta API Compliance: WhatsApp template submissions follow Meta's data handling policies
  • Right to Access: Templates are exportable via API for GDPR subject access requests

👤 FRAME 7: Contact Attributes System

🎯 Purpose

The Contact Attributes system enables organizations to define custom fields for storing additional information about contacts and conversations. This flexible schema system supports 10+ field types (text, number, date, boolean, select, multiselect, email, phone, URL, file) with validation rules, default values, and conditional visibility. Attributes power segmentation, personalization, and automation workflows across the entire UnifiedBeez platform.

📊 Attribute Types

10+ Supported Attribute Field Types

📝 Text

Single-line text input (max 255 chars)

📄 Textarea

Multi-line text (unlimited length)

🔢 Number

Integer or decimal with min/max validation

📅 Date

Date picker (YYYY-MM-DD format)

🕐 DateTime

Date + time picker with timezone

✅ Boolean

Checkbox (true/false)

📋 Select

Dropdown (single choice)

☑️ Multiselect

Multiple checkboxes

📧 Email

Email validation

📞 Phone

Phone number with country code

🔗 URL

URL validation (http/https)

📎 File

File upload (S3 storage)

🔧 Backend Services

1. AttributeService

Responsibility: Manage attribute schema and values

Key Methods:

  • createAttribute(organizationId, attributeData) - Define new custom attribute
  • updateAttribute(attributeId, updates) - Modify attribute schema
  • deleteAttribute(attributeId) - Remove attribute (cascade delete values)
  • getAttributes(organizationId, scope) - List attributes by scope (contact/conversation)
  • validateValue(attributeId, value) - Validate against validation rules
  • setAttributeValue(entityId, attributeId, value) - Store attribute value
  • getAttributeValues(entityId) - Retrieve all attribute values for entity

2. ContactManagementService

Responsibility: Integrate attributes with contact operations

Key Methods:

  • enrichContactWithAttributes(contactId) - Fetch contact with all custom attributes
  • updateContactAttributes(contactId, attributes) - Bulk update attribute values
  • segmentContacts(attributeFilters) - Filter contacts by attribute values
  • exportContactsWithAttributes(filters) - CSV export with custom fields

🔌 API Endpoints

Attribute Management Endpoints (10 total)

Method Endpoint Description Request Body
GET /api/attributes Get all attribute schemas Query: scope (contact, conversation)
GET /api/attributes/:id Get single attribute schema -
POST /api/attributes Create new attribute { key, label, dataType, validationRules, scope }
PUT /api/attributes/:id Update attribute schema { label, validationRules, defaultValue }
DELETE /api/attributes/:id Delete attribute -
GET /api/contacts/:id/attributes Get contact attribute values -
PUT /api/contacts/:id/attributes Update contact attributes { attributes: { customer_tier: 'gold', ... } }
GET /api/conversations/:id/attributes Get conversation attribute values -
PUT /api/conversations/:id/attributes Update conversation attributes { attributes: { priority: 'high', ... } }
POST /api/attributes/validate Validate attribute value { attributeId, value }

💾 Database Schema

contact_attributes_schema Table

CREATE TABLE contact_attributes_schema ( id BIGSERIAL PRIMARY KEY, organization_id BIGINT NOT NULL REFERENCES organizations(id), attribute_key VARCHAR(100) NOT NULL, -- Internal key: 'customer_tier' label VARCHAR(255) NOT NULL, -- Display label: 'Customer Tier' -- Data type data_type VARCHAR(50) NOT NULL, -- 'text', 'textarea', 'number', 'date', 'datetime', 'boolean', -- 'select', 'multiselect', 'email', 'phone', 'url', 'file' -- Validation is_required BOOLEAN DEFAULT FALSE, validation_rules JSONB DEFAULT '{}', -- { min: 0, max: 100, pattern: '^[A-Z]', options: ['gold', 'silver', 'bronze'] } -- Display default_value TEXT, placeholder VARCHAR(255), help_text TEXT, display_order INT DEFAULT 0, -- Usage scope scope VARCHAR(50) DEFAULT 'contact', -- 'contact', 'conversation' -- Metadata is_system BOOLEAN DEFAULT FALSE, -- True for UnifiedBeez system fields created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW(), INDEX idx_contact_attributes_org (organization_id), UNIQUE INDEX idx_contact_attributes_org_key (organization_id, attribute_key) );

contact_attribute_values Table

CREATE TABLE contact_attribute_values ( id BIGSERIAL PRIMARY KEY, organization_id BIGINT NOT NULL REFERENCES organizations(id), attribute_id BIGINT NOT NULL REFERENCES contact_attributes_schema(id) ON DELETE CASCADE, -- Entity reference (polymorphic) entity_type VARCHAR(50) NOT NULL, -- 'contact', 'conversation' entity_id BIGINT NOT NULL, -- Value storage value_text TEXT, -- For text, textarea, email, phone, url value_number DECIMAL(20, 4), -- For number value_boolean BOOLEAN, -- For boolean value_date DATE, -- For date value_datetime TIMESTAMP, -- For datetime value_json JSONB, -- For select, multiselect, file (structured data) created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW(), -- Indexes INDEX idx_attribute_values_org (organization_id), INDEX idx_attribute_values_attribute (attribute_id), INDEX idx_attribute_values_entity (entity_type, entity_id), UNIQUE INDEX idx_attribute_values_unique (attribute_id, entity_type, entity_id) );

🖼️ UI Screenshots Reference

Attribute Management Interface (6 screenshots)

  • Attributes List: UnifiedBeez_UI_UX/Live Dashboard UI - Inbox/Attributes.png
  • Contact Attributes View: UnifiedBeez_UI_UX/Live Dashboard UI - Inbox/General Inbox - Attributes Contacts.png
  • Attributes Modal: UnifiedBeez_UI_UX/Live Dashboard UI - Inbox/Attributes modal.png
  • Inbox Settings - Contact Attributes: UnifiedBeez_UI_UX/Live Dashboard UI - Inbox/Inbox Settings - Contacts attributes.png
  • Create New Attribute: UnifiedBeez_UI_UX/Live Dashboard UI - Inbox/Inbox Settings - Create new attributes.png
  • Attribute Preview (Contacts): UnifiedBeez_UI_UX/Live Dashboard UI - Internal Operations and Admin/Internal Operations & Admin - Inbox Attributes Preview ( Contacts ).png

🔐 GDPR Compliance

Data Protection Measures

  • PII Storage: Attribute values may contain sensitive PII - encrypted at rest using AES-256
  • Right to Access: Export all attribute values via API for GDPR subject access requests
  • Right to Erasure: Cascade delete attribute values when contact is deleted
  • Data Minimization: Only store necessary custom fields, avoid redundant data collection
  • Audit Logging: Track who created/modified attribute schemas and values (change history)
  • Data Retention: Attribute values follow contact retention policies (configurable)

👥 FRAME 8: Team Inbox Features

🎯 Purpose

The Team Inbox enables collaborative conversation management with shared visibility, intelligent assignment, collision detection, private notes, and workload balancing. Multiple agents can work together on conversations while avoiding duplicate responses, tracking accountability, and maintaining context through @mentions and internal notes. The system supports both manual and automated assignment strategies (round-robin, load-balanced, skill-based) with real-time updates via WebSocket.

✨ Core Team Features

7 Essential Team Collaboration Capabilities

👀 Shared Visibility

All team members see unassigned conversations and can claim them. Filter by team, assignee, or status.

🎯 Assignment Engine

Auto-assign via round-robin, load-balanced (least busy), or skill-based routing. Manual assignment supported.

⚠️ Collision Detection

Real-time typing indicators show when another agent is composing. Prevents duplicate responses.

📝 Private Notes

Internal notes visible only to team. @mention colleagues to notify them of important context.

@ Mentions

Tag team members with @username to notify them. Mentions tracked in notifications panel.

📊 Workload Management

Set max conversations per agent. Auto-assignment pauses when agent reaches capacity.

🚪 Away Status

Agents mark themselves as away/offline. System auto-reassigns their conversations to available teammates.

🔧 Backend Services

1. TeamInboxService

Responsibility: Orchestrate team inbox operations

Key Methods:

  • getTeamInboxView(teamId, filters) - Retrieve team conversations with filters
  • claimConversation(conversationId, userId) - Agent claims unassigned conversation
  • transferConversation(conversationId, fromUserId, toUserId) - Transfer between agents
  • getTeamWorkload(teamId) - View active conversations per agent
  • broadcastTypingIndicator(conversationId, userId, isTyping) - Collision prevention

2. AssignmentEngine

Responsibility: Intelligent conversation routing

Assignment Strategies:

  • roundRobinAssignment(teamId) - Distribute evenly in rotation
  • loadBalancedAssignment(teamId) - Assign to agent with fewest active conversations
  • skillBasedAssignment(conversationId, requiredSkills) - Match agent expertise
  • priorityAssignment(conversationId, priority) - Route high-priority to senior agents
  • checkAgentAvailability(userId) - Verify agent is online and under capacity

3. PresenceService

Responsibility: Track agent online/offline status

Key Methods:

  • setUserStatus(userId, status) - Update status (online, away, busy, offline)
  • getUserStatus(userId) - Check if agent is available
  • handleStatusChange(userId, newStatus) - Trigger reassignment if away
  • broadcastPresenceUpdate(userId) - Notify team via WebSocket

🔌 API Endpoints

Team Inbox Endpoints (15 total)

Method Endpoint Description Request Body
GET /api/inbox/team/:teamId Get team inbox conversations Query: status, assignee, priority
POST /api/inbox/assign Manually assign conversation { conversationId, assignToUserId }
POST /api/inbox/claim Agent claims unassigned conversation { conversationId }
POST /api/inbox/transfer Transfer conversation to another agent { conversationId, toUserId, reason }
POST /api/inbox/auto-assign Auto-assign via strategy { conversationId, strategy: 'round_robin'|'load_balanced' }
GET /api/inbox/team/:teamId/workload View team workload distribution -
POST /api/inbox/notes Add private note to conversation { conversationId, content, mentions: [userId1] }
GET /api/inbox/conversations/:id/notes Get all notes for conversation -
DELETE /api/inbox/notes/:id Delete private note -
POST /api/inbox/typing Send typing indicator { conversationId, isTyping: true|false }
GET /api/inbox/conversations/:id/viewers See who's currently viewing conversation -
PUT /api/users/:id/status Update agent status { status: 'online'|'away'|'busy'|'offline' }
GET /api/inbox/team/:teamId/presence Get team presence status -
POST /api/inbox/reassign-bulk Bulk reassign conversations { fromUserId, toUserId, conversationIds: [] }
GET /api/inbox/mentions Get user's @mentions notifications Query: unreadOnly

💾 Database Schema

teams Table

CREATE TABLE teams ( id BIGSERIAL PRIMARY KEY, organization_id BIGINT NOT NULL REFERENCES organizations(id), name VARCHAR(255) NOT NULL, description TEXT, -- Assignment settings auto_assignment_enabled BOOLEAN DEFAULT FALSE, assignment_strategy VARCHAR(50) DEFAULT 'round_robin', -- 'round_robin', 'load_balanced', 'skill_based' max_conversations_per_agent INT DEFAULT 50, -- Workload limit created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW(), INDEX idx_teams_org (organization_id) );

team_members Table

CREATE TABLE team_members ( id BIGSERIAL PRIMARY KEY, team_id BIGINT NOT NULL REFERENCES teams(id) ON DELETE CASCADE, user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE, role VARCHAR(50) DEFAULT 'agent', -- 'lead', 'agent' -- Availability is_active BOOLEAN DEFAULT TRUE, current_status VARCHAR(50) DEFAULT 'offline', -- 'online', 'away', 'busy', 'offline' last_active_at TIMESTAMP, joined_at TIMESTAMP DEFAULT NOW(), UNIQUE INDEX idx_team_members_unique (team_id, user_id), INDEX idx_team_members_user (user_id) );

conversation_assignments Table

CREATE TABLE conversation_assignments ( id BIGSERIAL PRIMARY KEY, conversation_id BIGINT NOT NULL REFERENCES conversations(id) ON DELETE CASCADE, assigned_to_user_id BIGINT REFERENCES users(id), assigned_to_team_id BIGINT REFERENCES teams(id), assigned_by BIGINT REFERENCES users(id), -- Who assigned (null if auto-assigned) assignment_method VARCHAR(50), -- 'manual', 'auto_round_robin', 'auto_load_balanced', 'claimed' assigned_at TIMESTAMP DEFAULT NOW(), INDEX idx_conversation_assignments_conversation (conversation_id), INDEX idx_conversation_assignments_user (assigned_to_user_id), INDEX idx_conversation_assignments_team (assigned_to_team_id) );

conversation_notes Table (Private Notes)

CREATE TABLE conversation_notes ( id BIGSERIAL PRIMARY KEY, conversation_id BIGINT NOT NULL REFERENCES conversations(id) ON DELETE CASCADE, organization_id BIGINT NOT NULL REFERENCES organizations(id), content TEXT NOT NULL, -- Author created_by BIGINT NOT NULL REFERENCES users(id), -- Mentions mentioned_users BIGINT[] DEFAULT '{}', -- Array of user IDs created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW(), INDEX idx_conversation_notes_conversation (conversation_id), INDEX idx_conversation_notes_created_by (created_by), INDEX idx_conversation_notes_mentions USING GIN (mentioned_users) );

🖼️ UI Screenshots Reference

Team Inbox Interface (12 screenshots)

  • Team Inbox Overview: UnifiedBeez_UI_UX/Live Dashboard UI - Inbox/Team Inbox.png
  • Team Inbox Collapsed: UnifiedBeez_UI_UX/Live Dashboard UI - Inbox/Team Inbox - Collapsed.png
  • Team Inbox Info Panel Open: UnifiedBeez_UI_UX/Live Dashboard UI - Inbox/Team Inbox - Info Open.png
  • Team Inbox Dropdown: UnifiedBeez_UI_UX/Live Dashboard UI - Inbox/Team Inbox - Info Open - Dropdown.png
  • Team Attributes View: UnifiedBeez_UI_UX/Live Dashboard UI - Inbox/Team inbox - Team attrributes.png
  • Team Inbox - See All Channels: UnifiedBeez_UI_UX/Live Dashboard UI - Inbox/Team Inbox - See all channels.png
  • Settings - Team: UnifiedBeez_UI_UX/Live Dashboard UI - Dashboard/Settings - Team.png
  • Live Dashboard - Team Members: UnifiedBeez_UI_UX/Live Dashboard UI - Dashboard/Live Dashboard - Team Members.png
  • Insights - Team Members: UnifiedBeez_UI_UX/Live Dashboard UI - Dashboard/Live Dashboard - Insights - Team Members.png
  • Add Team Member: UnifiedBeez_UI_UX/Beehive Dashboard UI/Add team member.png
  • Team Directory: UnifiedBeez_UI_UX/Live Dashboard UI - Internal Operations and Admin/Internal Operations & Admin - Core ( Team Directory ).png
  • Attribute Preview (Teams): UnifiedBeez_UI_UX/Live Dashboard UI - Internal Operations and Admin/Internal Operations & Admin - Inbox Attributes Preview (Teams).png

🔐 GDPR Compliance

Data Protection Measures

  • Private Notes Storage: Notes encrypted at rest, only accessible to team members
  • Assignment History: Track who assigned conversations for accountability and auditing
  • Mention Notifications: Pseudonymized user mentions in analytics (no PII exposure)
  • Presence Data: Online/offline status stored in Redis (ephemeral, auto-expires after 24h)
  • Right to Access: Export team notes and assignment history for GDPR requests
  • Data Retention: Notes follow conversation retention policy (90 days after closure)

🏷️ FRAME 9: Labels & Categorization System

🎯 Purpose

The Labels system provides flexible, color-coded categorization for conversations, enabling organizations to organize and filter conversations by topic, priority, sentiment, or any custom dimension. Labels support multi-label assignments (one conversation can have multiple labels), hierarchical structures (parent-child relationships), auto-labeling via automation rules, and bulk operations. Labels are used extensively in inbox filtering, reporting, and automation workflows.

✨ Label Features

5 Core Label Capabilities

🎨 Color-Coded

Assign hex colors to labels for visual identification. Support for 16+ standard colors.

☑️ Multi-Label Support

Apply multiple labels per conversation (e.g., "Sales", "Urgent", "VIP Customer").

🌳 Hierarchies

Nested labels (e.g., "Support" > "Technical Issue" > "Billing Error").

⚡ Auto-Labeling

Automation rules auto-apply labels based on keywords, sentiment, or channel.

🔍 Filter & Search

Filter inbox by single or multiple labels. Search conversations by label name.

🔧 Backend Services

1. LabelService

Responsibility: Manage label definitions and assignments

Key Methods:

  • createLabel(organizationId, labelData) - Create new label
  • updateLabel(labelId, updates) - Modify label (name, color, description)
  • deleteLabel(labelId) - Remove label (cascade remove from conversations)
  • getLabels(organizationId, filters) - List all labels with hierarchy
  • applyLabel(conversationId, labelId, userId) - Add label to conversation
  • removeLabel(conversationId, labelId) - Remove label from conversation
  • bulkApplyLabels(conversationIds, labelIds) - Bulk label assignment

2. CategoryManagement

Responsibility: Handle hierarchical label structures

Key Methods:

  • createHierarchy(parentLabelId, childLabelData) - Create nested label
  • getLabelTree(organizationId) - Retrieve full label hierarchy
  • moveLabelToParent(labelId, newParentId) - Reorganize hierarchy
  • getConversationsByLabelPath(labelPath) - Query by full path (e.g., "Support/Billing")

🔌 API Endpoints

Label Management Endpoints (10 total)

Method Endpoint Description Request Body
GET /api/labels Get all labels Query: includeHierarchy
GET /api/labels/:id Get single label details -
POST /api/labels Create new label { name, color, description, parentLabelId }
PUT /api/labels/:id Update label { name, color, description }
DELETE /api/labels/:id Delete label -
POST /api/conversations/:id/labels Apply labels to conversation { labelIds: [1, 2, 3] }
DELETE /api/conversations/:id/labels/:labelId Remove label from conversation -
POST /api/labels/bulk-apply Bulk apply labels { conversationIds: [], labelIds: [] }
GET /api/labels/:id/conversations Get all conversations with label Query: page, limit
GET /api/labels/analytics Label usage analytics Query: startDate, endDate

💾 Database Schema

labels Table

CREATE TABLE labels ( id BIGSERIAL PRIMARY KEY, organization_id BIGINT NOT NULL REFERENCES organizations(id), name VARCHAR(100) NOT NULL, color VARCHAR(7), -- Hex color code: #FF5733 description TEXT, -- Hierarchy parent_label_id BIGINT REFERENCES labels(id) ON DELETE CASCADE, -- Usage stats conversation_count INT DEFAULT 0, -- Cached count for performance created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW(), INDEX idx_labels_org (organization_id), INDEX idx_labels_parent (parent_label_id), UNIQUE INDEX idx_labels_org_name (organization_id, name) );

conversation_labels Table (Many-to-Many)

CREATE TABLE conversation_labels ( id BIGSERIAL PRIMARY KEY, conversation_id BIGINT NOT NULL REFERENCES conversations(id) ON DELETE CASCADE, label_id BIGINT NOT NULL REFERENCES labels(id) ON DELETE CASCADE, applied_by BIGINT REFERENCES users(id), -- Who applied the label (null if auto-applied) applied_via VARCHAR(50), -- 'manual', 'automation', 'api' applied_at TIMESTAMP DEFAULT NOW(), UNIQUE INDEX idx_conversation_labels_unique (conversation_id, label_id), INDEX idx_conversation_labels_conversation (conversation_id), INDEX idx_conversation_labels_label (label_id) );

🖼️ UI Screenshots Reference

Labels Interface (5 screenshots)

  • Labels List: UnifiedBeez_UI_UX/Live Dashboard UI - Inbox/Labels.png
  • General Inbox - Labels View: UnifiedBeez_UI_UX/Live Dashboard UI - Inbox/General Inbox - Labels.png
  • Labels Management (Beehive): UnifiedBeez_UI_UX/Beehive Dashboard UI/Labels.png
  • General Inbox - Labels (Beehive): UnifiedBeez_UI_UX/Beehive Dashboard UI/General Inbox - Labels.png
  • Input with Label: UnifiedBeez_UI_UX/Automations Library + Builders - Support and Escalation/Input with label.png

🔐 GDPR Compliance

Data Protection Measures

  • Label Metadata: Label names and descriptions do not contain PII (organizational categorization only)
  • Applied By Tracking: Track which user applied labels for audit purposes
  • Right to Access: Export label assignments as part of conversation data export
  • Data Retention: Label assignments deleted when conversation is deleted (cascade)
  • Analytics Anonymization: Label usage stats do not expose individual customer identifiers

⚙️ FRAME 10: Inbox Settings & Configuration

🎯 Purpose

The Inbox Settings module provides comprehensive configuration options for customizing inbox behavior, appearance, notifications, and preferences at both organizational and individual user levels. Settings include working hours, auto-assignment rules, notification preferences, signature management, away messages, and channel-specific configurations. Settings are validated and persisted in PostgreSQL with real-time updates via WebSocket.

⚙️ Settings Categories

6 Settings Sections in Inbox Module

🏢 General Settings
  • Working hours & timezone
  • Auto-away status
  • Default conversation view
  • Message retention policy
🔔 Notifications
  • Email notifications
  • Browser push notifications
  • Desktop notifications
  • Mention alerts
🎯 Assignment Rules
  • Auto-assignment strategy
  • Max conversations per agent
  • Skill-based routing
  • Priority handling
📝 Templates
  • Manage templates (see Frame 6)
  • Email signatures
  • Away messages
  • Quick replies shortcuts
🏷️ Attributes & Labels
  • Custom attributes (see Frame 7)
  • Label management (see Frame 9)
  • Contact fields configuration
📡 Channel Settings
  • WhatsApp configuration
  • Email SMTP/IMAP
  • Social media connections
  • Channel-specific rules

🔧 Backend Services

1. SettingsService

Responsibility: Manage inbox settings and preferences

Key Methods:

  • getSettings(organizationId, scope) - Retrieve settings by scope (org, team, user)
  • updateSettings(scope, settingsData) - Update settings (with validation)
  • getDefaultSettings() - Return default settings for new organizations
  • validateSettings(settingsData) - Validate settings before saving
  • exportSettings(organizationId) - Export settings as JSON
  • importSettings(organizationId, settingsJson) - Bulk import settings

2. ConfigurationManagement

Responsibility: Handle multi-level settings hierarchy

Key Methods:

  • resolveSettings(userId) - Merge org, team, and user settings (inheritance)
  • getEffectiveSettings(userId, key) - Get final setting value (user override > team > org)
  • resetToDefaults(scope, settingKey) - Reset specific setting to default

🔌 API Endpoints

Settings Management Endpoints (8 total)

Method Endpoint Description Request Body
GET /api/inbox/settings Get current user's inbox settings -
PUT /api/inbox/settings Update user inbox settings { notifications, workingHours, preferences }
GET /api/inbox/settings/organization Get organization-level settings -
PUT /api/inbox/settings/organization Update organization settings (admin only) { autoAssignment, retentionPolicy, ... }
GET /api/inbox/settings/team/:teamId Get team-level settings -
PUT /api/inbox/settings/team/:teamId Update team settings { maxConversationsPerAgent, workingHours }
POST /api/inbox/settings/reset Reset settings to defaults { scope: 'user'|'team'|'organization', keys: [] }
GET /api/inbox/settings/export Export settings as JSON Query: scope

💾 Database Schema

inbox_settings Table

CREATE TABLE inbox_settings ( id BIGSERIAL PRIMARY KEY, organization_id BIGINT NOT NULL REFERENCES organizations(id), -- Scope scope VARCHAR(50) NOT NULL, -- 'organization', 'team', 'user' scope_id BIGINT, -- team_id or user_id (null for organization scope) -- Settings (JSONB for flexibility) settings JSONB NOT NULL DEFAULT '{}', -- Example structure: -- { -- "general": { "workingHours": "9-17", "timezone": "America/New_York" }, -- "notifications": { "email": true, "push": false, "mentions": true }, -- "autoAssignment": { "enabled": true, "strategy": "round_robin" }, -- "preferences": { "defaultView": "mine", "soundEnabled": true } -- } created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW(), INDEX idx_inbox_settings_org (organization_id), INDEX idx_inbox_settings_scope (scope, scope_id), UNIQUE INDEX idx_inbox_settings_unique (organization_id, scope, scope_id) );

user_preferences Table (User-Specific Settings)

CREATE TABLE user_preferences ( id BIGSERIAL PRIMARY KEY, user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE, -- Preferences preferences JSONB NOT NULL DEFAULT '{}', -- { -- "inbox": { "defaultFilter": "unassigned", "compactView": false }, -- "notifications": { "email": true, "desktop": true, "sound": false }, -- "workingHours": { "monday": "9-17", "tuesday": "9-17", ... }, -- "signature": "Best regards,\nJohn Doe", -- "awayMessage": "I'm currently unavailable. I'll respond shortly." -- } created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW(), UNIQUE INDEX idx_user_preferences_user (user_id) );

🖼️ UI Screenshots Reference

Settings Interface (4 screenshots)

  • Settings Overview: UnifiedBeez_UI_UX/Live Dashboard UI - Dashboard/Settings.png
  • Settings - Notifications: UnifiedBeez_UI_UX/Live Dashboard UI - Dashboard/Settings - Notifications.png
  • Settings - Preference: UnifiedBeez_UI_UX/Live Dashboard UI - Dashboard/Settings - Preference.png
  • Inbox Settings - General Templates: UnifiedBeez_UI_UX/Live Dashboard UI - Inbox/Inbox Settings - General Templates.png

🔐 GDPR Compliance

Data Protection Measures

  • Settings Storage: User preferences (working hours, signatures) do not contain customer PII
  • Away Messages: Away messages encrypted at rest (may contain personal contact info)
  • Right to Access: Export user preferences as part of GDPR data export
  • Data Retention: Settings deleted when user account is deleted (cascade)
  • Audit Logging: Track who changed organization-level settings for compliance

⚡ FRAME 11: Real-Time Communication (WebSocket)

🎯 Purpose

The Real-Time Communication layer enables instant bidirectional message delivery between the UnifiedBeez backend and connected clients (agents, customers) using Socket.IO and WebSocket protocol. This system powers live message delivery, typing indicators, presence status, collision detection, and real-time UI updates across the entire platform. The architecture uses Redis pub/sub for multi-instance synchronization, JWT authentication for secure connections, and AWS ECS Fargate with sticky sessions for scalable WebSocket hosting.

🔌 Socket.IO Architecture

Socket.IO + Redis + ECS Fargate Architecture

💻📱
Clients (Web, Mobile)

Socket.IO Client Library (v4.8.1)

↕️
⚖️
Application Load Balancer

Sticky sessions enabled (AWSALB cookie)

↕️
🐳
ECS Task 1

Socket.IO Server

🐳
ECS Task 2

Socket.IO Server

🐳
ECS Task N

Socket.IO Server

↕️
🔄
ElastiCache Redis (Pub/Sub)

Synchronize events across all Socket.IO instances

🔧 Backend Services

1. WebSocketGateway (NestJS Gateway)

Responsibility: Handle WebSocket connections and events

Implementation:

@WebSocketGateway({ cors: { origin: process.env.FRONTEND_URL, credentials: true }, transports: ['websocket', 'polling'], namespace: '/messages' }) export class MessagesGateway { @WebSocketServer() server: Server; constructor( private readonly socketService: SocketService, private readonly redisAdapter: RedisAdapter ) {} // Connection lifecycle async handleConnection(client: Socket) { // Authenticate client via JWT const user = await this.validateToken(client.handshake.auth.token); if (!user) return client.disconnect(); // Join user-specific room client.join(`user:${user.id}`); client.join(`org:${user.organizationId}`); // Update presence status await this.socketService.setUserOnline(user.id); } async handleDisconnect(client: Socket) { const userId = client.data.userId; await this.socketService.setUserOffline(userId); } // Event handlers @SubscribeMessage('message:send') async handleSendMessage(client: Socket, payload: any) { ... } @SubscribeMessage('typing:start') async handleTypingStart(client: Socket, payload: any) { ... } @SubscribeMessage('typing:stop') async handleTypingStop(client: Socket, payload: any) { ... } }

2. SocketService

Responsibility: Manage socket connections and room broadcasting

Key Methods:

  • emitToUser(userId, event, data) - Send event to specific user (all devices)
  • emitToOrganization(orgId, event, data) - Broadcast to all org members
  • emitToConversation(conversationId, event, data) - Send to conversation participants
  • emitToRoom(roomId, event, data) - Generic room broadcast
  • setUserOnline(userId) - Mark user as online in Redis
  • setUserOffline(userId) - Mark user as offline in Redis
  • getUsersInRoom(roomId) - Get list of connected users in room

📡 WebSocket Events

Real-Time Events (20+ events)

Event Name Direction Payload Description
conversation:new Server → Client { conversation, contact } New conversation created
message:received Server → Client { message, conversationId } New message received
message:sent Server → Client { message, conversationId } Message sent successfully
message:status Server → Client { messageId, status } Message status update (delivered, read)
typing:start Client → Server { conversationId } User started typing
typing:stop Client → Server { conversationId } User stopped typing
typing:indicator Server → Client { conversationId, userId, isTyping } Broadcast typing status to other users
presence:update Server → Client { userId, status } User presence changed (online, away, offline)
conversation:assigned Server → Client { conversationId, assignedTo } Conversation assigned to user/team
conversation:status Server → Client { conversationId, status } Conversation status changed
label:applied Server → Client { conversationId, label } Label added to conversation
note:added Server → Client { conversationId, note, mentionedUsers } Private note added with @mentions
contact:updated Server → Client { contactId, updates } Contact attributes updated
conversation:viewing Client → Server { conversationId } User opened conversation (collision detection)
conversation:viewers Server → Client { conversationId, viewers: [] } List of users currently viewing conversation

🔐 JWT Authentication

WebSocket Connection Authentication

// Client-side (React/Next.js) import { io } from 'socket.io-client'; const socket = io('wss://api.unifiedbeez.com/messages', { transports: ['websocket', 'polling'], auth: { token: localStorage.getItem('accessToken') // JWT from login } }); socket.on('connect', () => { console.log('Connected to Socket.IO server'); }); socket.on('message:received', (data) => { // Handle incoming message addMessageToUI(data.message); }); // Server-side (NestJS) @UseGuards(WsJwtAuthGuard) // Validate JWT on connection async handleConnection(client: Socket) { const token = client.handshake.auth.token; try { const decoded = this.jwtService.verify(token); client.data.userId = decoded.sub; client.data.organizationId = decoded.organizationId; // Join rooms client.join(`user:${decoded.sub}`); client.join(`org:${decoded.organizationId}`); } catch (error) { client.disconnect(); } }

💾 Database Schema

redis_sessions Table (Presence Storage)

Note: Presence data stored in Redis (ephemeral), not PostgreSQL

// Redis Key Structure (TTL: 5 minutes) // User presence Key: presence:user:{userId} Value: { status: 'online', lastSeen: 1729681800, socketIds: ['abc123', 'def456'] } TTL: 300 seconds (auto-expire after 5 minutes of inactivity) // Typing indicators Key: typing:conversation:{conversationId} Value: Set of userIds currently typing TTL: 10 seconds (auto-expire after 10 seconds)

active_connections Table (Connection Tracking)

CREATE TABLE active_connections ( id BIGSERIAL PRIMARY KEY, user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE, socket_id VARCHAR(255) NOT NULL, -- Socket.IO connection ID connected_at TIMESTAMP DEFAULT NOW(), last_heartbeat TIMESTAMP DEFAULT NOW(), -- Client metadata user_agent TEXT, ip_address VARCHAR(45), device_type VARCHAR(50), -- 'web', 'mobile', 'desktop' INDEX idx_active_connections_user (user_id), INDEX idx_active_connections_socket (socket_id) );

🖼️ UI Screenshots Reference

Real-Time Chat Interface (7 screenshots)

  • General Inbox - WhatsApp Chat: UnifiedBeez_UI_UX/Live Dashboard UI - Inbox/General Inbox - Whatsapp Chat.png
  • Create New Chat: UnifiedBeez_UI_UX/Live Dashboard UI - Inbox/Create new chat.png
  • Team Inbox (Real-Time): UnifiedBeez_UI_UX/Live Dashboard UI - Inbox/Team Inbox.png
  • Team Inbox Info Open: UnifiedBeez_UI_UX/Live Dashboard UI - Inbox/Team Inbox - Info Open.png
  • Chatbox (Beezaro): UnifiedBeez_UI_UX/Automations Library + Email Builder _All pictures/Chatbox.png
  • Settings - Live Preview Chatbox: UnifiedBeez_UI_UX/Onboarding & Manual Setup/Onboarding & Manual Setup - Onboarding Flow Step 4 - AI Assistant Creation/Onboarding Flow - Step 4_ Settings, Live Preview Chatbox.png
  • Webchat Connection: UnifiedBeez_UI_UX/Onboarding & Manual Setup/Onboarding & Manual Setup - Webchat Connection/Manual Setup Step 7_ Webchat Connection.png

🔐 GDPR Compliance

Data Protection Measures

  • Ephemeral Data: Presence status and typing indicators stored in Redis with TTL (auto-expire, not permanently stored)
  • Connection Logs: Active connections table tracks IP addresses - anonymized after 30 days
  • Message Content: WebSocket events do not store message content (only references)
  • TLS Encryption: All WebSocket connections encrypted via WSS (TLS 1.3)
  • Right to Access: Connection history exportable for GDPR requests (last 30 days)
  • Data Retention: Connection records purged after 90 days automatically

📡 FRAME 12: Multi-Channel Message Routing

🎯 Purpose

The Multi-Channel Routing system provides a unified abstraction layer for sending and receiving messages across 6+ communication channels (WhatsApp, Email, Instagram, Facebook Messenger, Telegram, SMS). Each channel has a dedicated adapter that normalizes incoming messages to a common format, handles channel-specific constraints (24-hour windows, rate limits), and routes messages to the appropriate external API. This architecture enables UnifiedBeez to add new channels without modifying core business logic.

📡 Supported Channels

6 Channel Adapters in UnifiedBeez

💬
WhatsApp Business API
  • Meta Cloud API
  • 24-hour messaging window
  • Template messages
  • Media support (images, videos, docs)
📧
Email (SMTP/IMAP)
  • SMTP sending (AWS SES)
  • IMAP polling for inbound
  • HTML/Plain text support
  • Attachments via S3
📷
Instagram Direct
  • Instagram Graph API
  • 7-day response window
  • Story replies
  • Media sharing
💬
Facebook Messenger
  • Messenger Platform API
  • 7-day response window
  • Quick replies, buttons
  • Rich templates
✈️
Telegram
  • Telegram Bot API
  • No messaging window
  • Inline keyboards
  • Media, stickers, polls
💬
SMS (Twilio)
  • Twilio Messaging API
  • No messaging window
  • Text only (160 chars)
  • International support

🔧 Backend Services

1. ChannelIntegrationService

Responsibility: Orchestrate channel adapters and message routing

Key Methods:

  • sendMessage(channel, to, content, options) - Route outbound message to appropriate adapter
  • receiveMessage(channel, rawPayload) - Process inbound message from webhook
  • getChannelStatus(channelId) - Check channel connection health
  • retryFailedMessage(messageId) - Retry failed message delivery
  • handleWebhook(channel, payload, signature) - Verify and process webhooks

2. MessageRouter

Responsibility: Normalize and route messages

Key Methods:

  • normalizeIncoming(channel, rawMessage) - Convert to UnifiedBeez message format
  • normalizeOutgoing(channel, unifiedMessage) - Convert to channel-specific format
  • validateChannelConstraints(channel, message) - Check 24-hour window, rate limits, etc.
  • selectAdapter(channel) - Return appropriate adapter instance

🔌 Channel Adapters

Adapter Pattern (All Channels)

Each channel adapter implements a common interface:

// Base Adapter Interface interface IChannelAdapter { // Send message sendMessage(to: string, content: any, options?: any): Promise; // Normalize incoming webhook normalizeIncoming(payload: any): UnifiedMessage; // Validate webhook signature validateWebhook(payload: any, signature: string): boolean; // Check connection health checkHealth(): Promise; // Get channel capabilities getCapabilities(): ChannelCapabilities; } // WhatsApp Adapter Implementation @Injectable() export class WhatsAppAdapter implements IChannelAdapter { constructor( private readonly httpService: HttpService, private readonly configService: ConfigService ) {} async sendMessage(to: string, content: any, options?: any): Promise { const phoneNumberId = options.phoneNumberId; const accessToken = options.accessToken; const response = await this.httpService.post( `https://graph.facebook.com/v18.0/${phoneNumberId}/messages`, { messaging_product: 'whatsapp', to: to, type: content.type, // 'text', 'image', 'template' ...content.payload }, { headers: { 'Authorization': `Bearer ${accessToken}` } } ); return { success: true, messageId: response.data.messages[0].id }; } normalizeIncoming(payload: any): UnifiedMessage { const message = payload.entry[0]?.changes[0]?.value?.messages[0]; return { channel: 'whatsapp', channelMessageId: message.id, from: message.from, content: message.text?.body || message.caption, contentType: message.type, // 'text', 'image', 'video' timestamp: new Date(parseInt(message.timestamp) * 1000), attachments: this.extractAttachments(message) }; } validateWebhook(payload: any, signature: string): boolean { const secret = this.configService.get('WHATSAPP_WEBHOOK_SECRET'); const hash = crypto.createHmac('sha256', secret) .update(JSON.stringify(payload)) .digest('hex'); return signature === `sha256=${hash}`; } }

🔌 API Endpoints

Channel Integration Endpoints (10 total)

Method Endpoint Description Request Body
GET /api/channels Get all connected channels -
POST /api/channels/whatsapp Connect WhatsApp Business API { phoneNumberId, accessToken, wabaId }
POST /api/channels/email Connect email (SMTP/IMAP) { email, smtpHost, imapHost, credentials }
POST /api/channels/social Connect Instagram/Facebook Messenger { platform, pageId, accessToken }
POST /api/channels/telegram Connect Telegram bot { botToken }
POST /api/channels/sms Connect Twilio SMS { accountSid, authToken, phoneNumber }
DELETE /api/channels/:id Disconnect channel -
POST /api/webhooks/whatsapp WhatsApp webhook receiver Meta webhook payload
POST /api/webhooks/instagram Instagram webhook receiver Instagram Graph API payload
GET /api/channels/:id/health Check channel connection health -

💾 Database Schema

channel_connections Table

CREATE TABLE channel_connections ( id BIGSERIAL PRIMARY KEY, organization_id BIGINT NOT NULL REFERENCES organizations(id), -- Channel info channel VARCHAR(50) NOT NULL, -- 'whatsapp', 'email', 'instagram', etc. name VARCHAR(255) NOT NULL, -- User-friendly name -- Connection status status VARCHAR(50) DEFAULT 'active', -- 'active', 'disconnected', 'error' is_primary BOOLEAN DEFAULT FALSE, -- Primary channel for this type -- Credentials (encrypted) credentials JSONB NOT NULL, -- { apiKey, accessToken, etc. } -- Channel-specific config config JSONB DEFAULT '{}', -- WhatsApp: { phoneNumberId, wabaId, businessAccountId } -- Email: { smtpHost, smtpPort, imapHost, imapPort } -- Social: { pageId, accountId } -- Health monitoring last_health_check_at TIMESTAMP, last_message_received_at TIMESTAMP, error_count INT DEFAULT 0, last_error TEXT, last_error_at TIMESTAMP, created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW(), -- Indexes INDEX idx_channel_connections_org (organization_id), INDEX idx_channel_connections_channel (channel), UNIQUE INDEX idx_channel_connections_org_channel_primary (organization_id, channel, is_primary) WHERE is_primary = TRUE );

channel_adapters Table (Configuration)

CREATE TABLE channel_adapters ( id BIGSERIAL PRIMARY KEY, channel VARCHAR(50) NOT NULL UNIQUE, -- 'whatsapp', 'email', etc. adapter_class VARCHAR(255) NOT NULL, -- 'WhatsAppAdapter' -- Capabilities capabilities JSONB DEFAULT '{}', -- { -- supportsMedia: true, -- supportsTemplates: true, -- supportsButtons: false, -- messagingWindow: 24, -- rateLimit: { max: 1000, per: 'hour' } -- } -- Configuration default_config JSONB DEFAULT '{}', is_enabled BOOLEAN DEFAULT TRUE, created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW() );

🔐 GDPR Compliance

Data Protection Measures

  • Credentials Storage: Channel API keys and tokens encrypted at rest using AWS KMS
  • Webhook Payloads: Incoming message payloads normalized and original payload discarded (no raw PII storage)
  • Message Content: Only normalized message content stored (see messages table in Frame 4)
  • Channel Health Logs: Connection errors do not log customer message content
  • Right to Access: Export channel connection metadata (no API credentials exposed)
  • Data Retention: Disconnected channels purged after 90 days (credentials deleted immediately)