清理: - 删除 34 份过时文档(gap reports/QA临时报告/验收报告/阶段性文档) - 删除 docs/.hermes/skills 第三方 skills 副本(16 文件) - 删除 skills-lock.json 目录归集: - 根目录仅保留 README.md 索引 - product/ — 产品与架构设计(PRD + ARCHITECTURE + P2设计文档 + AI/企业路线图) - tracking/ — Chatwoot parity 开发跟踪 - requirements/ — M01-M12 模块需求 - plans/ — 历史实现计划 - parity/ — 路由 parity 与前端契约 - qa/ — QA 报告与测试计划 - ops/ — 运维部署 命名规范: - 全小写 kebab-case,禁止全大写文件名 - product/tracking/ops 用 NN- 序号前缀 - requirements 用 MNN- 两位零填充模块号 - plans/qa 用 YYYY-MM-DD- 日期前缀 - requirements M1-M9 零填充为 M01-M09(修复字典序) 同步更新: - backend/cmd/route_parity/main.go 路径默认值 - backend/scripts/parity_frontend_smoke.sh 报告路径 - 所有 docs 内部交叉引用 - .gitignore 排除编译产物 (backend/gochat, backend/route_parity) - 新增迁移 000052/000053 - 前端 WS 相关修改
653 lines
30 KiB
SQL
653 lines
30 KiB
SQL
-- Migration 000053: Create missing model tables and add missing columns
|
|
-- These tables exist as Go models but were never created by SQL migrations
|
|
-- or GORM AutoMigrate (which was not called in the Bootstrap path).
|
|
|
|
-- ============ conversation_labels ============
|
|
CREATE TABLE IF NOT EXISTS conversation_labels (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
conversation_id BIGINT NOT NULL,
|
|
tag_id BIGINT NOT NULL,
|
|
account_id BIGINT NOT NULL,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_conv_labels_conv_id ON conversation_labels (conversation_id);
|
|
CREATE INDEX IF NOT EXISTS idx_conv_labels_tag_id ON conversation_labels (tag_id);
|
|
CREATE INDEX IF NOT EXISTS idx_conv_labels_account_id ON conversation_labels (account_id);
|
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_conv_label_tag ON conversation_labels (conversation_id, tag_id);
|
|
|
|
-- ============ contact_labels (may already exist from migration) ============
|
|
CREATE TABLE IF NOT EXISTS contact_labels (
|
|
contact_id BIGINT NOT NULL,
|
|
tag_id BIGINT NOT NULL,
|
|
account_id BIGINT NOT NULL,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
PRIMARY KEY (contact_id, tag_id)
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_contact_labels_contact_id ON contact_labels (contact_id);
|
|
CREATE INDEX IF NOT EXISTS idx_contact_labels_tag_id ON contact_labels (tag_id);
|
|
CREATE INDEX IF NOT EXISTS idx_contact_labels_account_id ON contact_labels (account_id);
|
|
|
|
-- ============ tags (may already exist) ============
|
|
CREATE TABLE IF NOT EXISTS tags (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
account_id BIGINT NOT NULL,
|
|
name VARCHAR(255) NOT NULL,
|
|
color VARCHAR(50) NOT NULL DEFAULT '#1f93ff',
|
|
description TEXT,
|
|
show_on_sidebar BOOLEAN,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
deleted_at TIMESTAMPTZ
|
|
);
|
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_tag_account_name ON tags (account_id, name) WHERE deleted_at IS NULL;
|
|
CREATE INDEX IF NOT EXISTS idx_tags_deleted_at ON tags (deleted_at);
|
|
|
|
-- ============ agent_bots ============
|
|
CREATE TABLE IF NOT EXISTS agent_bots (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
account_id BIGINT,
|
|
name VARCHAR(255) NOT NULL,
|
|
description VARCHAR(512),
|
|
avatar_url VARCHAR(512),
|
|
outgoing_url VARCHAR(1024),
|
|
bot_type VARCHAR(50) DEFAULT 'webhook',
|
|
secret VARCHAR(128),
|
|
access_token VARCHAR(128),
|
|
config JSONB,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_agent_bots_account_id ON agent_bots (account_id);
|
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_bots_secret ON agent_bots (secret) WHERE secret != '';
|
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_bots_access_token ON agent_bots (access_token) WHERE access_token != '';
|
|
|
|
-- ============ agent_bot_inboxes ============
|
|
CREATE TABLE IF NOT EXISTS agent_bot_inboxes (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
agent_bot_id BIGINT NOT NULL,
|
|
inbox_id BIGINT NOT NULL,
|
|
account_id BIGINT,
|
|
status INTEGER DEFAULT 0,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_agent_bot_inboxes_agent_bot_id ON agent_bot_inboxes (agent_bot_id);
|
|
CREATE INDEX IF NOT EXISTS idx_agent_bot_inboxes_inbox_id ON agent_bot_inboxes (inbox_id);
|
|
CREATE INDEX IF NOT EXISTS idx_agent_bot_inboxes_account_id ON agent_bot_inboxes (account_id);
|
|
|
|
-- ============ agent_bot_presence_events ============
|
|
CREATE TABLE IF NOT EXISTS agent_bot_presence_events (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
agent_bot_id BIGINT NOT NULL,
|
|
inbox_id BIGINT NOT NULL,
|
|
account_id BIGINT NOT NULL,
|
|
presence_type VARCHAR(100) NOT NULL,
|
|
metadata JSONB,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_agent_bot_presence_events_agent_bot_id ON agent_bot_presence_events (agent_bot_id);
|
|
CREATE INDEX IF NOT EXISTS idx_agent_bot_presence_events_inbox_id ON agent_bot_presence_events (inbox_id);
|
|
CREATE INDEX IF NOT EXISTS idx_agent_bot_presence_events_account_id ON agent_bot_presence_events (account_id);
|
|
|
|
-- ============ custom_attribute_definitions ============
|
|
CREATE TABLE IF NOT EXISTS custom_attribute_definitions (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
account_id BIGINT NOT NULL,
|
|
attribute_name VARCHAR(255) NOT NULL,
|
|
attribute_display_name VARCHAR(255) NOT NULL,
|
|
attribute_type VARCHAR(50) NOT NULL DEFAULT 'text',
|
|
attribute_model VARCHAR(50) NOT NULL,
|
|
default_value JSONB,
|
|
attribute_values JSONB,
|
|
regex_pattern VARCHAR(255),
|
|
regex_cue VARCHAR(255),
|
|
description TEXT,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
deleted_at TIMESTAMPTZ
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_custom_attr_defs_account_id ON custom_attribute_definitions (account_id);
|
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_attr_name_account_model ON custom_attribute_definitions (attribute_name, account_id, attribute_model) WHERE deleted_at IS NULL;
|
|
CREATE INDEX IF NOT EXISTS idx_custom_attr_defs_deleted_at ON custom_attribute_definitions (deleted_at);
|
|
|
|
-- ============ custom_filters ============
|
|
CREATE TABLE IF NOT EXISTS custom_filters (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
account_id BIGINT NOT NULL,
|
|
name VARCHAR(255) NOT NULL,
|
|
filter_type VARCHAR(50) NOT NULL,
|
|
query JSONB NOT NULL,
|
|
created_by_id BIGINT NOT NULL,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
deleted_at TIMESTAMPTZ
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_custom_filters_account_id ON custom_filters (account_id);
|
|
CREATE INDEX IF NOT EXISTS idx_custom_filters_filter_type ON custom_filters (filter_type);
|
|
CREATE INDEX IF NOT EXISTS idx_custom_filters_created_by_id ON custom_filters (created_by_id);
|
|
CREATE INDEX IF NOT EXISTS idx_custom_filters_deleted_at ON custom_filters (deleted_at);
|
|
|
|
-- ============ conversation_participants ============
|
|
CREATE TABLE IF NOT EXISTS conversation_participants (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
account_id BIGINT NOT NULL,
|
|
conversation_id BIGINT NOT NULL,
|
|
user_id BIGINT NOT NULL,
|
|
role VARCHAR(50) DEFAULT 'participant',
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
deleted_at TIMESTAMPTZ
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_conv_participants_account_id ON conversation_participants (account_id);
|
|
CREATE INDEX IF NOT EXISTS idx_conv_participants_conversation_id ON conversation_participants (conversation_id);
|
|
CREATE INDEX IF NOT EXISTS idx_conv_participants_user_id ON conversation_participants (user_id);
|
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_conv_participants_user_conv ON conversation_participants (user_id, conversation_id) WHERE deleted_at IS NULL;
|
|
CREATE INDEX IF NOT EXISTS idx_conv_participants_deleted_at ON conversation_participants (deleted_at);
|
|
|
|
-- ============ notes ============
|
|
CREATE TABLE IF NOT EXISTS notes (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
content TEXT NOT NULL,
|
|
account_id BIGINT NOT NULL,
|
|
contact_id BIGINT NOT NULL,
|
|
user_id BIGINT,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
deleted_at TIMESTAMPTZ
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_notes_account_id ON notes (account_id);
|
|
CREATE INDEX IF NOT EXISTS idx_notes_contact_id ON notes (contact_id);
|
|
CREATE INDEX IF NOT EXISTS idx_notes_user_id ON notes (user_id);
|
|
CREATE INDEX IF NOT EXISTS idx_notes_deleted_at ON notes (deleted_at);
|
|
|
|
-- ============ contact_notes ============
|
|
CREATE TABLE IF NOT EXISTS contact_notes (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
contact_id BIGINT NOT NULL,
|
|
user_id BIGINT NOT NULL,
|
|
content TEXT,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_contact_notes_contact_id ON contact_notes (contact_id);
|
|
|
|
-- ============ company_notes (may already exist) ============
|
|
CREATE TABLE IF NOT EXISTS company_notes (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
company_id BIGINT NOT NULL,
|
|
user_id BIGINT NOT NULL,
|
|
content TEXT,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_company_notes_company_id ON company_notes (company_id);
|
|
|
|
-- ============ csat_templates ============
|
|
CREATE TABLE IF NOT EXISTS csat_templates (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
inbox_id BIGINT NOT NULL,
|
|
message TEXT,
|
|
status VARCHAR(50) DEFAULT 'pending',
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
deleted_at TIMESTAMPTZ
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_csat_templates_inbox_id ON csat_templates (inbox_id);
|
|
CREATE INDEX IF NOT EXISTS idx_csat_templates_deleted_at ON csat_templates (deleted_at);
|
|
|
|
-- ============ delivery_statuses ============
|
|
CREATE TABLE IF NOT EXISTS delivery_statuses (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
message_id BIGINT NOT NULL,
|
|
inbox_id BIGINT NOT NULL,
|
|
contact_id BIGINT NOT NULL,
|
|
status VARCHAR(50) NOT NULL DEFAULT 'sent',
|
|
delivered_at TIMESTAMPTZ,
|
|
read_at TIMESTAMPTZ,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
deleted_at TIMESTAMPTZ
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_delivery_statuses_message_id ON delivery_statuses (message_id);
|
|
CREATE INDEX IF NOT EXISTS idx_delivery_statuses_inbox_id ON delivery_statuses (inbox_id);
|
|
CREATE INDEX IF NOT EXISTS idx_delivery_statuses_contact_id ON delivery_statuses (contact_id);
|
|
CREATE INDEX IF NOT EXISTS idx_delivery_statuses_deleted_at ON delivery_statuses (deleted_at);
|
|
|
|
-- ============ draft_messages ============
|
|
CREATE TABLE IF NOT EXISTS draft_messages (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
conversation_id BIGINT NOT NULL,
|
|
user_id BIGINT NOT NULL,
|
|
content TEXT,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
deleted_at TIMESTAMPTZ
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_draft_messages_conversation_id ON draft_messages (conversation_id);
|
|
CREATE INDEX IF NOT EXISTS idx_draft_messages_user_id ON draft_messages (user_id);
|
|
CREATE INDEX IF NOT EXISTS idx_draft_messages_deleted_at ON draft_messages (deleted_at);
|
|
|
|
-- ============ email_channel_migrations ============
|
|
CREATE TABLE IF NOT EXISTS email_channel_migrations (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
account_id BIGINT NOT NULL,
|
|
inbox_id BIGINT NOT NULL,
|
|
target_inbox_id BIGINT NOT NULL,
|
|
migration_status VARCHAR(50) NOT NULL DEFAULT 'pending',
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
deleted_at TIMESTAMPTZ
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_email_channel_migrations_account_id ON email_channel_migrations (account_id);
|
|
CREATE INDEX IF NOT EXISTS idx_email_channel_migrations_deleted_at ON email_channel_migrations (deleted_at);
|
|
|
|
-- ============ inbox_limits ============
|
|
CREATE TABLE IF NOT EXISTS inbox_limits (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
inbox_id BIGINT NOT NULL,
|
|
type VARCHAR(100) NOT NULL,
|
|
value INTEGER NOT NULL,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
deleted_at TIMESTAMPTZ
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_inbox_limits_inbox_id ON inbox_limits (inbox_id);
|
|
CREATE INDEX IF NOT EXISTS idx_inbox_limits_deleted_at ON inbox_limits (deleted_at);
|
|
|
|
-- ============ notification_subscriptions ============
|
|
CREATE TABLE IF NOT EXISTS notification_subscriptions (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
identifier TEXT NOT NULL,
|
|
subscription_attributes JSONB NOT NULL,
|
|
subscription_type INTEGER NOT NULL,
|
|
user_id BIGINT NOT NULL,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_notification_subscriptions_on_identifier ON notification_subscriptions (identifier);
|
|
CREATE INDEX IF NOT EXISTS idx_notification_subscriptions_on_user_id ON notification_subscriptions (user_id);
|
|
|
|
-- ============ sso_sessions ============
|
|
CREATE TABLE IF NOT EXISTS sso_sessions (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
user_id BIGINT NOT NULL,
|
|
session_id VARCHAR(255) NOT NULL,
|
|
provider VARCHAR(50) NOT NULL,
|
|
idp_entity_id VARCHAR(512),
|
|
name_id VARCHAR(512),
|
|
account_id BIGINT NOT NULL,
|
|
role VARCHAR(50),
|
|
access_token VARCHAR(512),
|
|
refresh_token VARCHAR(512),
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
expires_at TIMESTAMPTZ NOT NULL,
|
|
last_seen_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
ended_at TIMESTAMPTZ,
|
|
status VARCHAR(20) NOT NULL DEFAULT 'active',
|
|
deleted_at TIMESTAMPTZ
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_sso_sessions_user_id ON sso_sessions (user_id);
|
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_sso_sessions_session_id ON sso_sessions (session_id);
|
|
CREATE INDEX IF NOT EXISTS idx_sso_sessions_account_id ON sso_sessions (account_id);
|
|
CREATE INDEX IF NOT EXISTS idx_sso_sessions_expires_at ON sso_sessions (expires_at);
|
|
CREATE INDEX IF NOT EXISTS idx_sso_sessions_deleted_at ON sso_sessions (deleted_at);
|
|
|
|
-- ============ whatsapp_calls ============
|
|
CREATE TABLE IF NOT EXISTS whatsapp_calls (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
inbox_id BIGINT NOT NULL,
|
|
conversation_id BIGINT NOT NULL,
|
|
call_id VARCHAR(255) NOT NULL,
|
|
call_status VARCHAR(50) NOT NULL,
|
|
duration INTEGER,
|
|
caller_number VARCHAR(50),
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_whatsapp_calls_inbox_id ON whatsapp_calls (inbox_id);
|
|
CREATE INDEX IF NOT EXISTS idx_whatsapp_calls_conversation_id ON whatsapp_calls (conversation_id);
|
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_whatsapp_calls_call_id ON whatsapp_calls (call_id);
|
|
CREATE INDEX IF NOT EXISTS idx_whatsapp_calls_call_status ON whatsapp_calls (call_status);
|
|
CREATE INDEX IF NOT EXISTS idx_whatsapp_calls_created_at ON whatsapp_calls (created_at);
|
|
|
|
-- ============ assignment_policies (may already exist from AutoMigrate) ============
|
|
CREATE TABLE IF NOT EXISTS assignment_policies (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
account_id BIGINT NOT NULL,
|
|
inbox_id BIGINT,
|
|
policy_type VARCHAR(100) NOT NULL DEFAULT 'round_robin',
|
|
enabled BOOLEAN NOT NULL DEFAULT true,
|
|
config JSONB,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
deleted_at TIMESTAMPTZ
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_assignment_policies_account_id ON assignment_policies (account_id);
|
|
CREATE INDEX IF NOT EXISTS idx_assignment_policies_inbox_id ON assignment_policies (inbox_id);
|
|
CREATE INDEX IF NOT EXISTS idx_assignment_policies_deleted_at ON assignment_policies (deleted_at);
|
|
|
|
-- ============ assignment_policies_v2 ============
|
|
CREATE TABLE IF NOT EXISTS assignment_policies_v2 (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
account_id BIGINT NOT NULL,
|
|
inbox_id BIGINT,
|
|
policy_type VARCHAR(100) NOT NULL DEFAULT 'round_robin',
|
|
enabled BOOLEAN NOT NULL DEFAULT true,
|
|
config JSONB,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
deleted_at TIMESTAMPTZ
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_assignment_policies_v2_account_id ON assignment_policies_v2 (account_id);
|
|
CREATE INDEX IF NOT EXISTS idx_assignment_policies_v2_inbox_id ON assignment_policies_v2 (inbox_id);
|
|
CREATE INDEX IF NOT EXISTS idx_assignment_policies_v2_deleted_at ON assignment_policies_v2 (deleted_at);
|
|
|
|
-- ============ automation_actions ============
|
|
CREATE TABLE IF NOT EXISTS automation_actions (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
account_id BIGINT NOT NULL,
|
|
action_type VARCHAR(100) NOT NULL,
|
|
config JSONB,
|
|
executed_at TIMESTAMPTZ,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
deleted_at TIMESTAMPTZ
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_automation_actions_account_id ON automation_actions (account_id);
|
|
CREATE INDEX IF NOT EXISTS idx_automation_actions_deleted_at ON automation_actions (deleted_at);
|
|
|
|
-- ============ banners ============
|
|
CREATE TABLE IF NOT EXISTS banners (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
title VARCHAR(255),
|
|
content TEXT,
|
|
banner_type VARCHAR(50),
|
|
status VARCHAR(50) DEFAULT 'active',
|
|
starts_at TIMESTAMPTZ,
|
|
ends_at TIMESTAMPTZ,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
deleted_at TIMESTAMPTZ
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_banners_status ON banners (status);
|
|
CREATE INDEX IF NOT EXISTS idx_banners_deleted_at ON banners (deleted_at);
|
|
|
|
-- ============ captain_assistant_inboxes ============
|
|
CREATE TABLE IF NOT EXISTS captain_assistant_inboxes (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
captain_assistant_id BIGINT NOT NULL,
|
|
inbox_id BIGINT NOT NULL,
|
|
account_id BIGINT NOT NULL,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
deleted_at TIMESTAMPTZ
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_captain_assistant_inboxes_assistant_id ON captain_assistant_inboxes (captain_assistant_id);
|
|
CREATE INDEX IF NOT EXISTS idx_captain_assistant_inboxes_inbox_id ON captain_assistant_inboxes (inbox_id);
|
|
CREATE INDEX IF NOT EXISTS idx_captain_assistant_inboxes_account_id ON captain_assistant_inboxes (account_id);
|
|
CREATE INDEX IF NOT EXISTS idx_captain_assistant_inboxes_deleted_at ON captain_assistant_inboxes (deleted_at);
|
|
|
|
-- ============ contactables ============
|
|
CREATE TABLE IF NOT EXISTS contactables (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
account_id BIGINT NOT NULL,
|
|
contactable_type VARCHAR(50) NOT NULL,
|
|
contactable_id BIGINT NOT NULL,
|
|
email VARCHAR(255),
|
|
phone VARCHAR(50),
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
deleted_at TIMESTAMPTZ
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_contactables_account_id ON contactables (account_id);
|
|
CREATE INDEX IF NOT EXISTS idx_contactables_contactable_type_id ON contactables (contactable_type, contactable_id);
|
|
CREATE INDEX IF NOT EXISTS idx_contactables_deleted_at ON contactables (deleted_at);
|
|
|
|
-- ============ contact_exports ============
|
|
CREATE TABLE IF NOT EXISTS contact_exports (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
account_id BIGINT NOT NULL,
|
|
user_id BIGINT NOT NULL,
|
|
status VARCHAR(50) DEFAULT 'pending',
|
|
file_url TEXT,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
deleted_at TIMESTAMPTZ
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_contact_exports_account_id ON contact_exports (account_id);
|
|
CREATE INDEX IF NOT EXISTS idx_contact_exports_user_id ON contact_exports (user_id);
|
|
CREATE INDEX IF NOT EXISTS idx_contact_exports_deleted_at ON contact_exports (deleted_at);
|
|
|
|
-- ============ data_imports ============
|
|
CREATE TABLE IF NOT EXISTS data_imports (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
account_id BIGINT NOT NULL,
|
|
user_id BIGINT NOT NULL,
|
|
status VARCHAR(50) DEFAULT 'pending',
|
|
file_url TEXT,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
deleted_at TIMESTAMPTZ
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_data_imports_account_id ON data_imports (account_id);
|
|
CREATE INDEX IF NOT EXISTS idx_data_imports_user_id ON data_imports (user_id);
|
|
CREATE INDEX IF NOT EXISTS idx_data_imports_deleted_at ON data_imports (deleted_at);
|
|
|
|
-- ============ direct_uploads ============
|
|
CREATE TABLE IF NOT EXISTS direct_uploads (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
account_id BIGINT NOT NULL,
|
|
file_name VARCHAR(255),
|
|
file_url TEXT,
|
|
file_size BIGINT,
|
|
content_type VARCHAR(100),
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
deleted_at TIMESTAMPTZ
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_direct_uploads_account_id ON direct_uploads (account_id);
|
|
CREATE INDEX IF NOT EXISTS idx_direct_uploads_deleted_at ON direct_uploads (deleted_at);
|
|
|
|
-- ============ email_templates ============
|
|
CREATE TABLE IF NOT EXISTS email_templates (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
account_id BIGINT NOT NULL,
|
|
name VARCHAR(255) NOT NULL,
|
|
subject VARCHAR(512),
|
|
body TEXT,
|
|
template_type VARCHAR(50),
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
deleted_at TIMESTAMPTZ
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_email_templates_account_id ON email_templates (account_id);
|
|
CREATE INDEX IF NOT EXISTS idx_email_templates_deleted_at ON email_templates (deleted_at);
|
|
|
|
-- ============ message_reactions ============
|
|
CREATE TABLE IF NOT EXISTS message_reactions (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
message_id BIGINT NOT NULL,
|
|
account_id BIGINT NOT NULL,
|
|
user_id BIGINT NOT NULL,
|
|
reaction_type VARCHAR(50) NOT NULL,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
deleted_at TIMESTAMPTZ
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_message_reactions_message_id ON message_reactions (message_id);
|
|
CREATE INDEX IF NOT EXISTS idx_message_reactions_account_id ON message_reactions (account_id);
|
|
CREATE INDEX IF NOT EXISTS idx_message_reactions_user_id ON message_reactions (user_id);
|
|
CREATE INDEX IF NOT EXISTS idx_message_reactions_deleted_at ON message_reactions (deleted_at);
|
|
|
|
-- ============ reports ============
|
|
CREATE TABLE IF NOT EXISTS reports (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
account_id BIGINT NOT NULL,
|
|
report_type VARCHAR(100) NOT NULL,
|
|
config JSONB,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
deleted_at TIMESTAMPTZ
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_reports_account_id ON reports (account_id);
|
|
CREATE INDEX IF NOT EXISTS idx_reports_report_type ON reports (report_type);
|
|
CREATE INDEX IF NOT EXISTS idx_reports_deleted_at ON reports (deleted_at);
|
|
|
|
-- ============ saml_idp_configs ============
|
|
CREATE TABLE IF NOT EXISTS saml_idp_configs (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
account_id BIGINT NOT NULL,
|
|
entity_id VARCHAR(512),
|
|
sso_url VARCHAR(512),
|
|
slo_url VARCHAR(512),
|
|
x509_cert TEXT,
|
|
name_id_format VARCHAR(100),
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
deleted_at TIMESTAMPTZ
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_saml_idp_configs_account_id ON saml_idp_configs (account_id);
|
|
CREATE INDEX IF NOT EXISTS idx_saml_idp_configs_deleted_at ON saml_idp_configs (deleted_at);
|
|
|
|
-- ============ pre_chat_forms ============
|
|
CREATE TABLE IF NOT EXISTS pre_chat_forms (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
inbox_id BIGINT NOT NULL,
|
|
enabled BOOLEAN DEFAULT false,
|
|
form_config JSONB,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
deleted_at TIMESTAMPTZ
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_pre_chat_forms_inbox_id ON pre_chat_forms (inbox_id);
|
|
CREATE INDEX IF NOT EXISTS idx_pre_chat_forms_deleted_at ON pre_chat_forms (deleted_at);
|
|
|
|
-- ============ widget_file_uploads ============
|
|
CREATE TABLE IF NOT EXISTS widget_file_uploads (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
inbox_id BIGINT NOT NULL,
|
|
enabled BOOLEAN DEFAULT true,
|
|
max_file_size INTEGER,
|
|
allowed_types JSONB,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
deleted_at TIMESTAMPTZ
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_widget_file_uploads_inbox_id ON widget_file_uploads (inbox_id);
|
|
CREATE INDEX IF NOT EXISTS idx_widget_file_uploads_deleted_at ON widget_file_uploads (deleted_at);
|
|
|
|
-- ============ widget_offline_messages ============
|
|
CREATE TABLE IF NOT EXISTS widget_offline_messages (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
inbox_id BIGINT NOT NULL,
|
|
email VARCHAR(255),
|
|
message TEXT,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
deleted_at TIMESTAMPTZ
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_widget_offline_messages_inbox_id ON widget_offline_messages (inbox_id);
|
|
CREATE INDEX IF NOT EXISTS idx_widget_offline_messages_deleted_at ON widget_offline_messages (deleted_at);
|
|
|
|
-- ============ widget_theme_configs ============
|
|
CREATE TABLE IF NOT EXISTS widget_theme_configs (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
inbox_id BIGINT NOT NULL,
|
|
theme_config JSONB,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
deleted_at TIMESTAMPTZ
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_widget_theme_configs_inbox_id ON widget_theme_configs (inbox_id);
|
|
CREATE INDEX IF NOT EXISTS idx_widget_theme_configs_deleted_at ON widget_theme_configs (deleted_at);
|
|
|
|
-- ============ widget_tests ============
|
|
CREATE TABLE IF NOT EXISTS widget_tests (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
inbox_id BIGINT NOT NULL,
|
|
test_config JSONB,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
deleted_at TIMESTAMPTZ
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_widget_tests_inbox_id ON widget_tests (inbox_id);
|
|
CREATE INDEX IF NOT EXISTS idx_widget_tests_deleted_at ON widget_tests (deleted_at);
|
|
|
|
-- ============ working_hours ============
|
|
CREATE TABLE IF NOT EXISTS working_hours (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
inbox_id BIGINT NOT NULL,
|
|
day_of_week INTEGER NOT NULL,
|
|
start_time VARCHAR(10),
|
|
end_time VARCHAR(10),
|
|
enabled BOOLEAN DEFAULT true,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
deleted_at TIMESTAMPTZ
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_working_hours_inbox_id ON working_hours (inbox_id);
|
|
CREATE INDEX IF NOT EXISTS idx_working_hours_deleted_at ON working_hours (deleted_at);
|
|
|
|
-- ============ account_ldap_settings ============
|
|
CREATE TABLE IF NOT EXISTS account_ldap_settings (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
account_id BIGINT NOT NULL,
|
|
enabled BOOLEAN DEFAULT false,
|
|
host VARCHAR(255),
|
|
port INTEGER,
|
|
base_dn VARCHAR(255),
|
|
bind_dn VARCHAR(255),
|
|
bind_password VARCHAR(255),
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
deleted_at TIMESTAMPTZ
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_account_ldap_settings_account_id ON account_ldap_settings (account_id);
|
|
CREATE INDEX IF NOT EXISTS idx_account_ldap_settings_deleted_at ON account_ldap_settings (deleted_at);
|
|
|
|
-- ============ account_oidc_settings ============
|
|
CREATE TABLE IF NOT EXISTS account_oidc_settings (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
account_id BIGINT NOT NULL,
|
|
enabled BOOLEAN DEFAULT false,
|
|
issuer VARCHAR(512),
|
|
client_id VARCHAR(255),
|
|
client_secret VARCHAR(255),
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
deleted_at TIMESTAMPTZ
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_account_oidc_settings_account_id ON account_oidc_settings (account_id);
|
|
CREATE INDEX IF NOT EXISTS idx_account_oidc_settings_deleted_at ON account_oidc_settings (deleted_at);
|
|
|
|
-- ============ account_saml_settings ============
|
|
CREATE TABLE IF NOT EXISTS account_saml_settings (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
account_id BIGINT NOT NULL,
|
|
enabled BOOLEAN DEFAULT false,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
deleted_at TIMESTAMPTZ
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_account_saml_settings_account_id ON account_saml_settings (account_id);
|
|
CREATE INDEX IF NOT EXISTS idx_account_saml_settings_deleted_at ON account_saml_settings (deleted_at);
|
|
|
|
-- ============ push_tokens ============
|
|
CREATE TABLE IF NOT EXISTS push_tokens (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
user_id BIGINT NOT NULL,
|
|
token TEXT NOT NULL,
|
|
platform VARCHAR(50),
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
deleted_at TIMESTAMPTZ
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_push_tokens_user_id ON push_tokens (user_id);
|
|
CREATE INDEX IF NOT EXISTS idx_push_tokens_deleted_at ON push_tokens (deleted_at);
|
|
|
|
-- ============ Add snoozed_until column to notifications ============
|
|
ALTER TABLE notifications ADD COLUMN IF NOT EXISTS snoozed_until TIMESTAMPTZ;
|
|
|
|
-- ============ Add missing columns to channels table ============
|
|
ALTER TABLE channels ADD COLUMN IF NOT EXISTS type VARCHAR(100);
|