feat: implement comprehensive credits management system

- Database schema:
  * Extended user_credits table with daily_limit, API costs, last_reset_at
  * Created credit_transactions table for full audit trail
  * Added RLS policies for secure access control

- Core services:
  * credit-service.ts - balance checking, deduction, addition, transaction history
  * admin-credit-service.ts - admin controls for managing users and credits

- API integration:
  * Integrated credit checking into discover-whiskybase.ts
  * Credits deducted after successful API calls
  * Insufficient credits error handling

- Admin interface:
  * /admin/users page with user management
  * Statistics dashboard (total users, credits in circulation, usage)
  * Interactive user table with search
  * Edit modal for credit adjustment and settings
  * Per-user daily limits and API cost configuration

- Features:
  * Automatic credit initialization (100 credits for new users)
  * Credit transaction logging with balance_after tracking
  * Admin can add/remove credits with reason
  * Admin can set custom daily limits per user
  * Admin can set custom API costs per user
  * Low credit warnings (< 10 credits)
  * Full transaction history

- User experience:
  * Credits checked before API calls
  * Clear error messages for insufficient credits
  * Graceful handling of credit deduction failures

System is ready for future enhancements like credit packages,
auto-recharge, and payment integration.
This commit is contained in:
2025-12-18 15:02:32 +01:00
parent e960d1bace
commit 95a8b3940b
7 changed files with 1013 additions and 6 deletions

View File

@@ -290,3 +290,59 @@ CREATE POLICY "Users can view their own admin record" ON admin_users FOR SELECT
-- Note: To add robin as admin, run this after getting the user_id:
-- INSERT INTO admin_users (user_id, role) VALUES ('<robin_user_id>', 'super_admin');
-- ============================================
-- Credits Management System
-- ============================================
-- Extend user_credits table with additional fields
ALTER TABLE user_credits
ADD COLUMN IF NOT EXISTS daily_limit INTEGER DEFAULT NULL,
ADD COLUMN IF NOT EXISTS google_search_cost INTEGER DEFAULT 1,
ADD COLUMN IF NOT EXISTS gemini_ai_cost INTEGER DEFAULT 1,
ADD COLUMN IF NOT EXISTS last_reset_at TIMESTAMP WITH TIME ZONE DEFAULT timezone('Europe/Berlin'::text, now());
-- Credit transactions table
CREATE TABLE IF NOT EXISTS credit_transactions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE,
amount INTEGER NOT NULL,
type TEXT NOT NULL CHECK (type IN ('deduction', 'addition', 'admin_adjustment')),
reason TEXT,
api_type TEXT CHECK (api_type IN ('google_search', 'gemini_ai')),
admin_id UUID REFERENCES auth.users(id),
balance_after INTEGER,
created_at TIMESTAMP WITH TIME ZONE DEFAULT timezone('Europe/Berlin'::text, now())
);
CREATE INDEX idx_credit_transactions_user_id ON credit_transactions(user_id);
CREATE INDEX idx_credit_transactions_created_at ON credit_transactions(created_at);
CREATE INDEX idx_credit_transactions_type ON credit_transactions(type);
-- Enable RLS for credit_transactions
ALTER TABLE credit_transactions ENABLE ROW LEVEL SECURITY;
-- Policies for credit_transactions
CREATE POLICY "Users can view their own transactions" ON credit_transactions
FOR SELECT USING (auth.uid() = user_id);
CREATE POLICY "Admins can view all transactions" ON credit_transactions
FOR SELECT USING (
auth.uid() IN (SELECT user_id FROM admin_users)
);
CREATE POLICY "System can insert transactions" ON credit_transactions
FOR INSERT WITH CHECK (true);
-- Update user_credits policies to allow admin updates
CREATE POLICY "Admins can update credits" ON user_credits
FOR UPDATE USING (
auth.uid() IN (SELECT user_id FROM admin_users)
);
-- Initialize credits for existing users (run manually if needed)
-- INSERT INTO user_credits (user_id, balance)
-- SELECT id, 100
-- FROM auth.users
-- ON CONFLICT (user_id) DO UPDATE SET balance = EXCLUDED.balance
-- WHERE user_credits.balance = 0;