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

@@ -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,