-- +goose Up -- Sales contact leads + admin-prepared payment quotes (custom/Enterprise deals). CREATE TABLE sales_leads ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name TEXT NOT NULL, email TEXT NOT NULL, company_name TEXT, phone TEXT, message TEXT NOT NULL, estimated_skus INT, source TEXT NOT NULL DEFAULT 'pricing' CHECK (char_length(source) BETWEEN 1 AND 64), status TEXT NOT NULL DEFAULT 'new' CHECK (status IN ('new', 'contacted', 'quoted', 'won', 'closed')), company_id UUID REFERENCES companies(id) ON DELETE SET NULL, user_id UUID REFERENCES users(id) ON DELETE SET NULL, admin_notes TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), CONSTRAINT sales_leads_name_len CHECK (char_length(btrim(name)) BETWEEN 1 AND 200), CONSTRAINT sales_leads_email_len CHECK (char_length(btrim(email)) BETWEEN 3 AND 320), CONSTRAINT sales_leads_message_len CHECK (char_length(btrim(message)) BETWEEN 1 AND 10000), CONSTRAINT sales_leads_company_name_len CHECK (company_name IS NULL OR char_length(company_name) <= 200), CONSTRAINT sales_leads_phone_len CHECK (phone IS NULL OR char_length(phone) <= 40), CONSTRAINT sales_leads_admin_notes_len CHECK (admin_notes IS NULL OR char_length(admin_notes) <= 10000), CONSTRAINT sales_leads_estimated_skus_chk CHECK (estimated_skus IS NULL OR estimated_skus >= 0) ); CREATE INDEX sales_leads_status_created_idx ON sales_leads (status, created_at DESC); CREATE INDEX sales_leads_email_idx ON sales_leads (lower(email), created_at DESC); CREATE INDEX sales_leads_company_idx ON sales_leads (company_id) WHERE company_id IS NOT NULL; CREATE TABLE sales_quotes ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), lead_id UUID NOT NULL REFERENCES sales_leads(id) ON DELETE CASCADE, company_id UUID NOT NULL REFERENCES companies(id) ON DELETE CASCADE, plan_id BIGINT REFERENCES plans(id) ON DELETE SET NULL, plan_name TEXT NOT NULL, monthly_credits INT NOT NULL DEFAULT 0, max_products INT, currency TEXT NOT NULL DEFAULT 'usd', total_amount_cents INT NOT NULL, installment_count INT NOT NULL DEFAULT 1, installment_interval TEXT NOT NULL DEFAULT 'month' CHECK (installment_interval IN ('month', 'quarter', 'year')), installment_amount_cents INT NOT NULL, term_months INT, stripe_product_id TEXT, stripe_price_id TEXT, stripe_checkout_session_id TEXT, checkout_url TEXT, status TEXT NOT NULL DEFAULT 'draft' CHECK (status IN ('draft', 'ready', 'sent', 'paid', 'canceled')), created_by_user_id UUID REFERENCES users(id) ON DELETE SET NULL, paid_at TIMESTAMPTZ, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), CONSTRAINT sales_quotes_plan_name_len CHECK (char_length(btrim(plan_name)) BETWEEN 1 AND 120), CONSTRAINT sales_quotes_currency_len CHECK (char_length(currency) BETWEEN 3 AND 10), CONSTRAINT sales_quotes_total_chk CHECK (total_amount_cents > 0), CONSTRAINT sales_quotes_installment_count_chk CHECK (installment_count BETWEEN 1 AND 60), CONSTRAINT sales_quotes_installment_amount_chk CHECK (installment_amount_cents > 0), CONSTRAINT sales_quotes_monthly_credits_chk CHECK (monthly_credits >= 0), CONSTRAINT sales_quotes_max_products_chk CHECK (max_products IS NULL OR max_products >= 0), CONSTRAINT sales_quotes_term_months_chk CHECK (term_months IS NULL OR term_months BETWEEN 1 AND 120) ); CREATE INDEX sales_quotes_lead_idx ON sales_quotes (lead_id, created_at DESC); CREATE INDEX sales_quotes_company_status_idx ON sales_quotes (company_id, status, created_at DESC); CREATE INDEX sales_quotes_status_idx ON sales_quotes (status, created_at DESC); -- +goose Down DROP TABLE IF EXISTS sales_quotes; DROP TABLE IF EXISTS sales_leads;