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:
@@ -1,6 +1,7 @@
|
||||
'use server';
|
||||
|
||||
import { trackApiUsage, checkDailyLimit } from './track-api-usage';
|
||||
import { checkCreditBalance, deductCredits } from './credit-service';
|
||||
import { createServerComponentClient } from '@supabase/auth-helpers-nextjs';
|
||||
import { cookies } from 'next/headers';
|
||||
|
||||
@@ -49,6 +50,16 @@ export async function discoverWhiskybaseId(bottle: {
|
||||
};
|
||||
}
|
||||
|
||||
// Check credit balance before making API call
|
||||
const creditCheck = await checkCreditBalance(user.id, 'google_search');
|
||||
if (!creditCheck.allowed) {
|
||||
return {
|
||||
success: false,
|
||||
error: `Nicht genügend Credits. Du benötigst ${creditCheck.cost} Credits, hast aber nur ${creditCheck.balance}.`,
|
||||
insufficientCredits: true
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
// Construct targeted search query
|
||||
const queryParts = [
|
||||
@@ -90,6 +101,13 @@ export async function discoverWhiskybaseId(bottle: {
|
||||
success: true
|
||||
});
|
||||
|
||||
// Deduct credits after successful API call
|
||||
const creditDeduction = await deductCredits(user.id, 'google_search', 'Whiskybase search');
|
||||
if (!creditDeduction.success) {
|
||||
console.error('Failed to deduct credits:', creditDeduction.error);
|
||||
// Don't fail the search if credit deduction fails
|
||||
}
|
||||
|
||||
if (!data.items || data.items.length === 0) {
|
||||
return {
|
||||
success: false,
|
||||
|
||||
Reference in New Issue
Block a user