Credits
The credits module (src/modules/credits/service.ts) provides grant, consume, revoke, getBalance, and getHistory.
How Credits Are Granted
| Scene | Trigger | Configuration |
|---|---|---|
| Signup | Auto-grant after registration | Admin Settings: initial_credits_enabled, initial_credits_amount, initial_credits_valid_days (0 = never expires), initial_credits_description |
| Payment | Order becomes PAID | credits + creditsValidDays on the product in src/config/pricing.ts; subscriptions expire at period end |
| Manual | Admin panel → Credits | Grant with scene GIFT / REWARD |
Consumption (FIFO)
- Earliest-expiring credits are consumed first (
expiresAtascending, never-expiring last) - Consumption is batched (up to 1000 credits per batch) and checks the available balance first
- Only valid credits count toward the balance: active, not expired, not deleted
import { consume } from '@/modules/credits/service';
const result = await consume({
userId,
credits: 10,
scene: 'ai_generation',
description: 'Generate image',
});
// result.success === false when the balance is insufficientClient-side consumption goes through POST /api/credits with { credits, scene, description }.
Expiration
- Each grant carries an optional
expiresAt(null= never expires) - One-time purchases:
now + creditsValidDays - Subscriptions: expires at
currentPeriodEnd— renewal grants a fresh batch
Records
Every grant/consume is a row in the credit table with the transaction type, scene, remainingCredits and expiresAt — so balances and history are fully auditable in the admin panel.