eny.space Landingpage
at develop 65 lines 2.6 kB view raw
1-- Create subscriptions table to track user subscriptions 2CREATE TABLE IF NOT EXISTS subscriptions ( 3 id UUID PRIMARY KEY DEFAULT gen_random_uuid(), 4 user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE, 5 stripe_customer_id TEXT, 6 stripe_subscription_id TEXT UNIQUE, 7 stripe_price_id TEXT, 8 status TEXT NOT NULL, 9 current_period_start TIMESTAMPTZ, 10 current_period_end TIMESTAMPTZ, 11 cancel_at_period_end BOOLEAN DEFAULT false, 12 created_at TIMESTAMPTZ DEFAULT NOW(), 13 updated_at TIMESTAMPTZ DEFAULT NOW() 14); 15 16-- Create index for faster lookups 17CREATE INDEX IF NOT EXISTS subscriptions_user_id_idx ON subscriptions(user_id); 18CREATE INDEX IF NOT EXISTS subscriptions_stripe_customer_id_idx ON subscriptions(stripe_customer_id); 19CREATE INDEX IF NOT EXISTS subscriptions_stripe_subscription_id_idx ON subscriptions(stripe_subscription_id); 20 21-- Enable Row Level Security 22ALTER TABLE subscriptions ENABLE ROW LEVEL SECURITY; 23 24-- Policy: Users can only see their own subscriptions 25DROP POLICY IF EXISTS "Users can view own subscriptions" ON subscriptions; 26CREATE POLICY "Users can view own subscriptions" 27 ON subscriptions 28 FOR SELECT 29 USING (auth.uid() = user_id); 30 31-- Policy: Users can insert their own subscription records (for initial customer creation) 32-- But they can ONLY insert records with status='incomplete' to prevent fraud 33DROP POLICY IF EXISTS "Users can insert own subscriptions" ON subscriptions; 34CREATE POLICY "Users can insert own subscriptions" 35 ON subscriptions 36 FOR INSERT 37 WITH CHECK ( 38 auth.uid() = user_id 39 AND status = 'incomplete' 40 ); 41 42-- Users CANNOT update their own subscriptions directly 43-- All updates must come from webhooks (using service role) or validated server actions 44-- This prevents users from setting status='active' without paying 45DROP POLICY IF EXISTS "Users can update own subscriptions" ON subscriptions; 46 47-- Note: Service role (used by webhooks via admin client) bypasses RLS entirely 48-- The admin client uses SUPABASE_SERVICE_ROLE_KEY which automatically bypasses all RLS policies. 49-- No policy needed for service role since it bypasses RLS. 50 51-- Function to update updated_at timestamp 52CREATE OR REPLACE FUNCTION update_updated_at_column() 53RETURNS TRIGGER AS $$ 54BEGIN 55 NEW.updated_at = NOW(); 56 RETURN NEW; 57END; 58$$ language 'plpgsql'; 59 60-- Trigger to automatically update updated_at 61DROP TRIGGER IF EXISTS update_subscriptions_updated_at ON subscriptions; 62CREATE TRIGGER update_subscriptions_updated_at 63 BEFORE UPDATE ON subscriptions 64 FOR EACH ROW 65 EXECUTE FUNCTION update_updated_at_column();