DATABASE.md - ScapBot Database Schema#

Tổng quan#

Database: PostgreSQL 16 với pgvector extension Kiến trúc: Multi-tenant, AI Assistant-centric, Module-based Isolation: Data isolated per AI Assistant Retention: Vĩnh viễn với partitioning


Core Concept#

┌─────────────────────────────────────────────────────────────────────────────┐
│                           SCAPBOT CORE CONCEPT                               │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  User đăng ký ──► Tenant ──► Cấp 1 AI Assistant (miễn phí)                  │
│                                     │                                        │
│                                     ▼                                        │
│                    ┌────────────────────────────────┐                       │
│                    │       AI ASSISTANT             │                       │
│                    │  (Trung tâm của mọi thứ)      │                       │
│                    └────────────────────────────────┘                       │
│                         │              │                                     │
│           ┌─────────────┴──────────────┴─────────────┐                      │
│           ▼                                          ▼                      │
│    ┌─────────────┐                          ┌─────────────┐                 │
│    │   MODULES   │                          │  PLATFORMS  │                 │
│    │ (Kích hoạt) │                          │ (Kết nối)   │                 │
│    └─────────────┘                          └─────────────┘                 │
│    • AI-CHAT                                • Facebook Page                 │
│    • AI-SALE                                • Zalo OA                       │
│    • AI-MARKETING                           • Telegram Bot                  │
│    • AI-SHIP                                • Website                       │
│    • AI-TAX                                 • Email                         │
│    • AI-CALL                                • Shipping Provider             │
│                                                                              │
│  ═══════════════════════════════════════════════════════════════════════   │
│                                                                              │
│                    DATA ISOLATION PER ASSISTANT                             │
│                    ════════════════════════════                             │
│                                                                              │
│    Mỗi AI Assistant có:                                                     │
│    • Knowledge Base riêng                                                   │
│    • Chat History riêng                                                     │
│    • Embeddings riêng                                                       │
│    • Learning Patterns riêng                                                │
│    • Module Data riêng (Orders, Campaigns, etc.)                           │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

Nguyên tắc quan trọng#

1. One Platform = One Assistant#

┌─────────────────────────────────────────────────────────────────────────────┐
│                      1 PLATFORM = 1 ASSISTANT                               │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  ✅ ĐÚNG:                           ❌ SAI (gây conflict):                  │
│                                                                              │
│  Assistant A                        Assistant A ──┐                         │
│      │                                            ├──► Facebook Page 1      │
│      └──► Facebook Page 1           Assistant B ──┘                         │
│                                                                              │
│  Assistant B                        → 2 AI cùng bật AI Mode = CONFLICT!     │
│      │                                                                       │
│      └──► Facebook Page 2                                                   │
│                                                                              │
│  ─────────────────────────────────────────────────────────────────────────  │
│                                                                              │
│  Áp dụng cho TẤT CẢ platform types:                                        │
│  • Facebook Page      → 1 Assistant                                         │
│  • Zalo OA            → 1 Assistant                                         │
│  • Telegram Bot       → 1 Assistant                                         │
│  • Website (chat)     → 1 Assistant                                         │
│  • Email account      → 1 Assistant                                         │
│  • Shipping Provider  → 1 Assistant                                         │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

2. Data Partitioning by Assistant#

┌─────────────────────────────────────────────────────────────────────────────┐
│                    PARTITION BY ASSISTANT_ID                                 │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  Tại sao KHÔNG partition by tenant_id?                                      │
│  ─────────────────────────────────────                                      │
│  • 1 tenant có nhiều assistants                                             │
│  • Mỗi assistant có data riêng biệt                                        │
│  • Vector search cần isolation → partition by assistant_id                  │
│                                                                              │
│  ═══════════════════════════════════════════════════════════════════════   │
│                                                                              │
│  HNSW Index + Partition = Accurate Results                                  │
│  ─────────────────────────────────────────                                  │
│                                                                              │
│  Query: "Tìm similar messages của Assistant A"                              │
│                                                                              │
│  ┌─────────────────┐   ┌─────────────────┐   ┌─────────────────┐           │
│  │  Partition 0    │   │  Partition 1    │   │  Partition 2    │           │
│  │  (Assistant A)  │   │  (Assistant B)  │   │  (Assistant C)  │           │
│  │  ┌───────────┐  │   │                 │   │                 │           │
│  │  │HNSW Index │  │   │    SKIPPED      │   │    SKIPPED      │           │
│  │  │  (scan)   │  │   │                 │   │                 │           │
│  │  └───────────┘  │   │                 │   │                 │           │
│  └─────────────────┘   └─────────────────┘   └─────────────────┘           │
│         │                                                                    │
│         ▼                                                                    │
│  Full accuracy results (không bị filter loss)                               │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

Database Schema Overview#

┌─────────────────────────────────────────────────────────────────────────────┐
│                         ScapBot Database Schema                              │
│                     AI Assistant-Centric Architecture                        │
│                     + 3-Layer Global Learning System                        │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  CORE (6 tables)                      AI & LEARNING (6 tables)              │
│  ═══════════════                      ════════════════════════              │
│  ┌─────────────┐                      ┌─────────────────────────┐           │
│  │  tenants    │                      │  ai_suggestions         │           │
│  └──────┬──────┘                      ├─────────────────────────┤           │
│         │                             │  ai_feedback            │           │
│         ▼                             ├─────────────────────────┤           │
│  ┌─────────────┐                      │  ai_learning_patterns   │           │
│  │   users     │                      ├─────────────────────────┤           │
│  └─────────────┘                      │  ai_contexts            │           │
│         │                             ├─────────────────────────┤           │
│         ▼                             │  conversation_summaries │           │
│  ┌─────────────────┐                  ├─────────────────────────┤           │
│  │ ai_assistants   │◄─────────────────│  sentiment_scores       │           │
│  └────────┬────────┘                  └─────────────────────────┘           │
│           │                                                                  │
│     ┌─────┴─────┐                     KNOWLEDGE BASE (4 tables)             │
│     ▼           ▼                     ═════════════════════════             │
│ ┌────────┐ ┌──────────┐               ┌─────────────────────────┐           │
│ │modules │ │platforms │               │  knowledge_bases        │           │
│ └────────┘ └──────────┘               ├─────────────────────────┤           │
│                                       │  documents              │           │
│  MESSAGING (5 tables)                 ├─────────────────────────┤           │
│  ════════════════════                 │  document_chunks        │           │
│  ┌─────────────────────────┐          ├─────────────────────────┤           │
│  │  contacts               │          │  document_embeddings    │           │
│  ├─────────────────────────┤          └─────────────────────────┘           │
│  │  conversations          │                                                 │
│  ├─────────────────────────┤          SUPPORT (4 tables)                    │
│  │  messages (PARTITIONED) │          ══════════════════                    │
│  ├─────────────────────────┤          ┌─────────────────────────┐           │
│  │  message_embeddings     │          │  tags                   │           │
│  ├─────────────────────────┤          ├─────────────────────────┤           │
│  │  attachments            │          │  conversation_tags      │           │
│  └─────────────────────────┘          ├─────────────────────────┤           │
│                                       │  templates              │           │
│  GLOBAL LEARNING (3 tables) ⭐        ├─────────────────────────┤           │
│  ════════════════════════════         │  assistant_modules      │           │
│  ┌─────────────────────────┐          └─────────────────────────┘           │
│  │  industries             │                                                 │
│  ├─────────────────────────┤                                                 │
│  │  global_patterns        │                                                 │
│  ├─────────────────────────┤                                                 │
│  │  industry_templates     │                                                 │
│  └─────────────────────────┘                                                 │
│                                                                              │
│  TOTAL: 27 tables                                                           │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

Entity Relationship Diagram#

┌─────────────────────────────────────────────────────────────────────────────┐
│                           ENTITY RELATIONSHIPS                               │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  tenants                                                                     │
│     │                                                                        │
│     ├──────────────────► users (staff/agents)                               │
│     │                        │                                               │
│     │                        └──► templates                                  │
│     │                                                                        │
│     └──────────────────► ai_assistants ◄─────────────────────────────┐      │
│                               │                                       │      │
│         ┌─────────────────────┼─────────────────────┐                │      │
│         │                     │                     │                │      │
│         ▼                     ▼                     ▼                │      │
│    assistant_modules     platforms            knowledge_bases        │      │
│         │                     │                     │                │      │
│         ▼                     │                     ▼                │      │
│      modules                  │                 documents            │      │
│                               │                     │                │      │
│                               ▼                     ▼                │      │
│                           contacts           document_chunks         │      │
│                               │                     │                │      │
│                               ▼                     ▼                │      │
│                         conversations        document_embeddings     │      │
│                               │                                      │      │
│         ┌─────────────────────┼─────────────────────┐               │      │
│         │                     │                     │               │      │
│         ▼                     ▼                     ▼               │      │
│  conversation_tags        messages           ai_contexts            │      │
│         │                     │                     │               │      │
│         ▼                     ├──► attachments      │               │      │
│       tags                    │                     │               │      │
│                               ├──► message_embeddings               │      │
│                               │                     │               │      │
│                               ├──► sentiment_scores │               │      │
│                               │                     │               │      │
│                               └──► ai_suggestions ──┼───────────────┘      │
│                                           │         │                       │
│                                           ▼         ▼                       │
│                                      ai_feedback   ai_learning_patterns    │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

Danh sách Tables (27)#

#BảngLoạiMục đíchPartition
1tenantsCoreDoanh nghiệp/khách hàng đăng ký-
2usersCoreStaff/Agents trong tenant-
3ai_assistantsCoreAI Assistants (1 default + N)-
4modulesCoreSystem modules (chat, sale, etc.)-
5assistant_modulesCoreModules activated per assistant-
6platformsCoreFacebook, Zalo… (1:1 với assistant)-
7contactsMessagingKhách hàng từ platforms-
8conversationsMessagingThread hội thoại-
9messagesMessagingTin nhắn✅ Monthly
10message_embeddingsMessagingVector embeddings tin nhắn✅ By Assistant
11attachmentsMessagingFiles đính kèm-
12knowledge_basesKnowledgeCollections tài liệu per assistant-
13documentsKnowledgeTài liệu (PDF, DOCX, URL…)-
14document_chunksKnowledgeChunks của tài liệu-
15document_embeddingsKnowledgeVector embeddings tài liệu✅ By Assistant
16ai_suggestionsAIGợi ý trả lời-
17ai_feedbackAIUser feedback on suggestions-
18ai_learning_patternsAILearned patterns per assistant-
19ai_contextsAIContext window snapshots-
20conversation_summariesAITóm tắt theo chunk-
21sentiment_scoresAIPhân tích cảm xúc-
22tagsSupportLabels cho conversations-
23conversation_tagsSupportMany-to-many tags-
24templatesSupportReply templates-
25industriesGlobal LearningDanh mục ngành nghề-
26global_patternsGlobal LearningPatterns từ toàn platform-
27industry_templatesGlobal LearningTemplates theo ngành-

Chi tiết Schema#

Extensions Required#

-- Vector similarity search
CREATE EXTENSION IF NOT EXISTS vector;

-- UUID generation
CREATE EXTENSION IF NOT EXISTS pgcrypto;

-- Full-text search (Vietnamese)
CREATE EXTENSION IF NOT EXISTS unaccent;

1. TENANTS (Doanh nghiệp/Cá nhân đăng ký)#

CREATE TABLE tenants (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),

    -- Identity
    name            VARCHAR(255) NOT NULL,
    email           VARCHAR(255) UNIQUE NOT NULL,
    phone           VARCHAR(50),

    -- Subscription
    plan            VARCHAR(50) DEFAULT 'free',  -- free, pro, enterprise
    max_assistants  INTEGER DEFAULT 1,           -- Số AI được tạo

    -- Settings
    settings        JSONB DEFAULT '{
        "timezone": "Asia/Ho_Chi_Minh",
        "language": "vi",
        "notifications": {
            "email": true,
            "push": false
        }
    }',

    -- Status
    status          VARCHAR(20) DEFAULT 'active',

    -- Timestamps
    created_at      TIMESTAMPTZ DEFAULT NOW(),
    updated_at      TIMESTAMPTZ DEFAULT NOW()
);

-- Indexes
CREATE INDEX idx_tenants_email ON tenants(email);
CREATE INDEX idx_tenants_status ON tenants(status);
CREATE INDEX idx_tenants_plan ON tenants(plan);

2. USERS (Staff/Agents)#

CREATE TABLE users (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id       UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,

    -- Auth
    email           VARCHAR(255) NOT NULL,
    password_hash   VARCHAR(255),

    -- Profile
    name            VARCHAR(255) NOT NULL,
    avatar_url      TEXT,

    -- Role & Permissions
    role            VARCHAR(50) DEFAULT 'agent',  -- owner, admin, manager, agent
    permissions     JSONB DEFAULT '[]',

    -- Status
    status          VARCHAR(20) DEFAULT 'active',
    last_login      TIMESTAMPTZ,

    -- Timestamps
    created_at      TIMESTAMPTZ DEFAULT NOW(),
    updated_at      TIMESTAMPTZ DEFAULT NOW(),

    UNIQUE(tenant_id, email)
);

-- Indexes
CREATE INDEX idx_users_tenant ON users(tenant_id);
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_users_role ON users(tenant_id, role);

3. AI_ASSISTANTS (Trung tâm của hệ thống)#

CREATE TABLE ai_assistants (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id       UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,

    -- Identity
    name            VARCHAR(255) NOT NULL,
    slug            VARCHAR(100) NOT NULL,
    avatar_url      TEXT,
    description     TEXT,

    -- AI Configuration
    config          JSONB DEFAULT '{
        "tone": "professional",
        "language": "vi",
        "auto_reply_delay_ms": 1000,
        "confidence_threshold": 0.8,
        "system_prompt": null,
        "forbidden_topics": [],
        "greeting_message": null
    }',

    -- Billing
    is_default      BOOLEAN DEFAULT FALSE,  -- Assistant miễn phí đầu tiên

    -- Stats
    total_conversations INTEGER DEFAULT 0,
    total_messages      INTEGER DEFAULT 0,

    -- Status
    status          VARCHAR(20) DEFAULT 'active',

    -- Timestamps
    created_at      TIMESTAMPTZ DEFAULT NOW(),
    updated_at      TIMESTAMPTZ DEFAULT NOW(),

    UNIQUE(tenant_id, slug)
);

-- Indexes
CREATE INDEX idx_assistants_tenant ON ai_assistants(tenant_id);
CREATE INDEX idx_assistants_status ON ai_assistants(tenant_id, status);
CREATE INDEX idx_assistants_default ON ai_assistants(tenant_id) WHERE is_default = TRUE;

Config JSONB Structure:

{
    "tone": "professional",
    "language": "vi",
    "auto_reply_delay_ms": 1000,
    "confidence_threshold": 0.8,
    "system_prompt": "Bạn là trợ lý bán hàng chuyên nghiệp...",
    "forbidden_topics": ["chính trị", "tôn giáo"],
    "greeting_message": "Xin chào! Tôi có thể giúp gì cho bạn?",
    "handoff_keywords": ["gặp người", "nhân viên"],
    "working_hours": {
        "enabled": true,
        "timezone": "Asia/Ho_Chi_Minh",
        "schedule": {
            "mon": {"start": "08:00", "end": "17:00"},
            "tue": {"start": "08:00", "end": "17:00"}
        }
    }
}

4. MODULES (System-defined)#

CREATE TABLE modules (
    id              VARCHAR(50) PRIMARY KEY,  -- 'chat', 'sale', 'marketing'

    -- Info
    name            VARCHAR(100) NOT NULL,
    description     TEXT,
    icon            VARCHAR(50),

    -- Pricing
    price_monthly   DECIMAL(10,2) DEFAULT 0,

    -- Features
    features        JSONB DEFAULT '[]',

    -- Dependencies
    dependencies    TEXT[] DEFAULT '{}',  -- ['chat'] for sale module

    -- Status
    status          VARCHAR(20) DEFAULT 'active',
    sort_order      INTEGER DEFAULT 0,

    created_at      TIMESTAMPTZ DEFAULT NOW()
);

-- Seed data
INSERT INTO modules (id, name, description, price_monthly, dependencies) VALUES
('chat', 'AI-CHAT', 'Trò chuyện với khách hàng đa nền tảng', 200000, '{}'),
('sale', 'AI-SALE', 'Quản lý đơn hàng, upsale, cross-sale', 300000, '{chat}'),
('marketing', 'AI-MARKETING', 'Tối ưu quảng cáo, chiến dịch', 500000, '{chat}'),
('ship', 'AI-SHIP', 'Quản lý vận chuyển, tracking', 200000, '{sale}'),
('tax', 'AI-TAX', 'Hóa đơn, báo cáo thuế', 300000, '{sale}'),
('call', 'AI-CALL', 'Gọi điện tự động', 400000, '{chat}'),
('research', 'AI-RESEARCH', 'Nghiên cứu thị trường, đối thủ', 300000, '{}');

5. ASSISTANT_MODULES (Modules activated per assistant)#

CREATE TABLE assistant_modules (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    assistant_id    UUID NOT NULL REFERENCES ai_assistants(id) ON DELETE CASCADE,
    module_id       VARCHAR(50) NOT NULL REFERENCES modules(id),

    -- Module-specific config
    config          JSONB DEFAULT '{}',

    -- Billing
    activated_at    TIMESTAMPTZ DEFAULT NOW(),
    expires_at      TIMESTAMPTZ,

    -- Status
    status          VARCHAR(20) DEFAULT 'active',

    created_at      TIMESTAMPTZ DEFAULT NOW(),

    UNIQUE(assistant_id, module_id)
);

-- Indexes
CREATE INDEX idx_assistant_modules_assistant ON assistant_modules(assistant_id);
CREATE INDEX idx_assistant_modules_module ON assistant_modules(module_id);
CREATE INDEX idx_assistant_modules_status ON assistant_modules(assistant_id, status);

6. PLATFORMS (1 Platform = 1 Assistant)#

CREATE TABLE platforms (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id       UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
    assistant_id    UUID NOT NULL REFERENCES ai_assistants(id) ON DELETE CASCADE,

    -- Platform info
    type            VARCHAR(50) NOT NULL,
    name            VARCHAR(255) NOT NULL,
    external_id     VARCHAR(255),

    -- Credentials (encrypted in production)
    credentials     JSONB NOT NULL,

    -- AI Mode
    ai_mode_enabled BOOLEAN DEFAULT FALSE,
    ai_mode_config  JSONB DEFAULT '{
        "auto_reply": true,
        "auto_assign": false,
        "escalate_on_negative_sentiment": true,
        "escalate_threshold": -0.5
    }',

    -- Webhook
    webhook_url     TEXT,
    webhook_secret  VARCHAR(255),

    -- Status
    status          VARCHAR(20) DEFAULT 'active',
    last_sync       TIMESTAMPTZ,
    error_message   TEXT,

    created_at      TIMESTAMPTZ DEFAULT NOW(),
    updated_at      TIMESTAMPTZ DEFAULT NOW(),

    -- CONSTRAINT: 1 platform chỉ thuộc 1 assistant trong tenant
    UNIQUE(tenant_id, type, external_id)
);

-- Indexes
CREATE INDEX idx_platforms_tenant ON platforms(tenant_id);
CREATE INDEX idx_platforms_assistant ON platforms(assistant_id);
CREATE INDEX idx_platforms_type ON platforms(tenant_id, type);
CREATE INDEX idx_platforms_status ON platforms(status) WHERE status = 'active';

Platform Types:

TypeCredentials Required
facebookpage_id, page_access_token, app_secret
telegrambot_token
zalooa_id, access_token
whatsappphone_number_id, access_token
viberauth_token
linechannel_access_token, channel_secret
websitewidget_id, allowed_domains
emailimap_host, smtp_host, username, password

7. CONTACTS (Khách hàng)#

CREATE TABLE contacts (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id       UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
    platform_id     UUID NOT NULL REFERENCES platforms(id) ON DELETE CASCADE,

    -- External ID from platform
    external_id     VARCHAR(255) NOT NULL,

    -- Profile
    name            VARCHAR(255),
    avatar_url      TEXT,
    email           VARCHAR(255),
    phone           VARCHAR(50),

    -- Platform-specific metadata
    metadata        JSONB DEFAULT '{}',

    -- AI-relevant fields
    language        VARCHAR(10),
    timezone        VARCHAR(50),

    -- Customer Intelligence (populated by AI)
    customer_profile JSONB DEFAULT '{}',

    -- Stats
    first_contact   TIMESTAMPTZ DEFAULT NOW(),
    last_contact    TIMESTAMPTZ DEFAULT NOW(),
    message_count   INTEGER DEFAULT 0,

    created_at      TIMESTAMPTZ DEFAULT NOW(),
    updated_at      TIMESTAMPTZ DEFAULT NOW(),

    UNIQUE(platform_id, external_id)
);

-- Indexes
CREATE INDEX idx_contacts_tenant ON contacts(tenant_id);
CREATE INDEX idx_contacts_platform ON contacts(platform_id);
CREATE INDEX idx_contacts_external ON contacts(platform_id, external_id);
CREATE INDEX idx_contacts_last_contact ON contacts(tenant_id, last_contact DESC);

-- Full-text search on name
CREATE INDEX idx_contacts_name_search ON contacts
    USING gin(to_tsvector('simple', coalesce(name, '')));

8. CONVERSATIONS (Thread hội thoại)#

CREATE TABLE conversations (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id       UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
    assistant_id    UUID NOT NULL REFERENCES ai_assistants(id),
    platform_id     UUID NOT NULL REFERENCES platforms(id),
    contact_id      UUID NOT NULL REFERENCES contacts(id),

    -- Status
    status          VARCHAR(20) DEFAULT 'open',
    assigned_to     UUID REFERENCES users(id) ON DELETE SET NULL,

    -- AI Metadata
    topic           VARCHAR(255),
    intent          VARCHAR(100),
    priority        INTEGER DEFAULT 0,

    -- Aggregated sentiment
    avg_sentiment   DECIMAL(3,2),

    -- Stats
    message_count   INTEGER DEFAULT 0,
    unread_count    INTEGER DEFAULT 0,
    last_message_at TIMESTAMPTZ,
    last_message_preview TEXT,

    -- AI Mode tracking
    ai_mode_active  BOOLEAN DEFAULT FALSE,
    ai_handled_count INTEGER DEFAULT 0,
    human_handled_count INTEGER DEFAULT 0,

    created_at      TIMESTAMPTZ DEFAULT NOW(),
    updated_at      TIMESTAMPTZ DEFAULT NOW(),
    closed_at       TIMESTAMPTZ
);

-- Indexes
CREATE INDEX idx_conversations_tenant ON conversations(tenant_id);
CREATE INDEX idx_conversations_assistant ON conversations(assistant_id);
CREATE INDEX idx_conversations_contact ON conversations(contact_id);
CREATE INDEX idx_conversations_status ON conversations(assistant_id, status);
CREATE INDEX idx_conversations_assigned ON conversations(tenant_id, assigned_to) WHERE assigned_to IS NOT NULL;
CREATE INDEX idx_conversations_last_message ON conversations(assistant_id, last_message_at DESC);
CREATE INDEX idx_conversations_priority ON conversations(assistant_id, priority DESC) WHERE status = 'open';

9. MESSAGES (PARTITIONED by time)#

CREATE TABLE messages (
    id              UUID NOT NULL DEFAULT gen_random_uuid(),
    tenant_id       UUID NOT NULL,
    assistant_id    UUID NOT NULL,
    conversation_id UUID NOT NULL,
    platform_id     UUID NOT NULL,

    -- Platform-specific identifiers
    external_id     VARCHAR(255),
    reply_to_external_id VARCHAR(255),

    -- Direction
    direction       VARCHAR(10) NOT NULL,

    -- Content
    content_type    VARCHAR(50) NOT NULL,
    content         TEXT,

    -- Platform-specific metadata
    metadata        JSONB DEFAULT '{}',

    -- Original webhook payload
    raw_payload     JSONB,

    -- Sender
    sender_type     VARCHAR(20) NOT NULL,
    sender_id       UUID,

    -- AI fields
    token_count     INTEGER,
    language        VARCHAR(10),
    handled_by      VARCHAR(20),
    ai_confidence   DECIMAL(3,2),

    -- Platform original timestamp
    platform_time   TIMESTAMPTZ,

    created_at      TIMESTAMPTZ NOT NULL DEFAULT NOW(),

    PRIMARY KEY (id, created_at)
) PARTITION BY RANGE (created_at);

-- Create monthly partitions
CREATE TABLE messages_2026_01 PARTITION OF messages FOR VALUES FROM ('2026-01-01') TO ('2026-02-01');
CREATE TABLE messages_2026_02 PARTITION OF messages FOR VALUES FROM ('2026-02-01') TO ('2026-03-01');
-- ... continue for all months
CREATE TABLE messages_default PARTITION OF messages DEFAULT;

-- Indexes
CREATE INDEX idx_messages_conversation ON messages(conversation_id, created_at DESC);
CREATE INDEX idx_messages_assistant ON messages(assistant_id, created_at DESC);
CREATE INDEX idx_messages_platform ON messages(platform_id, created_at DESC);
CREATE INDEX idx_messages_external ON messages(platform_id, external_id);

10. MESSAGE_EMBEDDINGS (PARTITIONED by assistant)#

CREATE TABLE message_embeddings (
    id              UUID NOT NULL DEFAULT gen_random_uuid(),
    tenant_id       UUID NOT NULL,
    assistant_id    UUID NOT NULL,
    message_id      UUID NOT NULL,
    message_time    TIMESTAMPTZ NOT NULL,
    conversation_id UUID NOT NULL,

    -- Embedding vector
    embedding       vector(1536),

    -- Metadata
    model_used      VARCHAR(100) NOT NULL,

    created_at      TIMESTAMPTZ DEFAULT NOW(),

    PRIMARY KEY (id, assistant_id)
) PARTITION BY HASH (assistant_id);

-- Create 32 partitions
CREATE TABLE message_embeddings_p00 PARTITION OF message_embeddings FOR VALUES WITH (MODULUS 32, REMAINDER 0);
CREATE TABLE message_embeddings_p01 PARTITION OF message_embeddings FOR VALUES WITH (MODULUS 32, REMAINDER 1);
-- ... continue for p02 to p31

-- HNSW index for vector search
CREATE INDEX idx_msg_embeddings_vector ON message_embeddings
    USING hnsw (embedding vector_cosine_ops)
    WITH (m = 24, ef_construction = 128);

-- Filter indexes
CREATE INDEX idx_msg_embeddings_assistant ON message_embeddings(assistant_id);
CREATE INDEX idx_msg_embeddings_conversation ON message_embeddings(conversation_id);

11. ATTACHMENTS#

CREATE TABLE attachments (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id       UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
    assistant_id    UUID NOT NULL,
    message_id      UUID NOT NULL,
    message_time    TIMESTAMPTZ NOT NULL,

    -- File info
    filename        VARCHAR(255) NOT NULL,
    mime_type       VARCHAR(100) NOT NULL,
    size            BIGINT NOT NULL,

    -- Storage location (MinIO)
    bucket          VARCHAR(100) NOT NULL,
    path            TEXT NOT NULL,

    -- AI-generated content
    ai_description  TEXT,
    ai_transcript   TEXT,

    created_at      TIMESTAMPTZ DEFAULT NOW()
);

-- Indexes
CREATE INDEX idx_attachments_message ON attachments(message_id, message_time);
CREATE INDEX idx_attachments_assistant ON attachments(assistant_id);

12. KNOWLEDGE_BASES (per Assistant)#

CREATE TABLE knowledge_bases (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id       UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
    assistant_id    UUID NOT NULL REFERENCES ai_assistants(id) ON DELETE CASCADE,

    -- Info
    name            VARCHAR(255) NOT NULL,
    description     TEXT,
    type            VARCHAR(50) NOT NULL,

    -- Settings
    settings        JSONB DEFAULT '{
        "chunk_size": 500,
        "chunk_overlap": 50,
        "embedding_model": "text-embedding-3-small"
    }',

    -- Stats
    document_count  INTEGER DEFAULT 0,
    chunk_count     INTEGER DEFAULT 0,
    total_tokens    INTEGER DEFAULT 0,

    -- Status
    status          VARCHAR(20) DEFAULT 'active',

    created_at      TIMESTAMPTZ DEFAULT NOW(),
    updated_at      TIMESTAMPTZ DEFAULT NOW(),

    UNIQUE(assistant_id, name)
);

-- Indexes
CREATE INDEX idx_knowledge_bases_assistant ON knowledge_bases(assistant_id);
CREATE INDEX idx_knowledge_bases_type ON knowledge_bases(assistant_id, type);

13. DOCUMENTS#

CREATE TABLE documents (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id       UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
    assistant_id    UUID NOT NULL,
    knowledge_base_id UUID NOT NULL REFERENCES knowledge_bases(id) ON DELETE CASCADE,

    -- Document info
    title           VARCHAR(500) NOT NULL,
    description     TEXT,
    source_type     VARCHAR(50) NOT NULL,

    -- Source details
    source_url      TEXT,
    file_path       TEXT,
    file_bucket     VARCHAR(100),
    mime_type       VARCHAR(100),
    file_size       BIGINT,

    -- Content
    raw_content     TEXT,
    content_hash    VARCHAR(64),

    -- Processing status
    status          VARCHAR(20) DEFAULT 'pending',
    error_message   TEXT,
    processed_at    TIMESTAMPTZ,

    -- Stats
    chunk_count     INTEGER DEFAULT 0,
    token_count     INTEGER DEFAULT 0,

    -- Metadata
    metadata        JSONB DEFAULT '{}',
    language        VARCHAR(10),

    created_at      TIMESTAMPTZ DEFAULT NOW(),
    updated_at      TIMESTAMPTZ DEFAULT NOW()
);

-- Indexes
CREATE INDEX idx_documents_assistant ON documents(assistant_id);
CREATE INDEX idx_documents_kb ON documents(knowledge_base_id);
CREATE INDEX idx_documents_status ON documents(assistant_id, status);
CREATE INDEX idx_documents_hash ON documents(assistant_id, content_hash);

14. DOCUMENT_CHUNKS#

CREATE TABLE document_chunks (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id       UUID NOT NULL,
    assistant_id    UUID NOT NULL,
    document_id     UUID NOT NULL REFERENCES documents(id) ON DELETE CASCADE,
    knowledge_base_id UUID NOT NULL,

    -- Chunk info
    chunk_index     INTEGER NOT NULL,
    content         TEXT NOT NULL,
    token_count     INTEGER NOT NULL,

    -- Position in original document
    start_char      INTEGER,
    end_char        INTEGER,

    metadata        JSONB DEFAULT '{}',

    created_at      TIMESTAMPTZ DEFAULT NOW(),

    UNIQUE(document_id, chunk_index)
);

-- Indexes
CREATE INDEX idx_chunks_document ON document_chunks(document_id);
CREATE INDEX idx_chunks_assistant ON document_chunks(assistant_id);
CREATE INDEX idx_chunks_kb ON document_chunks(knowledge_base_id);

-- Full-text search
CREATE INDEX idx_chunks_content_search ON document_chunks
    USING gin(to_tsvector('simple', content));

15. DOCUMENT_EMBEDDINGS (PARTITIONED by assistant)#

CREATE TABLE document_embeddings (
    id              UUID NOT NULL DEFAULT gen_random_uuid(),
    tenant_id       UUID NOT NULL,
    assistant_id    UUID NOT NULL,
    chunk_id        UUID NOT NULL,
    document_id     UUID NOT NULL,
    knowledge_base_id UUID NOT NULL,

    -- Embedding vector
    embedding       vector(1536),

    model_used      VARCHAR(100) NOT NULL,

    created_at      TIMESTAMPTZ DEFAULT NOW(),

    PRIMARY KEY (id, assistant_id)
) PARTITION BY HASH (assistant_id);

-- Create 32 partitions (same as message_embeddings)
CREATE TABLE document_embeddings_p00 PARTITION OF document_embeddings FOR VALUES WITH (MODULUS 32, REMAINDER 0);
-- ... continue for p01 to p31

-- HNSW index
CREATE INDEX idx_doc_embeddings_vector ON document_embeddings
    USING hnsw (embedding vector_cosine_ops)
    WITH (m = 32, ef_construction = 200);

-- Filter indexes
CREATE INDEX idx_doc_embeddings_assistant ON document_embeddings(assistant_id);
CREATE INDEX idx_doc_embeddings_kb ON document_embeddings(knowledge_base_id);

16. AI_SUGGESTIONS#

CREATE TABLE ai_suggestions (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id       UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
    assistant_id    UUID NOT NULL REFERENCES ai_assistants(id) ON DELETE CASCADE,
    conversation_id UUID NOT NULL REFERENCES conversations(id) ON DELETE CASCADE,

    -- Trigger message
    trigger_message_id UUID NOT NULL,
    trigger_message_time TIMESTAMPTZ NOT NULL,

    -- Suggestions (3 options)
    suggestions     JSONB NOT NULL,

    -- Usage tracking
    selected_index  INTEGER,
    was_edited      BOOLEAN DEFAULT FALSE,
    final_response  TEXT,

    -- Metadata
    model_used      VARCHAR(100),
    context_tokens  INTEGER,
    generation_ms   INTEGER,

    created_at      TIMESTAMPTZ DEFAULT NOW()
);

-- Indexes
CREATE INDEX idx_suggestions_assistant ON ai_suggestions(assistant_id);
CREATE INDEX idx_suggestions_conversation ON ai_suggestions(conversation_id);

17. AI_FEEDBACK (Tín hiệu học)#

CREATE TABLE ai_feedback (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id       UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
    assistant_id    UUID NOT NULL REFERENCES ai_assistants(id) ON DELETE CASCADE,

    -- What was suggested
    suggestion_id   UUID REFERENCES ai_suggestions(id),
    suggestion_text TEXT,

    -- User action
    action          VARCHAR(20) NOT NULL,  -- accepted, rejected, edited, ignored
    edited_text     TEXT,

    -- Context
    conversation_id UUID,
    message_id      UUID,
    user_id         UUID REFERENCES users(id),

    -- Outcome (cross-module signal) - THE KEY TO TRUE LEARNING
    outcome_type    VARCHAR(50),
    outcome_id      UUID,
    outcome_value   DECIMAL(15,2),
    outcome_at      TIMESTAMPTZ,

    created_at      TIMESTAMPTZ DEFAULT NOW()
);

-- Indexes
CREATE INDEX idx_feedback_assistant ON ai_feedback(assistant_id);
CREATE INDEX idx_feedback_action ON ai_feedback(assistant_id, action);
CREATE INDEX idx_feedback_outcome ON ai_feedback(assistant_id, outcome_type) WHERE outcome_type IS NOT NULL;
CREATE INDEX idx_feedback_created ON ai_feedback(assistant_id, created_at DESC);

18. AI_LEARNING_PATTERNS#

CREATE TABLE ai_learning_patterns (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    assistant_id    UUID NOT NULL REFERENCES ai_assistants(id) ON DELETE CASCADE,

    -- Pattern identification
    pattern_type    VARCHAR(50) NOT NULL,
    pattern_key     VARCHAR(255),

    -- The learned pattern
    pattern_data    JSONB NOT NULL,

    -- Confidence & Statistics
    confidence      DECIMAL(3,2) NOT NULL,
    sample_count    INTEGER DEFAULT 1,
    success_rate    DECIMAL(3,2),

    -- Revenue impact
    total_revenue   DECIMAL(15,2) DEFAULT 0,
    avg_order_value DECIMAL(15,2),

    created_at      TIMESTAMPTZ DEFAULT NOW(),
    updated_at      TIMESTAMPTZ DEFAULT NOW(),

    UNIQUE(assistant_id, pattern_type, pattern_key)
);

-- Indexes
CREATE INDEX idx_learning_assistant ON ai_learning_patterns(assistant_id);
CREATE INDEX idx_learning_type ON ai_learning_patterns(assistant_id, pattern_type);
CREATE INDEX idx_learning_confidence ON ai_learning_patterns(assistant_id, confidence DESC);

19. AI_CONTEXTS#

CREATE TABLE ai_contexts (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id       UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
    assistant_id    UUID NOT NULL REFERENCES ai_assistants(id) ON DELETE CASCADE,
    conversation_id UUID NOT NULL REFERENCES conversations(id) ON DELETE CASCADE,

    -- Assembled context
    context         TEXT NOT NULL,
    token_count     INTEGER NOT NULL,

    -- Components used
    summaries_used  UUID[],
    message_ids     UUID[],
    kb_chunks_used  UUID[],

    -- Contact context
    contact_context JSONB,

    -- Validity
    valid_until_message_id UUID,
    is_current      BOOLEAN DEFAULT TRUE,

    created_at      TIMESTAMPTZ DEFAULT NOW()
);

-- Indexes
CREATE INDEX idx_contexts_assistant ON ai_contexts(assistant_id);
CREATE INDEX idx_contexts_conversation ON ai_contexts(conversation_id) WHERE is_current = TRUE;

20. CONVERSATION_SUMMARIES#

CREATE TABLE conversation_summaries (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id       UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
    assistant_id    UUID NOT NULL,
    conversation_id UUID NOT NULL REFERENCES conversations(id) ON DELETE CASCADE,

    -- Chunk info
    chunk_index     INTEGER NOT NULL,
    message_start_id UUID NOT NULL,
    message_start_time TIMESTAMPTZ NOT NULL,
    message_end_id  UUID NOT NULL,
    message_end_time TIMESTAMPTZ NOT NULL,
    message_count   INTEGER NOT NULL,

    -- Summary content
    summary         TEXT NOT NULL,
    key_points      JSONB,
    action_items    JSONB,
    entities        JSONB,

    -- Metadata
    model_used      VARCHAR(100) NOT NULL,
    input_tokens    INTEGER,
    output_tokens   INTEGER,

    created_at      TIMESTAMPTZ DEFAULT NOW(),

    UNIQUE(conversation_id, chunk_index)
);

-- Indexes
CREATE INDEX idx_summaries_assistant ON conversation_summaries(assistant_id);
CREATE INDEX idx_summaries_conversation ON conversation_summaries(conversation_id, chunk_index);

21. SENTIMENT_SCORES#

CREATE TABLE sentiment_scores (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id       UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
    assistant_id    UUID NOT NULL,

    -- Reference
    entity_type     VARCHAR(20) NOT NULL,
    entity_id       UUID NOT NULL,
    entity_time     TIMESTAMPTZ,

    -- Scores
    sentiment       DECIMAL(3,2) NOT NULL,
    confidence      DECIMAL(3,2) NOT NULL,

    -- Detailed emotions
    emotions        JSONB,

    model_used      VARCHAR(100),

    created_at      TIMESTAMPTZ DEFAULT NOW(),

    UNIQUE(entity_type, entity_id)
);

-- Indexes
CREATE INDEX idx_sentiment_assistant ON sentiment_scores(assistant_id);
CREATE INDEX idx_sentiment_entity ON sentiment_scores(entity_type, entity_id);
CREATE INDEX idx_sentiment_score ON sentiment_scores(assistant_id, sentiment);

22-24. SUPPORT TABLES#

-- 22. TAGS
CREATE TABLE tags (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id       UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,

    name            VARCHAR(100) NOT NULL,
    color           VARCHAR(7) DEFAULT '#6c757d',
    description     TEXT,
    usage_count     INTEGER DEFAULT 0,

    created_at      TIMESTAMPTZ DEFAULT NOW(),

    UNIQUE(tenant_id, name)
);

-- 23. CONVERSATION_TAGS
CREATE TABLE conversation_tags (
    conversation_id UUID NOT NULL REFERENCES conversations(id) ON DELETE CASCADE,
    tag_id          UUID NOT NULL REFERENCES tags(id) ON DELETE CASCADE,

    created_by      UUID REFERENCES users(id),
    created_at      TIMESTAMPTZ DEFAULT NOW(),

    PRIMARY KEY(conversation_id, tag_id)
);

-- 24. TEMPLATES
CREATE TABLE templates (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id       UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
    assistant_id    UUID REFERENCES ai_assistants(id) ON DELETE CASCADE,

    name            VARCHAR(255) NOT NULL,
    content         TEXT NOT NULL,
    category        VARCHAR(100),
    keywords        TEXT[],
    intent_tags     TEXT[],
    variables       JSONB,
    use_count       INTEGER DEFAULT 0,
    last_used       TIMESTAMPTZ,
    created_by      UUID REFERENCES users(id),
    is_shared       BOOLEAN DEFAULT TRUE,

    created_at      TIMESTAMPTZ DEFAULT NOW(),
    updated_at      TIMESTAMPTZ DEFAULT NOW()
);

25-27. GLOBAL LEARNING TABLES (3-Layer Learning System)#

-- ============================================================================
-- 25. INDUSTRIES (Ngành nghề)
-- ============================================================================

CREATE TABLE industries (
    id              VARCHAR(50) PRIMARY KEY,  -- 'fashion', 'f&b', 'beauty'

    -- Info
    name            VARCHAR(100) NOT NULL,
    description     TEXT,
    icon            VARCHAR(50),

    -- Default settings for this industry
    default_config  JSONB DEFAULT '{
        "tone": "friendly",
        "response_style": "conversational",
        "emoji_usage": "moderate"
    }',

    -- Status
    sort_order      INTEGER DEFAULT 0,
    is_active       BOOLEAN DEFAULT TRUE,

    created_at      TIMESTAMPTZ DEFAULT NOW()
);

-- Seed industries
INSERT INTO industries (id, name, description, sort_order) VALUES
('fashion', 'Thời trang', 'Quần áo, giày dép, phụ kiện', 1),
('f&b', 'F&B', 'Nhà hàng, cafe, đồ ăn', 2),
('beauty', 'Làm đẹp', 'Spa, mỹ phẩm, skincare', 3),
('tech', 'Công nghệ', 'Điện tử, phần mềm, gadgets', 4),
('services', 'Dịch vụ', 'Tư vấn, dịch vụ chuyên nghiệp', 5),
('education', 'Giáo dục', 'Đào tạo, khóa học', 6),
('health', 'Sức khỏe', 'Y tế, dược phẩm, fitness', 7),
('real_estate', 'Bất động sản', 'Nhà đất, cho thuê', 8),
('travel', 'Du lịch', 'Tour, khách sạn, vé máy bay', 9),
('general', 'Khác', 'Ngành nghề khác', 99);


-- ============================================================================
-- 26. GLOBAL_PATTERNS (Platform-wide patterns, anonymized)
-- ============================================================================

CREATE TABLE global_patterns (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),

    -- Pattern identification
    pattern_type    VARCHAR(50) NOT NULL,   -- 'greeting', 'objection', 'closing', 'upsale'
    pattern_key     VARCHAR(255) NOT NULL,  -- 'size_inquiry_with_height'

    -- The learned pattern (ANONYMIZED - no tenant-specific data)
    pattern_data    JSONB NOT NULL,
    /*
    Example pattern_data:
    {
        "strategy": "ask_height_before_size_recommendation",
        "template": "Dạ có size [X] ạ! Chị cao bao nhiêu để em tư vấn size chuẩn nhất nhé? 😊",
        "trigger_intents": ["size_inquiry", "product_availability"],
        "response_style": "consultative",
        "include_emoji": true
    }
    */

    -- Aggregated statistics from ALL assistants (anonymized)
    confidence      DECIMAL(3,2) NOT NULL,   -- 0.00 - 1.00
    sample_count    INTEGER NOT NULL,        -- Total samples across all shops
    success_rate    DECIMAL(3,2),            -- Conversion rate

    -- Which industries this applies to (NULL = all industries)
    industries      TEXT[] DEFAULT NULL,     -- ['fashion', 'f&b'] or NULL for all

    -- Revenue impact (aggregated, anonymized)
    avg_revenue_impact DECIMAL(10,2),        -- Average order value when this pattern used

    -- Quality control
    is_verified     BOOLEAN DEFAULT FALSE,   -- Manual review passed
    is_active       BOOLEAN DEFAULT TRUE,

    -- Tracking
    contributor_count INTEGER DEFAULT 1,     -- How many assistants contributed
    last_aggregated_at TIMESTAMPTZ DEFAULT NOW(),

    created_at      TIMESTAMPTZ DEFAULT NOW(),
    updated_at      TIMESTAMPTZ DEFAULT NOW(),

    UNIQUE(pattern_type, pattern_key)
);

-- Indexes
CREATE INDEX idx_global_patterns_type ON global_patterns(pattern_type);
CREATE INDEX idx_global_patterns_industry ON global_patterns USING gin(industries);
CREATE INDEX idx_global_patterns_active ON global_patterns(confidence DESC)
    WHERE is_active = TRUE AND is_verified = TRUE;
CREATE INDEX idx_global_patterns_contribution ON global_patterns(contributor_count DESC);


-- ============================================================================
-- 27. INDUSTRY_TEMPLATES (Pre-defined templates per vertical)
-- ============================================================================

CREATE TABLE industry_templates (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    industry_id     VARCHAR(50) NOT NULL REFERENCES industries(id),

    -- Template identification
    template_type   VARCHAR(50) NOT NULL,   -- 'greeting', 'objection', 'closing', 'faq'
    template_key    VARCHAR(255) NOT NULL,  -- 'size_inquiry', 'return_policy'

    -- Template content
    template_data   JSONB NOT NULL,
    /*
    Example template_data:
    {
        "trigger_keywords": ["size", "cỡ", "số"],
        "strategy": "Ask for height/weight before recommending size",
        "template": "Dạ có size [X] ạ! Để em tư vấn size chuẩn, chị cho em biết chiều cao và cân nặng nhé 😊",
        "variables": ["size", "product_name"],
        "follow_up": "Provide size chart if customer shares measurements"
    }
    */

    -- Usage stats (aggregated from usage)
    usage_count     INTEGER DEFAULT 0,
    success_rate    DECIMAL(3,2),

    -- Status
    is_active       BOOLEAN DEFAULT TRUE,

    created_at      TIMESTAMPTZ DEFAULT NOW(),

    UNIQUE(industry_id, template_type, template_key)
);

-- Indexes
CREATE INDEX idx_industry_templates_industry ON industry_templates(industry_id);
CREATE INDEX idx_industry_templates_type ON industry_templates(industry_id, template_type);
CREATE INDEX idx_industry_templates_active ON industry_templates(industry_id) WHERE is_active = TRUE;

-- Seed example templates for Fashion industry
INSERT INTO industry_templates (industry_id, template_type, template_key, template_data) VALUES
('fashion', 'faq', 'size_inquiry', '{
    "trigger_keywords": ["size", "cỡ", "số", "vừa"],
    "strategy": "ask_measurements_before_recommend",
    "template": "Dạ có size [X] ạ! Chị cao bao nhiêu, nặng bao nhiêu để em tư vấn size chuẩn nhất nhé? 😊",
    "success_rate": 0.85
}'::jsonb),
('fashion', 'faq', 'return_policy', '{
    "trigger_keywords": ["đổi", "trả", "hoàn"],
    "strategy": "proactive_assurance",
    "template": "Dạ shop em có chính sách đổi trả trong 7 ngày nếu sản phẩm còn nguyên tem mác ạ. Chị yên tâm mua sắm nhé! 😊",
    "success_rate": 0.90
}'::jsonb),
('fashion', 'upsale', 'bundle_offer', '{
    "trigger_keywords": ["mua", "đặt", "order"],
    "strategy": "complementary_product",
    "template": "Em thấy [PRODUCT] này kết hợp với [RELATED] rất đẹp luôn ạ! Chị lấy combo em giảm thêm 10% nhé? 😊",
    "success_rate": 0.45
}'::jsonb);

ALTER: ai_assistants (Thêm industry_id)#

-- Add industry reference to ai_assistants
ALTER TABLE ai_assistants
ADD COLUMN industry_id VARCHAR(50) REFERENCES industries(id) DEFAULT 'general';

-- Index for industry lookup
CREATE INDEX idx_assistants_industry ON ai_assistants(industry_id);

ALTER: ai_learning_patterns (Thêm source tracking)#

-- Add source tracking to distinguish pattern origins
ALTER TABLE ai_learning_patterns
ADD COLUMN source VARCHAR(20) DEFAULT 'assistant',  -- 'assistant', 'global', 'industry'
ADD COLUMN global_pattern_id UUID REFERENCES global_patterns(id),
ADD COLUMN is_override BOOLEAN DEFAULT FALSE;  -- TRUE if this overrides a global/industry pattern

-- Index for source filtering
CREATE INDEX idx_learning_source ON ai_learning_patterns(assistant_id, source);

Data Flow Diagrams#

User Registration Flow (Updated with Industry Selection)#

┌─────────────────────────────────────────────────────────────────────────────┐
│                         USER REGISTRATION FLOW                               │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  1. User đăng ký                                                            │
│     ════════════                                                            │
│     ┌─────────────────┐                                                     │
│     │  Registration   │                                                     │
│     │  Form           │                                                     │
│     └────────┬────────┘                                                     │
│              │                                                               │
│              ▼                                                               │
│     ┌─────────────────┐                                                     │
│     │  CREATE tenant  │ ← name, email, plan='free'                         │
│     └────────┬────────┘                                                     │
│              │                                                               │
│              ▼                                                               │
│     ┌─────────────────┐                                                     │
│     │  CREATE user    │ ← role='owner'                                     │
│     └────────┬────────┘                                                     │
│              │                                                               │
│              ▼                                                               │
│  2. Tự động tạo AI Assistant mặc định                                       │
│     ════════════════════════════════                                        │
│     ┌─────────────────────────────┐                                         │
│     │  CREATE ai_assistant        │                                         │
│     │  - name: "Trợ lý mặc định"  │                                         │
│     │  - is_default: true         │                                         │
│     │  - config: {defaults}       │                                         │
│     └────────────┬────────────────┘                                         │
│                  │                                                           │
│                  ▼                                                           │
│     ┌─────────────────────────────┐                                         │
│     │  CREATE assistant_module    │                                         │
│     │  - module_id: 'chat'        │ ← Module CHAT miễn phí                  │
│     └────────────┬────────────────┘                                         │
│                  │                                                           │
│                  ▼                                                           │
│  3. User được redirect đến Dashboard                                        │
│     ═══════════════════════════════                                         │
│     ┌─────────────────────────────────────────────────────────────────┐    │
│     │                      DASHBOARD                                   │    │
│     │  ┌─────────────────────────────────────────────────────────┐   │    │
│     │  │  AI Assistant: "Trợ lý mặc định"                        │   │    │
│     │  │  Modules: [CHAT ✓]                                      │   │    │
│     │  │  Platforms: [Chưa kết nối]                              │   │    │
│     │  │                                                          │   │    │
│     │  │  [+ Kết nối Facebook] [+ Kết nối Zalo] [+ Module khác]  │   │    │
│     │  └─────────────────────────────────────────────────────────┘   │    │
│     └─────────────────────────────────────────────────────────────────┘    │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

Platform Connection Flow#

┌─────────────────────────────────────────────────────────────────────────────┐
│                      PLATFORM CONNECTION FLOW                                │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  User muốn kết nối Facebook Page với Assistant A                            │
│                                                                              │
│  Step 1: OAuth Flow                                                          │
│  ══════════════════                                                          │
│  ┌─────────────┐    ┌─────────────┐    ┌─────────────┐                     │
│  │   ScapBot   │───►│  Facebook   │───►│  User Auth  │                     │
│  │   Dashboard │    │  OAuth      │    │  & Consent  │                     │
│  └─────────────┘    └─────────────┘    └──────┬──────┘                     │
│                                                │                             │
│                                                ▼                             │
│  Step 2: Get Page Access Token                                              │
│  ═════════════════════════════                                              │
│  ┌──────────────────────────────────────────────────────────────────────┐  │
│  │  Callback với: page_id, page_access_token, page_name                  │  │
│  └───────────────────────────────────┬──────────────────────────────────┘  │
│                                       │                                      │
│                                       ▼                                      │
│  Step 3: Check Platform Exists                                              │
│  ═════════════════════════════                                              │
│  ┌──────────────────────────────────────────────────────────────────────┐  │
│  │  SELECT * FROM platforms                                              │  │
│  │  WHERE tenant_id = $tenant AND type = 'facebook' AND external_id = $p │  │
│  └───────────────────────────────────┬──────────────────────────────────┘  │
│                                       │                                      │
│              ┌────────────────────────┼────────────────────────┐            │
│              ▼                        ▼                        ▼            │
│  ┌───────────────────┐   ┌───────────────────┐   ┌───────────────────┐    │
│  │  NOT EXISTS       │   │  EXISTS           │   │  EXISTS           │    │
│  │                   │   │  assistant = A    │   │  assistant = B    │    │
│  │  → CREATE new     │   │                   │   │  (khác assistant) │    │
│  │    platform       │   │  → Already        │   │                   │    │
│  │    for Assistant A│   │    connected ✓    │   │  → Show warning   │    │
│  └───────────────────┘   └───────────────────┘   │    "Page đang     │    │
│                                                   │    được B quản lý"│    │
│                                                   │                   │    │
│                                                   │  → User chọn:     │    │
│                                                   │    [Chuyển sang A]│    │
│                                                   │    [Giữ nguyên B] │    │
│                                                   └───────────────────┘    │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

Message Processing Flow#

┌─────────────────────────────────────────────────────────────────────────────┐
│                       MESSAGE PROCESSING FLOW                                │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  INCOMING MESSAGE (from Facebook)                                            │
│         │                                                                    │
│         ▼                                                                    │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │ 1. WEBHOOK HANDLER                                                   │   │
│  │    - Validate signature                                              │   │
│  │    - Parse payload                                                   │   │
│  │    - Lookup platform by external_id                                  │   │
│  │    - Get assistant_id from platform                                  │   │
│  │    - Push to Valkey Queue                                            │   │
│  │    - Return 200 OK (< 50ms)                                          │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│         │                                                                    │
│         │ (Async via Valkey)                                                │
│         ▼                                                                    │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │ 2. MESSAGE WORKER                                                    │   │
│  │    - Get/Create contact                                              │   │
│  │    - Get/Create conversation                                         │   │
│  │    - INSERT message                                                  │   │
│  │    - Update conversation stats                                       │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│         │                                                                    │
│         │ (Parallel async tasks)                                            │
│    ┌────┴────┬────────────┬────────────┬────────────┐                      │
│    ▼         ▼            ▼            ▼            ▼                      │
│ ┌───────┐ ┌───────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐                │
│ │Embed  │ │Senti- │ │Summarize │ │Update    │ │Notify    │                │
│ │ding   │ │ment   │ │Check     │ │Contact   │ │Dashboard │                │
│ └───────┘ └───────┘ └──────────┘ └──────────┘ └──────────┘                │
│         │                                                                    │
│         ▼                                                                    │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │ 3. AI MODE CHECK                                                     │   │
│  │                                                                      │   │
│  │    platform.ai_mode_enabled == TRUE ?                               │   │
│  │                                                                      │   │
│  │    YES → Build AI Context → Generate suggestions → Auto-reply       │   │
│  │    NO  → Show suggestions to human agent                            │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

AI Learning Flow#

┌─────────────────────────────────────────────────────────────────────────────┐
│                           AI LEARNING FLOW                                   │
│                    (How Assistant Gets Smarter)                              │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  NGUYÊN TẮC: RAG + Feedback Loop (KHÔNG fine-tune)                          │
│                                                                              │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │                    DATA SOURCES FOR LEARNING                         │   │
│  ├─────────────────────────────────────────────────────────────────────┤   │
│  │                                                                      │   │
│  │  1. KNOWLEDGE BASE (Explicit)                                        │   │
│  │     User upload documents → Chunk → Embed → document_embeddings      │   │
│  │     "AI biết thêm" = Thêm documents                                  │   │
│  │                                                                      │   │
│  │  2. CHAT HISTORY (Implicit)                                          │   │
│  │     Messages → Embed → message_embeddings                            │   │
│  │     Messages → Summarize → conversation_summaries                    │   │
│  │     "AI nhớ context" = Retrieve similar conversations                │   │
│  │                                                                      │   │
│  │  3. USER FEEDBACK (Reinforcement)                                    │   │
│  │     AI suggests → User accepts/rejects/edits → ai_feedback           │   │
│  │     "AI biết cách nào hay" = Track success rate                      │   │
│  │                                                                      │   │
│  │  4. OUTCOME SIGNALS (Business Impact) ← THE KEY!                     │   │
│  │     Suggestion → Accepted → Order Created → Order Completed          │   │
│  │     ai_feedback.outcome_type = 'order_completed'                     │   │
│  │     ai_feedback.outcome_value = 500000 (VND)                         │   │
│  │     "AI biết cách nào HIỆU QUẢ" = Maximize revenue                   │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                                                              │
│  LEARNING PIPELINE                                                           │
│  ┌─────────────┐    ┌─────────────┐    ┌─────────────┐    ┌─────────────┐ │
│  │  Collect    │───►│  Aggregate  │───►│  Extract    │───►│  Store      │ │
│  │  Feedback   │    │  by Pattern │    │  Patterns   │    │  Patterns   │ │
│  └─────────────┘    └─────────────┘    └─────────────┘    └─────────────┘ │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

RAG Query Flow#

┌─────────────────────────────────────────────────────────────────────────────┐
│                           RAG QUERY FLOW                                     │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  Customer: "Chính sách đổi trả của shop như thế nào?"                       │
│                                                                              │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │ 1. EMBED QUERY                                                       │   │
│  │    Input: "chính sách đổi trả"                                       │   │
│  │    Output: query_vector = vector(1536)                               │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│         │                                                                    │
│         ▼                                                                    │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │ 2. SEARCH KNOWLEDGE BASE (assistant-isolated)                        │   │
│  │                                                                      │   │
│  │    SELECT dc.content, d.title,                                       │   │
│  │           1 - (de.embedding <=> $query_vector) AS similarity         │   │
│  │    FROM document_embeddings de                                       │   │
│  │    JOIN document_chunks dc ON dc.id = de.chunk_id                    │   │
│  │    WHERE de.assistant_id = $assistant_id    ← ISOLATION              │   │
│  │    ORDER BY de.embedding <=> $query_vector                           │   │
│  │    LIMIT 5;                                                          │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│         │                                                                    │
│         ▼                                                                    │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │ 3. GET LEARNING PATTERNS                                             │   │
│  │                                                                      │   │
│  │    SELECT pattern_data FROM ai_learning_patterns                     │   │
│  │    WHERE assistant_id = $assistant_id                                │   │
│  │      AND confidence > 0.7                                            │   │
│  │    ORDER BY confidence DESC LIMIT 5;                                 │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│         │                                                                    │
│         ▼                                                                    │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │ 4. ASSEMBLE CONTEXT & GENERATE                                       │   │
│  │                                                                      │   │
│  │    context = {                                                       │   │
│  │        system_prompt,                                                │   │
│  │        knowledge_chunks,                                             │   │
│  │        learning_patterns,                                            │   │
│  │        conversation_history,                                         │   │
│  │        contact_profile                                               │   │
│  │    }                                                                 │   │
│  │    → Send to LLM → Generate 3 response options                       │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

AI Learning Mechanism (Chi tiết)#

Nguyên tắc cốt lõi: RAG + Feedback Loop#

┌─────────────────────────────────────────────────────────────────────────────┐
│                    AI LEARNING PRINCIPLE                                     │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  ❌ KHÔNG fine-tune model                                                   │
│     - Tốn kém ($$$)                                                         │
│     - Chậm (hours/days)                                                     │
│     - Khó rollback                                                          │
│     - Cần nhiều data                                                        │
│                                                                              │
│  ✅ RAG + Feedback Loop                                                     │
│     - Chi phí thấp (chỉ storage + embedding)                               │
│     - Real-time (seconds)                                                   │
│     - Dễ cập nhật/xóa                                                       │
│     - Học từ ít data                                                        │
│                                                                              │
│  ═══════════════════════════════════════════════════════════════════════   │
│                                                                              │
│  HOW IT WORKS:                                                               │
│  ─────────────                                                               │
│  1. Knowledge được EMBED và lưu vào vector database                        │
│  2. Khi query, RETRIEVE relevant knowledge                                  │
│  3. AUGMENT prompt với retrieved knowledge + learned patterns              │
│  4. LLM GENERATE response dựa trên augmented context                       │
│  5. User feedback → Cập nhật patterns → Lần sau response tốt hơn           │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

4 Nguồn học của AI (Chi tiết)#

┌─────────────────────────────────────────────────────────────────────────────┐
│                         4 LEARNING SOURCES                                   │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  ┌────────────────────────────────────────────────────────────────────────┐ │
│  │ NGUỒN 1: KNOWLEDGE BASE (Học tường minh)                               │ │
│  │ ═══════════════════════════════════════════                            │ │
│  │                                                                         │ │
│  │ Hành động người dùng:                                                   │ │
│  │   Upload: FAQ.pdf, Product_Catalog.xlsx, Policies.docx                 │ │
│  │                                                                         │ │
│  │ Xử lý hệ thống:                                                         │ │
│  │   ┌──────────┐    ┌──────────┐    ┌──────────┐    ┌──────────┐        │ │
│  │   │ Document │───►│  Parse   │───►│  Chunk   │───►│  Embed   │        │ │
│  │   │ Upload   │    │ Content  │    │ (500 tok)│    │ (1536d)  │        │ │
│  │   └──────────┘    └──────────┘    └──────────┘    └──────────┘        │ │
│  │                                                         │               │ │
│  │                                                         ▼               │ │
│  │                                              ┌──────────────────┐      │ │
│  │                                              │document_embeddings│      │ │
│  │                                              └──────────────────┘      │ │
│  │                                                                         │ │
│  │ Bảng sử dụng:                                                           │ │
│  │   • knowledge_bases    → Bộ chứa tài liệu                              │ │
│  │   • documents          → Metadata file                                 │ │
│  │   • document_chunks    → Đoạn văn bản                                  │ │
│  │   • document_embeddings → Vector embeddings                            │ │
│  │                                                                         │ │
│  │ Khi nào AI "biết thêm"? → Ngay khi user upload document                │ │
│  │ Làm sao "quên"?         → Xóa document → Cascade delete embeddings     │ │
│  └────────────────────────────────────────────────────────────────────────┘ │
│                                                                              │
│  ┌────────────────────────────────────────────────────────────────────────┐ │
│  │ NGUỒN 2: CHAT HISTORY (Học ẩn)                                         │ │
│  │ ═════════════════════════════════════════                              │ │
│  │                                                                         │ │
│  │ Xử lý tự động (mỗi tin nhắn):                                      │ │
│  │   ┌──────────┐    ┌──────────┐    ┌──────────────────┐                │ │
│  │   │ Message  │───►│  Embed   │───►│ message_embeddings│                │ │
│  │   │ Received │    │ (async)  │    │ (partitioned)    │                │ │
│  │   └──────────┘    └──────────┘    └──────────────────┘                │ │
│  │                                                                         │ │
│  │ Xử lý tự động (mỗi 50 tin nhắn):                                  │ │
│  │   ┌──────────┐    ┌──────────┐    ┌────────────────────────┐          │ │
│  │   │ 50 msgs  │───►│Summarize │───►│ conversation_summaries │          │ │
│  │   │ chunk    │    │ (LLM)    │    │                        │          │ │
│  │   └──────────┘    └──────────┘    └────────────────────────┘          │ │
│  │                                                                         │ │
│  │ Bảng sử dụng:                                                           │ │
│  │   • messages              → Tin nhắn gốc                               │ │
│  │   • message_embeddings    → Vector embeddings (phân vùng theo assistant)│ │
│  │   • conversation_summaries → Tóm tắt theo chunk                        │ │
│  │                                                                         │ │
│  │ Khi nào AI "nhớ"?  → Retrieve similar past conversations               │ │
│  │ Làm sao "quên"?    → Data retention policy / GDPR delete               │ │
│  └────────────────────────────────────────────────────────────────────────┘ │
│                                                                              │
│  ┌────────────────────────────────────────────────────────────────────────┐ │
│  │ NGUỒN 3: USER FEEDBACK (Học tăng cường)                                │ │
│  │ ═══════════════════════════════════════════════                        │ │
│  │                                                                         │ │
│  │ Luồng:                                                                  │ │
│  │   AI gợi ý 3 lựa chọn                                                   │ │
│  │         │                                                               │ │
│  │         ▼                                                               │ │
│  │   Human agent: [Accept] [Reject] [Edit]                                │ │
│  │         │                                                               │ │
│  │         ▼                                                               │ │
│  │   ┌──────────────────────────────────────────────────────────────┐    │ │
│  │   │ INSERT INTO ai_feedback:                                     │    │ │
│  │   │   action: 'accepted' | 'rejected' | 'edited' | 'ignored'    │    │ │
│  │   │   suggestion_text: "..."                                     │    │ │
│  │   │   edited_text: "..." (if edited)                            │    │ │
│  │   └──────────────────────────────────────────────────────────────┘    │ │
│  │                                                                         │ │
│  │ Bảng sử dụng:                                                           │ │
│  │   • ai_suggestions → Gợi ý được tạo                                    │ │
│  │   • ai_feedback    → Hành động của người dùng với gợi ý                │ │
│  │                                                                         │ │
│  │ Độ mạnh tín hiệu:                                                       │ │
│  │   • accepted  = Tích cực (+1.0)                                        │ │
│  │   • edited    = Một phần (+0.5), nhưng học từ phiên bản đã chỉnh sửa   │ │
│  │   • rejected  = Tiêu cực (-1.0)                                        │ │
│  │   • ignored   = Tiêu cực yếu (-0.1)                                    │ │
│  └────────────────────────────────────────────────────────────────────────┘ │
│                                                                              │
│  ┌────────────────────────────────────────────────────────────────────────┐ │
│  │ NGUỒN 4: OUTCOME SIGNALS (Học từ tác động kinh doanh) ⭐ QUAN TRỌNG!   │ │
│  │ ═══════════════════════════════════════════════════════════════        │ │
│  │                                                                         │ │
│  │ Đây là ĐIỂM KHÁC BIỆT so với các hệ thống khác!                        │ │
│  │                                                                         │ │
│  │ Vấn đề khi chỉ dùng phản hồi người dùng:                                │ │
│  │   • Người dùng chấp nhận ≠ Thành công kinh doanh                       │ │
│  │   • User có thể accept response mà không dẫn đến đơn hàng             │ │
│  │   • Không biết response nào THỰC SỰ mang lại doanh thu                 │ │
│  │                                                                         │ │
│  │ Giải pháp - Theo dõi kết quả:                                               │ │
│  │   ┌──────────────────────────────────────────────────────────────┐    │ │
│  │   │ CONVERSATION TIMELINE                                        │    │ │
│  │   ├──────────────────────────────────────────────────────────────┤    │ │
│  │   │                                                              │    │ │
│  │   │  10:00 Customer: "Áo này có size L không?"                  │    │ │
│  │   │  10:01 AI suggest → Human accept → Send response            │    │ │
│  │   │        └──► ai_feedback created (action: accepted)          │    │ │
│  │   │                                                              │    │ │
│  │   │  10:05 Customer: "OK, cho mình đặt 2 cái"                   │    │ │
│  │   │  10:06 Order created: 700,000 VND                           │    │ │
│  │   │        └──► UPDATE ai_feedback SET                          │    │ │
│  │   │              outcome_type = 'order_created'                 │    │ │
│  │   │              outcome_value = 700000                         │    │ │
│  │   │                                                              │    │ │
│  │   │  Day+2 Order delivered successfully                         │    │ │
│  │   │        └──► UPDATE ai_feedback SET                          │    │ │
│  │   │              outcome_type = 'order_completed'               │    │ │
│  │   │                                                              │    │ │
│  │   └──────────────────────────────────────────────────────────────┘    │ │
│  │                                                                         │ │
│  │ Bảng sử dụng:                                                           │ │
│  │   • ai_feedback.outcome_type  → 'order_created', 'order_completed',    │ │
│  │                                 'lead_converted', 'issue_resolved'     │ │
│  │   • ai_feedback.outcome_value → Doanh thu (VND)                        │ │
│  │   • ai_feedback.outcome_id    → Liên kết đến đơn hàng/lead/ticket      │ │
│  │   • ai_feedback.outcome_at    → Thời điểm kết quả xảy ra               │ │
│  │                                                                         │ │
│  │ Giờ AI biết: "Response này không chỉ được accept,                      │ │
│  │               mà còn dẫn đến đơn hàng 700K!"                           │ │
│  └────────────────────────────────────────────────────────────────────────┘ │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

Quy trình học (Công việc nền)#

┌─────────────────────────────────────────────────────────────────────────────┐
│                    QUY TRÌNH HỌC (Chạy hàng ngày/tuần)                       │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  GIAI ĐOẠN 1: Thu thập phản hồi gốc                                             │
│  ═══════════════════════════════                                             │
│                                                                              │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │ SELECT * FROM ai_feedback                                           │   │
│  │ WHERE assistant_id = $assistant_id                                  │   │
│  │   AND created_at > $last_processed_at                               │   │
│  │   AND outcome_type IS NOT NULL;  -- Chỉ lấy có outcome             │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                                                              │
│  Kết quả: 1000 bản ghi phản hồi với kết quả                                  │
│                                                                              │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  GIAI ĐOẠN 2: Tổng hợp theo mẫu                                              │
│  ═════════════════════════════                                               │
│                                                                              │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │ GROUP BY: intent + response_style + outcome                         │   │
│  │                                                                     │   │
│  │ Ví dụ tổng hợp:                                                │   │
│  │ ┌───────────────────────────────────────────────────────────────┐  │   │
│  │ │ Pattern: "size_inquiry_with_height_question"                  │  │   │
│  │ │ ─────────────────────────────────────────────                 │  │   │
│  │ │ Intent:         "hỏi về size"                                 │  │   │
│  │ │ Response style: "hỏi lại chiều cao để tư vấn"                │  │   │
│  │ │                                                               │  │   │
│  │ │ Thống kê:                                                     │  │   │
│  │ │   Tổng mẫu:           150                                     │  │   │
│  │ │   Chấp nhận:          120 (80%)                               │  │   │
│  │ │   Chỉnh sửa rồi gửi:   20 (13%)                               │  │   │
│  │ │   Từ chối:             10 (7%)                                │  │   │
│  │ │                                                               │  │   │
│  │ │ Kết quả:                                                      │  │   │
│  │ │   Dẫn đến đơn hàng:    85 (57%)                               │  │   │
│  │ │   Tổng doanh thu:      42,500,000 VND                         │  │   │
│  │ │   Giá trị đơn trung bình: 500,000 VND                         │  │   │
│  │ │                                                               │  │   │
│  │ │ Độ tin cậy:            0.85 (cao)                             │  │   │
│  │ └───────────────────────────────────────────────────────────────┘  │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                                                              │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  GIAI ĐOẠN 3: Trích xuất & Lưu trữ mẫu                                          │
│  ═════════════════════════════════                                           │
│                                                                              │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │ INSERT INTO ai_learning_patterns (                                  │   │
│  │     assistant_id,                                                   │   │
│  │     pattern_type,                                                   │   │
│  │     pattern_key,                                                    │   │
│  │     pattern_data,                                                   │   │
│  │     confidence,                                                     │   │
│  │     sample_count,                                                   │   │
│  │     success_rate,                                                   │   │
│  │     total_revenue,                                                  │   │
│  │     avg_order_value                                                 │   │
│  │ ) VALUES (                                                          │   │
│  │     $assistant_id,                                                  │   │
│  │     'response_template',                                            │   │
│  │     'size_inquiry_with_height_question',                            │   │
│  │     '{                                                              │   │
│  │         "trigger_intent": "hỏi về size",                           │   │
│  │         "response_strategy": "hỏi chiều cao trước khi tư vấn",    │   │
│  │         "tone": "friendly",                                         │   │
│  │         "include_emoji": true,                                      │   │
│  │         "example_responses": [                                      │   │
│  │             "Size L còn hàng ạ! Chị cao bao nhiêu để em tư vấn...",│   │
│  │             "Dạ có size này ạ. Anh cho em biết chiều cao nhé..."  │   │
│  │         ],                                                          │   │
│  │         "avoid_patterns": [                                         │   │
│  │             "Trả lời ngay mà không hỏi thêm"                       │   │
│  │         ]                                                           │   │
│  │     }'::jsonb,                                                      │   │
│  │     0.85,                                                           │   │
│  │     150,                                                            │   │
│  │     0.57,                                                           │   │
│  │     42500000,                                                       │   │
│  │     500000                                                          │   │
│  │ )                                                                   │   │
│  │ ON CONFLICT (assistant_id, pattern_type, pattern_key)               │   │
│  │ DO UPDATE SET                                                       │   │
│  │     pattern_data = EXCLUDED.pattern_data,                           │   │
│  │     confidence = EXCLUDED.confidence,                               │   │
│  │     sample_count = ai_learning_patterns.sample_count + EXCLUDED.sample_count, │
│  │     success_rate = EXCLUDED.success_rate,                           │   │
│  │     total_revenue = ai_learning_patterns.total_revenue + EXCLUDED.total_revenue, │
│  │     updated_at = NOW();                                             │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

Sinh phản hồi AI (Sử dụng mẫu đã học)#

┌─────────────────────────────────────────────────────────────────────────────┐
│                    LUỒNG SINH PHẢN HỒI AI                                    │
│                    (Cách AI sử dụng mẫu đã học)                              │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  KHỞI ĐỘNG: Khách hàng gửi tin nhắn mới                                         │
│  ═══════════════════════════════════                                         │
│                                                                              │
│  Customer: "Váy này có size M không ạ?"                                     │
│         │                                                                    │
│         ▼                                                                    │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │ STEP 1: INTENT DETECTION                                            │   │
│  │ ─────────────────────────                                           │   │
│  │ Detect: intent = "size_inquiry"                                     │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│         │                                                                    │
│         ▼                                                                    │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │ STEP 2: RETRIEVE KNOWLEDGE (RAG)                                    │   │
│  │ ────────────────────────────────                                    │   │
│  │                                                                     │   │
│  │ Query document_embeddings WHERE assistant_id = $assistant_id        │   │
│  │                                                                     │   │
│  │ Các đoạn truy xuất được:                                                   │   │
│  │   • "Size M: phù hợp 55-60kg, chiều cao 158-165cm"                 │   │
│  │   • "Váy mã A001 có các size: S, M, L, XL"                         │   │
│  │   • "Chính sách đổi size trong 7 ngày"                             │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│         │                                                                    │
│         ▼                                                                    │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │ STEP 3: RETRIEVE LEARNING PATTERNS ⭐                               │   │
│  │ ────────────────────────────────────                                │   │
│  │                                                                     │   │
│  │ SELECT * FROM ai_learning_patterns                                  │   │
│  │ WHERE assistant_id = $assistant_id                                  │   │
│  │   AND (                                                             │   │
│  │     pattern_key LIKE '%size%'                                       │   │
│  │     OR pattern_type = 'general_style'                               │   │
│  │   )                                                                 │   │
│  │   AND confidence > 0.6                                              │   │
│  │ ORDER BY success_rate DESC, total_revenue DESC                      │   │
│  │ LIMIT 5;                                                            │   │
│  │                                                                     │   │
│  │ Các mẫu truy xuất được:                                                 │   │
│  │   ┌───────────────────────────────────────────────────────────┐   │   │
│  │   │ Pattern 1: "size_inquiry_with_height_question"            │   │   │
│  │   │ Độ tin cậy: 0.85, Tỷ lệ thành công: 57%, Doanh thu: 42.5M │   │   │
│  │   │ Chiến lược: "Hỏi chiều cao trước khi tư vấn"             │   │   │
│  │   ├───────────────────────────────────────────────────────────┤   │   │
│  │   │ Pattern 2: "include_size_chart_link"                      │   │   │
│  │   │ Độ tin cậy: 0.72, Tỷ lệ thành công: 45%, Doanh thu: 28M   │   │   │
│  │   │ Chiến lược: "Gửi kèm link bảng size"                     │   │   │
│  │   ├───────────────────────────────────────────────────────────┤   │   │
│  │   │ Pattern 3: "general_friendly_tone"                        │   │   │
│  │   │ Độ tin cậy: 0.90, Tỷ lệ thành công: 62%, Doanh thu: 85M   │   │   │
│  │   │ Chiến lược: "Dùng emoji, xưng hô thân thiện"             │   │   │
│  │   └───────────────────────────────────────────────────────────┘   │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│         │                                                                    │
│         ▼                                                                    │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │ STEP 4: RETRIEVE SIMILAR CONVERSATIONS                              │   │
│  │ ─────────────────────────────────────                               │   │
│  │                                                                     │   │
│  │ Query message_embeddings for similar past conversations             │   │
│  │                                                                     │   │
│  │ Tìm thấy: 3 cuộc hội thoại tương tự dẫn đến đơn hàng                │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│         │                                                                    │
│         ▼                                                                    │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │ STEP 5: GET CONTACT CONTEXT                                         │   │
│  │ ──────────────────────────                                          │   │
│  │                                                                     │   │
│  │ SELECT customer_profile FROM contacts WHERE id = $contact_id        │   │
│  │                                                                     │   │
│  │ Profile: { "purchase_count": 2, "avg_order": 450000, "vip": false } │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│         │                                                                    │
│         ▼                                                                    │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │ STEP 6: ASSEMBLE PROMPT & GENERATE                                  │   │
│  │ ─────────────────────────────────                                   │   │
│  │                                                                     │   │
│  │ ┌─────────────────────────────────────────────────────────────┐   │   │
│  │ │ SYSTEM PROMPT                                               │   │   │
│  │ │ ─────────────                                               │   │   │
│  │ │ Bạn là trợ lý bán hàng của Shop ABC.                       │   │   │
│  │ │                                                             │   │   │
│  │ │ KNOWLEDGE:                                                  │   │   │
│  │ │ - Size M: 55-60kg, 158-165cm                               │   │   │
│  │ │ - Váy A001 có size S, M, L, XL                             │   │   │
│  │ │ - Đổi size trong 7 ngày                                    │   │   │
│  │ │                                                             │   │   │
│  │ │ LEARNED PATTERNS (from past success):                       │   │   │
│  │ │ ⭐ THÀNH CÔNG CAO: Khi khách hỏi size, hỏi lại chiều cao   │   │   │
│  │ │    trước khi tư vấn (57% dẫn đến đơn, TB 500K)            │   │   │
│  │ │ ⭐ Dùng giọng thân thiện với emoji (62% thành công)        │   │   │
│  │ │                                                             │   │   │
│  │ │ CUSTOMER CONTEXT:                                           │   │   │
│  │ │ - Khách quen (đã mua 2 lần, avg 450K)                      │   │   │
│  │ │                                                             │   │   │
│  │ │ Tạo 3 lựa chọn phản hồi.                                     │   │   │
│  │ └─────────────────────────────────────────────────────────────┘   │   │
│  │                                                                     │   │
│  │ USER MESSAGE: "Váy này có size M không ạ?"                         │   │
│  │                                                                     │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│         │                                                                    │
│         ▼                                                                    │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │ STEP 7: LLM GENERATES (Influenced by patterns)                      │   │
│  │ ─────────────────────────────────────────────                       │   │
│  │                                                                     │   │
│  │ Lựa chọn 1 (khuyến nghị - khớp mẫu thành công cao):              │   │
│  │ "Dạ có size M ạ chị! 😊 Chị cao bao nhiêu để em tư vấn size        │   │
│  │  chuẩn nhất nhé? Size M thường phù hợp với 158-165cm ạ"            │   │
│  │                                                                     │   │
│  │ Lựa chọn 2:                                                           │   │
│  │ "Size M còn hàng ạ! Em gửi chị bảng size để tham khảo nhé 📏"      │   │
│  │                                                                     │   │
│  │ Lựa chọn 3:                                                           │   │
│  │ "Dạ có ạ chị ơi! Size M phù hợp 55-60kg. Chị cần em tư vấn         │   │
│  │  thêm không ạ?"                                                    │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│         │                                                                    │
│         ▼                                                                    │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │ STEP 8: SAVE TO ai_suggestions                                      │   │
│  │ ─────────────────────────────                                       │   │
│  │                                                                     │   │
│  │ INSERT INTO ai_suggestions (suggestions, patterns_used, ...)        │   │
│  │                                                                     │   │
│  │ → Chờ hành động từ nhân viên → Tạo ai_feedback → Vòng lặp tiếp tục │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

Intelligence Timeline (với 3-Layer Learning System)#

┌─────────────────────────────────────────────────────────────────────────────┐
│                    DÒNG THỜI GIAN TRÍ TUỆ (VỚI 3-LAYER LEARNING)            │
│                                                                              │
│  ⭐ Khác biệt quan trọng: Nhờ 3-Layer Learning System, khách hàng mới      │
│     KHÔNG bắt đầu từ "naive" mà đã có 80+ patterns sẵn từ Day 1!           │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│   Ngày 1              Tuần 2              Tháng 1              Tháng 3      │
│   ══════              ══════              ═══════              ═══════      │
│   ┌─────┐            ┌─────┐              ┌─────┐              ┌─────┐     │
│   │ 🙂  │  ────────► │ 😊  │  ──────────► │ 🧠  │  ──────────► │ 🎯  │     │
│   │     │            │     │              │     │              │     │     │
│   │Smart│            │Learn│              │Tuned│              │Expert     │
│   └─────┘            └─────┘              └─────┘              └─────┘     │
│     ▲                                                                       │
│     │ Inherit từ Global + Industry patterns                                │
│                                                                              │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  NGÀY 1: GIAI ĐOẠN ĐÃ HUẤN LUYỆN TRƯỚC (Nhờ 3-Layer Learning)                           │
│  ═══════════════════════════════════════════════                            │
│                                                                              │
│  Mẫu được kế thừa:                                                        │
│    • Mẫu toàn cục: 50+ (từ nền tảng)                                       │
│    • Mẫu ngành: 30+ (theo ngành đã chọn)                                   │
│    • Mẫu riêng: 0 (chưa có dữ liệu riêng)                                  │
│    • Tổng có sẵn: 80+ mẫu                                         │
│                                                                              │
│  Hành vi AI:                                                                │
│    • Đã biết industry best practices                                       │
│    • Hỏi chiều cao khi khách hỏi size (Fashion)                           │
│    • Upsale combo/bundle (Global Pattern)                                  │
│    • Handle common objections                                               │
│                                                                              │
│  Sự tham gia của con người:                                                          │
│    • Tỷ lệ chỉnh sửa: 30-40% (thấp hơn nhiều so với không có 3-Layer)           │
│    • Tỷ lệ từ chối: 10-15%                                                   │
│    • AI Mode: CÓ THỂ BẬT cho simple cases ngay từ đầu!                    │
│                                                                              │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  TUẦN 1-2: GIAI ĐOẠN CÁ NHÂN HÓA                                            │
│  ═══════════════════════════════                                            │
│                                                                              │
│  Dữ liệu tích lũy:                                                           │
│    • Messages: 0 → 500                                                      │
│    • Assistant Patterns: 0 → 10 (extracted)                                │
│    • Feedback: 0 → 100                                                      │
│    • Outcomes: 0 → 20 orders linked                                        │
│                                                                              │
│  Hành vi AI:                                                                │
│    • Vẫn dùng Global + Industry patterns                                   │
│    • Bắt đầu học style riêng của shop                                      │
│    • Nhận biết customer preferences đặc thù                                │
│                                                                              │
│  Sự tham gia của con người:                                                          │
│    • Tỷ lệ chỉnh sửa: 25-35%                                                      │
│    • Tỷ lệ từ chối: 8-10%                                                     │
│    • AI Mode: BẬT cho 40-50% cases                                         │
│                                                                              │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  THÁNG 1-2: GIAI ĐOẠN TÙY CHỈNH                                                │
│  ═══════════════════════════                                                │
│                                                                              │
│  Dữ liệu tích lũy:                                                           │
│    • Messages: 1K → 5K                                                      │
│    • Assistant Patterns: 20 → 50 (một số override Global)                  │
│    • Feedback: 500 → 2000                                                   │
│    • Outcomes: 100 → 500 orders linked                                      │
│                                                                              │
│  Hành vi AI:                                                                │
│    • Style riêng của shop (formal/casual)                                  │
│    • Override một số Global patterns không phù hợp                         │
│    • Biết upsale items phổ biến của shop                                   │
│                                                                              │
│  Sự tham gia của con người:                                                          │
│    • Tỷ lệ chỉnh sửa: 20-25%                                                      │
│    • Tỷ lệ từ chối: 5-8%                                                      │
│    • AI Mode: Auto-reply 60-70% cases                                      │
│                                                                              │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  THÁNG 3-6: GIAI ĐOẠN CHUYÊN GIA                                                     │
│  ═══════════════════════                                                     │
│                                                                              │
│  Dữ liệu tích lũy:                                                           │
│    • Messages: 10K → 50K                                                    │
│    • Assistant Patterns: 100 → 300 (với revenue attribution)               │
│    • Feedback: 5K → 20K                                                     │
│    • Outcomes: 2K → 10K orders với revenue data                            │
│                                                                              │
│  Hành vi AI:                                                                │
│    • Fully personalized cho shop này                                        │
│    • Hiểu customer segments riêng                                          │
│    • Optimize for REVENUE, không chỉ satisfaction                          │
│    • Seasonal pattern awareness                                             │
│                                                                              │
│  Sự tham gia của con người:                                                          │
│    • Tỷ lệ chỉnh sửa: < 15%                                                       │
│    • Tỷ lệ từ chối: < 3%                                                      │
│    • AI Mode: Auto-reply 80%+ cases                                        │
│    • Human chỉ handle: VIP, complaints, edge cases                         │
│                                                                              │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  SO SÁNH: Có vs Không có 3-Layer Learning                                   │
│  ════════════════════════════════════════                                    │
│                                                                              │
│                    │ KHÔNG CÓ 3-Layer    │ CÓ 3-Layer Learning │           │
│  ──────────────────┼─────────────────────┼─────────────────────┤           │
│  Day 1 patterns    │ 0                   │ 80+                 │           │
│  Day 1 AI Mode     │ Nên TẮT            │ Có thể BẬT          │           │
│  Day 1 Edit rate   │ 60-70%              │ 30-40%              │           │
│  Time to AI ON     │ 1-2 tháng           │ Ngay lập tức        │           │
│  Time to Expert    │ 6-12 tháng          │ 3-6 tháng           │           │
│  ──────────────────┴─────────────────────┴─────────────────────┘           │
│                                                                              │
│  → 3-Layer Learning RÚT NGẮN thời gian "trưởng thành" của AI 50%!         │
│                                                                              │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  CẢI TIẾN LIÊN TỤC (Đang diễn ra)                                            │
│  ════════════════════════════════                                            │
│                                                                              │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │                                                                     │   │
│  │  Ra mắt sản phẩm mới                                                │   │
│  │       │                                                             │   │
│  │       ▼                                                             │   │
│  │  Tải tài liệu mới → AI biết ngay lập tức                           │   │
│  │       │                                                             │   │
│  │       ▼                                                             │   │
│  │  Hội thoại đầu tiên → Thu thập phản hồi                            │   │
│  │       │                                                             │   │
│  │       ▼                                                             │   │
│  │  Đơn hàng được đặt → Liên kết kết quả                              │   │
│  │       │                                                             │   │
│  │       ▼                                                             │   │
│  │  Trích xuất mẫu → AI tối ưu cho sản phẩm mới                       │   │
│  │       │                                                             │   │
│  │       ▼                                                             │   │
│  │  Khách hàng tiếp theo → Phản hồi tốt hơn                           │   │
│  │                                                                     │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

Bảng điều khiển Chỉ số học#

┌─────────────────────────────────────────────────────────────────────────────┐
│                    CHỈ SỐ HỌC AI (theo từng Assistant)                       │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  CHỈ SỐ KIẾN THỨC                                                           │
│  ═════════════════                                                           │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │ Tài liệu:         45                                                │   │
│  │ Đoạn:             2,340                                             │   │
│  │ Tổng tokens:      1.2M                                              │   │
│  │ Cập nhật lần cuối: 2 ngày trước                                    │   │
│  │ Điểm bao phủ:     78% (ước tính độ bao phủ chủ đề)                 │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                                                              │
│  CHỈ SỐ HỌC                                                            │
│  ════════════════                                                            │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │ Tổng mẫu:         342                                               │   │
│  │ Độ tin cậy cao:   156 (confidence > 0.8)                           │   │
│  │ Liên kết doanh thu: 89 (với outcome data)                          │   │
│  │                                                                     │   │
│  │ Top mẫu theo doanh thu:                                            │   │
│  │   1. size_with_consultation    → 42.5M VND (57% success)           │   │
│  │   2. shipping_reassurance      → 28.0M VND (62% success)           │   │
│  │   3. discount_for_bundle       → 25.0M VND (45% success)           │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                                                              │
│  CHỈ SỐ PHẢN HỒI (30 ngày gần nhất)                                            │
│  ═══════════════════════════════                                             │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │ Tổng gợi ý:         5,432                                           │   │
│  │ Chấp nhận:          3,802 (70%)  ████████████████████░░░░░░░░░     │   │
│  │ Chỉnh sửa:           869 (16%)   █████░░░░░░░░░░░░░░░░░░░░░░░░     │   │
│  │ Từ chối:             542 (10%)   ███░░░░░░░░░░░░░░░░░░░░░░░░░░     │   │
│  │ Bỏ qua:              219 (4%)    █░░░░░░░░░░░░░░░░░░░░░░░░░░░░     │   │
│  │                                                                     │   │
│  │ Xu hướng: Tỷ lệ chấp nhận ↑ 5% so với tháng trước                  │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                                                              │
│  CHỈ SỐ KẾT QUẢ (30 ngày gần nhất)                                             │
│  ══════════════════════════════                                              │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │ Hội thoại:          1,245                                           │   │
│  │ Dẫn đến đơn hàng:     623 (50%)                                    │   │
│  │ Tổng doanh thu:     312.5M VND                                     │   │
│  │ Doanh thu từ AI:    187.5M VND (60%)                               │   │
│  │ Giá trị đơn TB:       502K VND                                     │   │
│  │                                                                     │   │
│  │ Thống kê AI Mode:                                                   │   │
│  │   Tự động trả lời:    834 tin nhắn                                 │   │
│  │   Chuyển tiếp:         89 (11%)                                    │   │
│  │   Khách hài lòng:     92% (không có phản hồi tiêu cực)             │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

Truy vấn SQL cho Phân tích Học#

-- 1. Lấy các mẫu hiệu suất tốt nhất theo doanh thu
SELECT
    pattern_key,
    pattern_type,
    confidence,
    success_rate,
    total_revenue,
    sample_count,
    avg_order_value
FROM ai_learning_patterns
WHERE assistant_id = $assistant_id
  AND confidence > 0.6
ORDER BY total_revenue DESC
LIMIT 10;

-- 2. Tính hiệu suất AI theo thời gian
SELECT
    DATE_TRUNC('week', created_at) AS week,
    COUNT(*) AS total_suggestions,
    SUM(CASE WHEN action = 'accepted' THEN 1 ELSE 0 END) AS accepted,
    SUM(CASE WHEN action = 'edited' THEN 1 ELSE 0 END) AS edited,
    SUM(CASE WHEN action = 'rejected' THEN 1 ELSE 0 END) AS rejected,
    ROUND(100.0 * SUM(CASE WHEN action = 'accepted' THEN 1 ELSE 0 END) / COUNT(*), 1) AS accept_rate
FROM ai_feedback
WHERE assistant_id = $assistant_id
  AND created_at > NOW() - INTERVAL '3 months'
GROUP BY DATE_TRUNC('week', created_at)
ORDER BY week;

-- 3. Phân bổ doanh thu theo AI
SELECT
    DATE_TRUNC('month', f.created_at) AS month,
    COUNT(DISTINCT f.conversation_id) AS conversations,
    COUNT(DISTINCT CASE WHEN f.outcome_type = 'order_completed' THEN f.outcome_id END) AS orders,
    SUM(CASE WHEN f.outcome_type = 'order_completed' THEN f.outcome_value ELSE 0 END) AS total_revenue,
    AVG(CASE WHEN f.outcome_type = 'order_completed' THEN f.outcome_value END) AS avg_order_value
FROM ai_feedback f
WHERE f.assistant_id = $assistant_id
  AND f.action IN ('accepted', 'edited')
  AND f.outcome_type IS NOT NULL
GROUP BY DATE_TRUNC('month', f.created_at)
ORDER BY month;

-- 4. Xác định mẫu cần cải thiện (độ tin cậy thấp, sử dụng nhiều)
SELECT
    pattern_key,
    sample_count,
    confidence,
    success_rate
FROM ai_learning_patterns
WHERE assistant_id = $assistant_id
  AND sample_count > 50
  AND (confidence < 0.5 OR success_rate < 0.3)
ORDER BY sample_count DESC;

Ước tính dung lượng lưu trữ#

Theo từng Assistant (Hàng tháng)#

BảngBản ghiKích thước TBTổng
messages50K500B25MB
message_embeddings50K6KB300MB
conversation_summaries1K2KB2MB
ai_suggestions25K1KB25MB
ai_feedback10K500B5MB
Tổng phụ~360MB

Theo từng Assistant - Knowledge Base#

BảngBản ghiKích thước TBTổng
documents1002KB200KB
document_chunks2K1KB2MB
document_embeddings2K6KB12MB
Tổng phụ~14MB

Tổng nền tảng (Hàng tháng)#

Kịch bảnAssistantsLưu trữ/ThángHàng năm
Khởi đầu10036GB432GB
Tăng trưởng1,000360GB4.3TB
Quy mô lớn10,0003.6TB43TB

Tham số HNSW Index#

Quy môBản ghi/Assistantmef_constructionef_search
Nhỏ< 50K166440
Trung bình50K-500K24128100
Lớn500K-2M32200200
-- Production settings
SET hnsw.ef_search = 100;

-- Enable iterative scan (pgvector 0.8+)
SET hnsw.iterative_scan = relaxed_order;

Tổng kết#

Quyết định thiết kế chính#

Quyết địnhLý do
AI Assistant là thực thể chínhCho phép nhiều AI trên mỗi tenant với dữ liệu cách ly
1 Platform = 1 AssistantNgăn xung đột AI Mode
Phân vùng theo assistant_idTìm kiếm vector chính xác không mất bộ lọc
RAG thay vì fine-tuningHiệu quả chi phí, cập nhật kiến thức real-time
Theo dõi Phản hồi + Kết quảCho phép học thật sự từ kết quả kinh doanh
3-Layer Learning SystemGlobal → Industry → Assistant: Khách hàng mới có AI thông minh từ Ngày 1

Số lượng bảng: 27#

Danh mụcSố lượng
Core6
Messaging5
Knowledge Base4
AI & Learning6
Global Learning3
Support3

Cập nhật: 2026-01-22 (Cập nhật Intelligence Timeline cho 3-Layer Learning System)