Add Lead Scoring ML + Email Sequences/Drip Campaigns
Build & Auto-Repair / build (push) Has been cancelled
Build & Auto-Repair / build (push) Has been cancelled
Lead Scoring:
- lead_scoring_config table with configurable feature weights
- Scoring engine: boolean, keyword, and range-based feature scoring
- Settings tab: configure scoring features, run scoring on all leads
- ml_score + ml_score_details columns on leads table
- API: /api/leads/score, /api/leads/score/config
- mlScore returned in lead detail and list APIs
Email Campaigns:
- email_campaigns, email_campaign_steps, subscribers, logs tables
- Campaign list page with status badges and subscriber counts
- Campaign detail with step management, subscriber search/add, send
- Drip logic: steps with configurable delay days, template variables
- Variable replacement ({{name}}, {{email}}) in email bodies
- Sidebar: Campaigns nav item
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
-- ============================================================================
|
||||
-- Lead Scoring ML — Configurable scoring engine with historical training
|
||||
-- ============================================================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS lead_scoring_config (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
feature_name VARCHAR(100) NOT NULL UNIQUE,
|
||||
feature_type VARCHAR(50) NOT NULL DEFAULT 'keyword',
|
||||
field_ref VARCHAR(100) NOT NULL,
|
||||
weight DECIMAL(5,2) NOT NULL DEFAULT 1.00,
|
||||
value_map JSONB,
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_lead_scoring_active ON lead_scoring_config(is_active);
|
||||
|
||||
ALTER TABLE leads ADD COLUMN IF NOT EXISTS ml_score INT DEFAULT 0;
|
||||
ALTER TABLE leads ADD COLUMN IF NOT EXISTS ml_score_details JSONB;
|
||||
|
||||
-- Seed default scoring features
|
||||
INSERT INTO lead_scoring_config (feature_name, feature_type, field_ref, weight, value_map) VALUES
|
||||
('Has Email', 'boolean', 'email', 5, '{"true": 5, "false": 0}'),
|
||||
('Has Phone', 'boolean', 'phone', 5, '{"true": 5, "false": 0}'),
|
||||
('Source: Referral', 'keyword', 'source', 15, '{"referral": 15, "friend": 15, "word_of_mouth": 15}'),
|
||||
('Source: Website', 'keyword', 'source', 10, '{"website": 10, "organic": 8, "direct": 8}'),
|
||||
('Source: Social', 'keyword', 'source', 8, '{"facebook": 8, "linkedin": 8, "twitter": 5, "instagram": 5}'),
|
||||
('Source: Paid', 'keyword', 'source', 6, '{"google_ads": 6, "paid": 6, "ppc": 6}'),
|
||||
('Company Name Present', 'boolean', 'company_name', 10, '{"true": 10, "false": 0}'),
|
||||
('Description Length', 'range', 'description', 10, '{"0": 0, "50": 5, "200": 10, "500": 15}')
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- Update ml_score for all existing leads
|
||||
UPDATE leads SET ml_score = 0 WHERE ml_score IS NULL;
|
||||
@@ -0,0 +1,62 @@
|
||||
-- ============================================================================
|
||||
-- Email Sequences / Drip Campaigns — Automated follow-up sequences
|
||||
-- ============================================================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS email_campaigns (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
name VARCHAR(255) NOT NULL,
|
||||
description TEXT,
|
||||
status VARCHAR(50) NOT NULL DEFAULT 'draft',
|
||||
trigger_type VARCHAR(50) NOT NULL DEFAULT 'manual',
|
||||
trigger_config JSONB,
|
||||
created_by UUID REFERENCES users(id),
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
deleted_at TIMESTAMPTZ
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS email_campaign_steps (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
campaign_id UUID NOT NULL REFERENCES email_campaigns(id) ON DELETE CASCADE,
|
||||
step_order INT NOT NULL DEFAULT 0,
|
||||
delay_days INT NOT NULL DEFAULT 0,
|
||||
subject VARCHAR(500) NOT NULL,
|
||||
body_text TEXT,
|
||||
body_html TEXT,
|
||||
variables JSONB,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS email_campaign_subscribers (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
campaign_id UUID NOT NULL REFERENCES email_campaigns(id) ON DELETE CASCADE,
|
||||
lead_id UUID REFERENCES leads(id) ON DELETE SET NULL,
|
||||
email VARCHAR(255) NOT NULL,
|
||||
contact_name VARCHAR(255),
|
||||
subscribed_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
unsubscribed_at TIMESTAMPTZ,
|
||||
status VARCHAR(50) NOT NULL DEFAULT 'pending',
|
||||
current_step INT NOT NULL DEFAULT 0,
|
||||
last_sent_at TIMESTAMPTZ,
|
||||
CONSTRAINT uq_campaign_lead UNIQUE (campaign_id, lead_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS email_campaign_logs (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
campaign_id UUID REFERENCES email_campaigns(id) ON DELETE CASCADE,
|
||||
subscriber_id UUID REFERENCES email_campaign_subscribers(id) ON DELETE CASCADE,
|
||||
step_id UUID REFERENCES email_campaign_steps(id) ON DELETE SET NULL,
|
||||
recipient VARCHAR(255) NOT NULL,
|
||||
subject VARCHAR(500),
|
||||
body_text TEXT,
|
||||
sent_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
status VARCHAR(50) NOT NULL DEFAULT 'sent',
|
||||
error_message TEXT
|
||||
);
|
||||
|
||||
ALTER TABLE email_campaign_subscribers ADD CONSTRAINT IF NOT EXISTS uq_campaign_lead UNIQUE (campaign_id, lead_id);
|
||||
|
||||
CREATE INDEX idx_campaign_steps_order ON email_campaign_steps(campaign_id, step_order);
|
||||
CREATE INDEX idx_campaign_subscribers ON email_campaign_subscribers(campaign_id, status);
|
||||
CREATE INDEX idx_campaign_logs ON email_campaign_logs(campaign_id, sent_at);
|
||||
@@ -91,5 +91,11 @@ BEGIN;
|
||||
\echo '=== Running 024_resource_planning.sql (Resource Planning) ==='
|
||||
\i 024_resource_planning.sql
|
||||
|
||||
\echo '=== Running 025_lead_scoring.sql (Lead Scoring ML) ==='
|
||||
\i 025_lead_scoring.sql
|
||||
|
||||
\echo '=== Running 026_email_campaigns.sql (Email Campaigns) ==='
|
||||
\i 026_email_campaigns.sql
|
||||
|
||||
\echo '=== Migration Complete ==='
|
||||
COMMIT;
|
||||
|
||||
Reference in New Issue
Block a user