-- ============================================================================ -- Custom Fields — Adaptable fields per entity type (leads, customers, etc.) -- ============================================================================ CREATE TABLE IF NOT EXISTS custom_field_definitions ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), entity_type VARCHAR(50) NOT NULL, field_key VARCHAR(100) NOT NULL, field_label VARCHAR(255) NOT NULL, field_type VARCHAR(50) NOT NULL DEFAULT 'text', options JSONB, placeholder TEXT, default_value TEXT, section VARCHAR(100), is_required BOOLEAN NOT NULL DEFAULT FALSE, sort_order INT NOT NULL DEFAULT 0, is_active BOOLEAN NOT NULL DEFAULT TRUE, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), CONSTRAINT uq_custom_field_entity_key UNIQUE (entity_type, field_key), CONSTRAINT chk_custom_field_type CHECK (field_type IN ('text','number','date','select','multi_select','boolean','url','email','phone')) ); CREATE INDEX idx_custom_fields_entity ON custom_field_definitions(entity_type, is_active, sort_order); ALTER TABLE leads ADD COLUMN IF NOT EXISTS custom_fields JSONB DEFAULT '{}'; ALTER TABLE customers ADD COLUMN IF NOT EXISTS custom_fields JSONB DEFAULT '{}'; ALTER TABLE opportunities ADD COLUMN IF NOT EXISTS custom_fields JSONB DEFAULT '{}'; ALTER TABLE projects ADD COLUMN IF NOT EXISTS custom_fields JSONB DEFAULT '{}'; -- Seed sample fields INSERT INTO custom_field_definitions (entity_type, field_key, field_label, field_type, options, section, sort_order) VALUES ('lead', 'service_type', 'Service Type', 'select', '["Web Development","Mobile App","SEO","Consulting","Retainer","Maintenance"]', 'Details', 1), ('lead', 'budget_confirmed', 'Budget Confirmed', 'boolean', NULL, 'Details', 2), ('lead', 'referral_source', 'Referral Source', 'text', NULL, 'Details', 3), ('customer', 'industry_vertical', 'Industry Vertical', 'select', '["Fintech","Healthcare","E-commerce","Education","Real Estate","Hospitality","Other"]', 'Business', 1), ('customer', 'vat_number', 'VAT Number', 'text', NULL, 'Business', 2), ('project', 'project_type', 'Project Type', 'select', '["New Build","Redesign","Maintenance","Consulting","Retainer"]', 'Details', 1), ('project', 'hosting_provider', 'Hosting Provider', 'text', NULL, 'Technical', 2), ('project', 'tech_stack', 'Tech Stack', 'multi_select', '["React","Next.js","Node.js","Python","PHP","WordPress","Shopify","Laravel","Vue","Angular"]', 'Technical', 3), ('opportunity', 'competitor', 'Competitor', 'text', NULL, 'Details', 1), ('opportunity', 'decision_timeline', 'Decision Timeline', 'select', '["This Week","This Month","This Quarter","Next Quarter","Not Sure"]', 'Details', 2) ON CONFLICT (entity_type, field_key) DO NOTHING;