-- Extension 5: Professional CRM -- Contacts, interaction logs, and opportunities (single-user, no RLS) CREATE TABLE IF NOT EXISTS professional_contacts ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name TEXT NOT NULL, company TEXT, title TEXT, email TEXT, phone TEXT, linkedin_url TEXT, how_we_met TEXT, tags TEXT[] NOT NULL DEFAULT '{}', notes TEXT, last_contacted TIMESTAMPTZ, follow_up_date DATE, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE TABLE IF NOT EXISTS contact_interactions ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), contact_id UUID NOT NULL REFERENCES professional_contacts(id) ON DELETE CASCADE, interaction_type TEXT NOT NULL CHECK (interaction_type IN ('meeting', 'email', 'call', 'coffee', 'event', 'linkedin', 'other')), occurred_at TIMESTAMPTZ NOT NULL DEFAULT now(), summary TEXT NOT NULL, follow_up_needed BOOLEAN NOT NULL DEFAULT false, follow_up_notes TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE TABLE IF NOT EXISTS opportunities ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), contact_id UUID REFERENCES professional_contacts(id) ON DELETE SET NULL, title TEXT NOT NULL, description TEXT, stage TEXT NOT NULL DEFAULT 'identified' CHECK (stage IN ('identified', 'in_conversation', 'proposal', 'negotiation', 'won', 'lost')), value DECIMAL(12, 2), expected_close_date DATE, notes TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE INDEX IF NOT EXISTS idx_contacts_last_contacted ON professional_contacts(last_contacted); CREATE INDEX IF NOT EXISTS idx_contacts_follow_up ON professional_contacts(follow_up_date) WHERE follow_up_date IS NOT NULL; CREATE INDEX IF NOT EXISTS idx_interactions_contact ON contact_interactions(contact_id, occurred_at DESC); CREATE INDEX IF NOT EXISTS idx_opportunities_stage ON opportunities(stage); DROP TRIGGER IF EXISTS update_professional_contacts_updated_at ON professional_contacts; CREATE TRIGGER update_professional_contacts_updated_at BEFORE UPDATE ON professional_contacts FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); DROP TRIGGER IF EXISTS update_opportunities_updated_at ON opportunities; CREATE TRIGGER update_opportunities_updated_at BEFORE UPDATE ON opportunities FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); CREATE OR REPLACE FUNCTION update_last_contacted() RETURNS TRIGGER AS $$ BEGIN UPDATE professional_contacts SET last_contacted = NEW.occurred_at WHERE id = NEW.contact_id; RETURN NEW; END; $$ LANGUAGE plpgsql; DROP TRIGGER IF EXISTS update_contact_last_contacted ON contact_interactions; CREATE TRIGGER update_contact_last_contacted AFTER INSERT ON contact_interactions FOR EACH ROW EXECUTE FUNCTION update_last_contacted();