146 lines
6.4 KiB
SQL
146 lines
6.4 KiB
SQL
-- GoChat Knowledge Base (Help Center) tables
|
|
-- Reference: Chatwoot Portal/Category/Article/Folder models
|
|
-- M4 milestone: KnowledgeBase + Article CRUD + Search
|
|
|
|
-- Portals (Knowledge Base containers)
|
|
-- Chatwoot names this "Portal" in the data model; concept = "Knowledge Base"
|
|
CREATE TABLE IF NOT EXISTS portals (
|
|
id SERIAL PRIMARY KEY,
|
|
account_id INTEGER NOT NULL,
|
|
name VARCHAR(255) NOT NULL,
|
|
slug VARCHAR(255) NOT NULL,
|
|
description TEXT DEFAULT '',
|
|
logo_url VARCHAR(512) DEFAULT '',
|
|
header_text TEXT DEFAULT '',
|
|
homepage_link VARCHAR(512) DEFAULT '',
|
|
page_title VARCHAR(255) DEFAULT '',
|
|
color VARCHAR(50) DEFAULT '#1f93ff',
|
|
custom_domain VARCHAR(255) DEFAULT '',
|
|
locale VARCHAR(10) DEFAULT 'en',
|
|
archived BOOLEAN DEFAULT FALSE,
|
|
portal_configuration JSONB DEFAULT '{}',
|
|
ssl_settings JSONB DEFAULT '{}',
|
|
homepage_content TEXT DEFAULT '',
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
deleted_at TIMESTAMP WITH TIME ZONE
|
|
);
|
|
|
|
CREATE UNIQUE INDEX idx_portals_slug ON portals(slug) WHERE deleted_at IS NULL;
|
|
CREATE INDEX idx_portals_account_id ON portals(account_id) WHERE deleted_at IS NULL;
|
|
CREATE INDEX idx_portals_custom_domain ON portals(custom_domain) WHERE deleted_at IS NULL AND custom_domain != '';
|
|
CREATE INDEX idx_portals_archived ON portals(archived) WHERE deleted_at IS NULL;
|
|
CREATE INDEX idx_portals_deleted_at ON portals(deleted_at);
|
|
|
|
-- Categories (article grouping within a portal)
|
|
CREATE TABLE IF NOT EXISTS categories (
|
|
id SERIAL PRIMARY KEY,
|
|
portal_id INTEGER NOT NULL,
|
|
name VARCHAR(255) NOT NULL,
|
|
description TEXT DEFAULT '',
|
|
slug VARCHAR(255) NOT NULL,
|
|
icon VARCHAR(255) DEFAULT '',
|
|
position INTEGER DEFAULT 0,
|
|
locale VARCHAR(10) DEFAULT 'en',
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
deleted_at TIMESTAMP WITH TIME ZONE
|
|
);
|
|
|
|
CREATE UNIQUE INDEX idx_categories_slug ON categories(slug) WHERE deleted_at IS NULL;
|
|
CREATE INDEX idx_categories_portal_id ON categories(portal_id) WHERE deleted_at IS NULL;
|
|
CREATE INDEX idx_categories_position ON categories(portal_id, position) WHERE deleted_at IS NULL;
|
|
CREATE INDEX idx_categories_deleted_at ON categories(deleted_at);
|
|
|
|
-- Related categories (many-to-many between categories)
|
|
CREATE TABLE IF NOT EXISTS related_categories (
|
|
id SERIAL PRIMARY KEY,
|
|
category_id INTEGER NOT NULL,
|
|
related_category_id INTEGER NOT NULL,
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
deleted_at TIMESTAMP WITH TIME ZONE
|
|
);
|
|
|
|
CREATE INDEX idx_related_categories_category_id ON related_categories(category_id) WHERE deleted_at IS NULL;
|
|
CREATE INDEX idx_related_categories_related_category_id ON related_categories(related_category_id) WHERE deleted_at IS NULL;
|
|
CREATE INDEX idx_related_categories_deleted_at ON related_categories(deleted_at);
|
|
|
|
-- Articles (help center content)
|
|
CREATE TABLE IF NOT EXISTS articles (
|
|
id SERIAL PRIMARY KEY,
|
|
account_id INTEGER NOT NULL,
|
|
portal_id INTEGER NOT NULL,
|
|
category_id INTEGER,
|
|
folder_id INTEGER,
|
|
author_id INTEGER,
|
|
title VARCHAR(255) NOT NULL,
|
|
slug VARCHAR(255) NOT NULL,
|
|
description TEXT DEFAULT '',
|
|
content TEXT DEFAULT '',
|
|
status VARCHAR(50) NOT NULL DEFAULT 'draft',
|
|
position INTEGER DEFAULT 0,
|
|
views INTEGER DEFAULT 0,
|
|
locale VARCHAR(10) DEFAULT 'en',
|
|
associated_article_id INTEGER,
|
|
meta JSONB DEFAULT '{}',
|
|
custom_attributes JSONB DEFAULT '{}',
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
deleted_at TIMESTAMP WITH TIME ZONE
|
|
);
|
|
|
|
CREATE UNIQUE INDEX idx_articles_slug ON articles(slug) WHERE deleted_at IS NULL;
|
|
CREATE INDEX idx_articles_account_id ON articles(account_id) WHERE deleted_at IS NULL;
|
|
CREATE INDEX idx_articles_portal_id ON articles(portal_id) WHERE deleted_at IS NULL;
|
|
CREATE INDEX idx_articles_category_id ON articles(category_id) WHERE deleted_at IS NULL AND category_id IS NOT NULL;
|
|
CREATE INDEX idx_articles_folder_id ON articles(folder_id) WHERE deleted_at IS NULL AND folder_id IS NOT NULL;
|
|
CREATE INDEX idx_articles_author_id ON articles(author_id) WHERE deleted_at IS NULL AND author_id IS NOT NULL;
|
|
CREATE INDEX idx_articles_status ON articles(portal_id, status) WHERE deleted_at IS NULL;
|
|
CREATE INDEX idx_articles_position ON articles(portal_id, position) WHERE deleted_at IS NULL;
|
|
CREATE INDEX idx_articles_associated_article_id ON articles(associated_article_id) WHERE deleted_at IS NULL AND associated_article_id IS NOT NULL;
|
|
CREATE INDEX idx_articles_deleted_at ON articles(deleted_at);
|
|
|
|
-- Folders (article organization within a portal)
|
|
CREATE TABLE IF NOT EXISTS folders (
|
|
id SERIAL PRIMARY KEY,
|
|
portal_id INTEGER NOT NULL,
|
|
name VARCHAR(255) NOT NULL,
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
deleted_at TIMESTAMP WITH TIME ZONE
|
|
);
|
|
|
|
CREATE INDEX idx_folders_portal_id ON folders(portal_id) WHERE deleted_at IS NULL;
|
|
CREATE INDEX idx_folders_deleted_at ON folders(deleted_at);
|
|
|
|
-- Portal members (user membership with roles)
|
|
CREATE TABLE IF NOT EXISTS portal_members (
|
|
id SERIAL PRIMARY KEY,
|
|
portal_id INTEGER NOT NULL,
|
|
user_id INTEGER NOT NULL,
|
|
role VARCHAR(50) NOT NULL DEFAULT 'reader',
|
|
custom_attributes JSONB DEFAULT '{}',
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
deleted_at TIMESTAMP WITH TIME ZONE
|
|
);
|
|
|
|
CREATE INDEX idx_portal_members_portal_id ON portal_members(portal_id) WHERE deleted_at IS NULL;
|
|
CREATE INDEX idx_portal_members_user_id ON portal_members(user_id) WHERE deleted_at IS NULL;
|
|
CREATE UNIQUE INDEX idx_portal_members_portal_user ON portal_members(portal_id, user_id) WHERE deleted_at IS NULL;
|
|
CREATE INDEX idx_portal_members_deleted_at ON portal_members(deleted_at);
|
|
|
|
-- Article embeddings (vector search, enterprise feature)
|
|
CREATE TABLE IF NOT EXISTS article_embeddings (
|
|
id SERIAL PRIMARY KEY,
|
|
article_id INTEGER NOT NULL,
|
|
embedding JSONB NOT NULL,
|
|
term TEXT NOT NULL,
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
deleted_at TIMESTAMP WITH TIME ZONE
|
|
);
|
|
|
|
CREATE INDEX idx_article_embeddings_article_id ON article_embeddings(article_id) WHERE deleted_at IS NULL;
|
|
CREATE INDEX idx_article_embeddings_deleted_at ON article_embeddings(deleted_at); |