-- ============================================================ -- Migration 006: Referral System Tables -- All tables in public schema (cross-tenant, like billing) -- ============================================================ -- 1. Referral codes — one per tenant, auto-generated on registration CREATE TABLE IF NOT EXISTS public.referral_codes ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id VARCHAR(100) NOT NULL UNIQUE, user_id VARCHAR(100) NOT NULL, code VARCHAR(20) NOT NULL UNIQUE, click_count INT NOT NULL DEFAULT 0, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE INDEX IF NOT EXISTS idx_referral_codes_code ON public.referral_codes (code); CREATE INDEX IF NOT EXISTS idx_referral_codes_tenant ON public.referral_codes (tenant_id); -- 2. Referral relationships — tracks who referred whom (tenant level) CREATE TABLE IF NOT EXISTS public.referral_relationships ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), referrer_tenant_id VARCHAR(100) NOT NULL, referred_tenant_id VARCHAR(100) NOT NULL UNIQUE, -- one referrer per tenant referral_code VARCHAR(20) NOT NULL, level INT NOT NULL DEFAULT 1, -- 1=direct, 2=indirect status VARCHAR(20) NOT NULL DEFAULT 'PENDING', registered_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), activated_at TIMESTAMPTZ, rewarded_at TIMESTAMPTZ ); CREATE INDEX IF NOT EXISTS idx_referral_rel_referrer ON public.referral_relationships (referrer_tenant_id); CREATE INDEX IF NOT EXISTS idx_referral_rel_status ON public.referral_relationships (status); CREATE INDEX IF NOT EXISTS idx_referral_rel_referred ON public.referral_relationships (referred_tenant_id); -- 3. Referral rewards — credit records for each tenant CREATE TABLE IF NOT EXISTS public.referral_rewards ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), beneficiary_tenant_id VARCHAR(100) NOT NULL, referral_relationship_id UUID NOT NULL REFERENCES public.referral_relationships(id), reward_type VARCHAR(20) NOT NULL, -- CREDIT | PERCENTAGE trigger_type VARCHAR(20) NOT NULL, -- FIRST_PAYMENT | RECURRING amount_cents INT NOT NULL, status VARCHAR(20) NOT NULL DEFAULT 'PENDING', invoice_id VARCHAR(100), source_invoice_id VARCHAR(100), recurring_month INT, expires_at TIMESTAMPTZ, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), applied_at TIMESTAMPTZ ); CREATE INDEX IF NOT EXISTS idx_referral_rewards_beneficiary ON public.referral_rewards (beneficiary_tenant_id, status); CREATE INDEX IF NOT EXISTS idx_referral_rewards_relationship ON public.referral_rewards (referral_relationship_id); -- 4. Referral stats — denormalized cache per tenant CREATE TABLE IF NOT EXISTS public.referral_stats ( tenant_id VARCHAR(100) PRIMARY KEY, direct_count INT NOT NULL DEFAULT 0, active_count INT NOT NULL DEFAULT 0, total_credit_earned INT NOT NULL DEFAULT 0, total_credit_applied INT NOT NULL DEFAULT 0, pending_credit INT NOT NULL DEFAULT 0, updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- 5. Processed events — idempotency for Redis Stream consumers CREATE TABLE IF NOT EXISTS public.referral_processed_events ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), event_id VARCHAR(255) NOT NULL UNIQUE, event_type VARCHAR(100) NOT NULL, processed_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE INDEX IF NOT EXISTS idx_referral_processed_events_event_id ON public.referral_processed_events (event_id);