-- G16: Third-party integration tables (IntegrationHook + IntegrationApp) -- Reference: Chatwoot Integrations::Hook + Integrations::App -- IntegrationHook: per-account/per-inbox integration binding -- Stores provider-specific settings in JSONB, keyed by hook_type (slack/shopify/linear/notion/webhook) CREATE TABLE IF NOT EXISTS integration_hooks ( id SERIAL PRIMARY KEY, account_id INTEGER NOT NULL, inbox_id INTEGER, -- NULL = account-level hook hook_type VARCHAR(50) NOT NULL, -- webhook/slack/shopify/linear/notion status VARCHAR(20) DEFAULT 'active', -- active/inactive url VARCHAR(1024) DEFAULT '', -- webhook callback URL access_token VARCHAR(256), -- API token for the hook (unique) settings JSONB DEFAULT '{}', -- provider-specific config (Slack channel_id, Shopify shop_domain, etc.) 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_integration_hooks_account_id ON integration_hooks(account_id) WHERE deleted_at IS NULL; CREATE INDEX idx_integration_hooks_inbox_id ON integration_hooks(inbox_id) WHERE deleted_at IS NULL; CREATE INDEX idx_integration_hooks_hook_type ON integration_hooks(hook_type) WHERE deleted_at IS NULL; CREATE UNIQUE INDEX idx_integration_hooks_access_token ON integration_hooks(access_token) WHERE deleted_at IS NULL AND access_token IS NOT NULL; CREATE INDEX idx_integration_hooks_deleted_at ON integration_hooks(deleted_at); -- IntegrationApp: catalog of supported integrations -- Each app is keyed by hook_type (one app per provider type) CREATE TABLE IF NOT EXISTS integration_apps ( id SERIAL PRIMARY KEY, name VARCHAR(255) NOT NULL, description VARCHAR(512) DEFAULT '', hook_type VARCHAR(50) NOT NULL, -- webhook/slack/shopify/linear/notion icon VARCHAR(512) DEFAULT '', -- icon URL or CSS class action_url VARCHAR(1024) DEFAULT '', -- frontend action URL for setup page enabled BOOLEAN DEFAULT TRUE, -- whether the integration is available for installation created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); CREATE UNIQUE INDEX idx_integration_apps_hook_type ON integration_apps(hook_type); -- Seed default integration apps INSERT INTO integration_apps (name, description, hook_type, icon, action_url, enabled) VALUES ('Slack', 'Connect Slack channels for real-time notifications', 'slack', '/assets/integrations/slack.svg', '/app/accounts/{account_id}/integrations/slack', TRUE), ('Shopify', 'Sync Shopify orders and customer data', 'shopify', '/assets/integrations/shopify.svg', '/app/accounts/{account_id}/integrations/shopify', TRUE), ('Linear', 'Create Linear issues from conversations', 'linear', '/assets/integrations/linear.svg', '/app/accounts/{account_id}/integrations/linear', TRUE), ('Notion', 'Export conversation summaries to Notion pages', 'notion', '/assets/integrations/notion.svg', '/app/accounts/{account_id}/integrations/notion', TRUE), ('Webhook', 'Custom webhook for event-driven integrations', 'webhook', '/assets/integrations/webhook.svg', '/app/accounts/{account_id}/integrations/webhook', TRUE) ON CONFLICT (hook_type) DO NOTHING;