feat: implement subscription plan system with monthly credits
- Database schema: * subscription_plans table - stores plan tiers (Starter, Bronze, Silver, Gold) * user_subscriptions table - assigns users to plans * Default plans created (10, 50, 100, 250 credits/month) * All existing users assigned to Starter plan - Subscription service (subscription-service.ts): * getAllPlans() - fetch all plans * getActivePlans() - fetch active plans for users * createPlan() - admin creates new plan * updatePlan() - admin edits plan * deletePlan() - admin removes plan * getUserSubscription() - get user's current plan * setUserPlan() - admin assigns user to plan * grantMonthlyCredits() - distribute credits to all users - Plan management interface (/admin/plans): * Visual plan cards with credits, price, description * Create/Edit/Delete plans * Toggle active/inactive status * Sort order management * Grant monthly credits button (manual trigger) - Features: * Monthly credit allocation based on plan * Prevents duplicate credit grants (tracks last_credit_grant_at) * Admin can manually trigger monthly credit distribution * Plans can be activated/deactivated * Custom pricing and credit amounts per plan - UI: * Beautiful plan cards with color coding * Modal for create/edit with validation * Success/error messages * Manage Plans button in admin dashboard Ready for future automation (cron job for monthly credits) and payment integration (Stripe/PayPal).
This commit is contained in:
@@ -346,3 +346,78 @@ FOR UPDATE USING (
|
||||
-- FROM auth.users
|
||||
-- ON CONFLICT (user_id) DO UPDATE SET balance = EXCLUDED.balance
|
||||
-- WHERE user_credits.balance = 0;
|
||||
|
||||
-- ============================================
|
||||
-- Subscription Plans System
|
||||
-- ============================================
|
||||
|
||||
-- Subscription plans table
|
||||
CREATE TABLE IF NOT EXISTS subscription_plans (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
display_name TEXT NOT NULL,
|
||||
monthly_credits INTEGER NOT NULL,
|
||||
price DECIMAL(10, 2) DEFAULT 0,
|
||||
description TEXT,
|
||||
is_active BOOLEAN DEFAULT true,
|
||||
sort_order INTEGER DEFAULT 0,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT timezone('Europe/Berlin'::text, now()),
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT timezone('Europe/Berlin'::text, now())
|
||||
);
|
||||
|
||||
CREATE INDEX idx_subscription_plans_active ON subscription_plans(is_active);
|
||||
CREATE INDEX idx_subscription_plans_sort_order ON subscription_plans(sort_order);
|
||||
|
||||
-- User subscriptions table
|
||||
CREATE TABLE IF NOT EXISTS user_subscriptions (
|
||||
user_id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE,
|
||||
plan_id UUID REFERENCES subscription_plans(id) ON DELETE SET NULL,
|
||||
started_at TIMESTAMP WITH TIME ZONE DEFAULT timezone('Europe/Berlin'::text, now()),
|
||||
last_credit_grant_at TIMESTAMP WITH TIME ZONE DEFAULT timezone('Europe/Berlin'::text, now()),
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT timezone('Europe/Berlin'::text, now())
|
||||
);
|
||||
|
||||
CREATE INDEX idx_user_subscriptions_plan_id ON user_subscriptions(plan_id);
|
||||
|
||||
-- Enable RLS
|
||||
ALTER TABLE subscription_plans ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE user_subscriptions ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- Policies for subscription_plans (everyone can view active plans)
|
||||
CREATE POLICY "Anyone can view active plans" ON subscription_plans
|
||||
FOR SELECT USING (is_active = true);
|
||||
|
||||
CREATE POLICY "Admins can manage plans" ON subscription_plans
|
||||
FOR ALL USING (
|
||||
auth.uid() IN (SELECT user_id FROM admin_users)
|
||||
);
|
||||
|
||||
-- Policies for user_subscriptions
|
||||
CREATE POLICY "Users can view their own subscription" ON user_subscriptions
|
||||
FOR SELECT USING (auth.uid() = user_id);
|
||||
|
||||
CREATE POLICY "Admins can view all subscriptions" ON user_subscriptions
|
||||
FOR SELECT USING (
|
||||
auth.uid() IN (SELECT user_id FROM admin_users)
|
||||
);
|
||||
|
||||
CREATE POLICY "Admins can manage subscriptions" ON user_subscriptions
|
||||
FOR ALL USING (
|
||||
auth.uid() IN (SELECT user_id FROM admin_users)
|
||||
);
|
||||
|
||||
-- Insert default plans
|
||||
INSERT INTO subscription_plans (name, display_name, monthly_credits, price, description, sort_order) VALUES
|
||||
('starter', 'Starter', 10, 0.00, 'Perfect for occasional use', 1),
|
||||
('bronze', 'Bronze', 50, 4.99, 'Great for regular users', 2),
|
||||
('silver', 'Silver', 100, 8.99, 'Best value for power users', 3),
|
||||
('gold', 'Gold', 250, 19.99, 'Unlimited searches for professionals', 4)
|
||||
ON CONFLICT (name) DO NOTHING;
|
||||
|
||||
-- Set all existing users to Starter plan
|
||||
INSERT INTO user_subscriptions (user_id, plan_id)
|
||||
SELECT
|
||||
u.id,
|
||||
(SELECT id FROM subscription_plans WHERE name = 'starter' LIMIT 1)
|
||||
FROM auth.users u
|
||||
ON CONFLICT (user_id) DO NOTHING;
|
||||
|
||||
Reference in New Issue
Block a user