feat(credits): solde IA unique (option M), packs Stripe et polish billing

Un pot de crédits global (BASIC 100 / PRO 1 000 / BUSINESS 4 000) remplace
les seaux par fonction côté débit. Packs one-shot S/M/L, admin sans seaux
legacy, usage multi-features, hints de coût, anti-flash thème et hydratation
admin. Inclut aussi le pipeline slides renforcé et la page publique polishée.
This commit is contained in:
Antigravity
2026-07-16 20:43:18 +00:00
parent 704fed1191
commit 556a0b2f3f
77 changed files with 35745 additions and 10430 deletions

View File

@@ -1,27 +1,48 @@
import { NextResponse } from 'next/server';
import { auth } from '@/auth';
import { getUserQuotas, getEffectiveTier } from '@/lib/entitlements';
import { NextResponse } from 'next/server'
import { auth } from '@/auth'
import { getCreditUsageSummary, getQuotasCompatFromCredits } from '@/lib/credits'
export const dynamic = 'force-dynamic';
export const dynamic = 'force-dynamic'
export async function GET() {
const session = await auth();
const session = await auth()
if (!session?.user?.id) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}
try {
const [quotas, tier] = await Promise.all([
getUserQuotas(session.user.id),
getEffectiveTier(session.user.id),
]);
return NextResponse.json({ quotas, tier });
const summary = await getCreditUsageSummary(session.user.id)
// Compat anciens clients : quotas dérivés des crédits
const quotas = await getQuotasCompatFromCredits(session.user.id)
return NextResponse.json({
tier: summary.tier,
period: summary.period,
balance: {
totalRemaining: summary.balance.unlimited
? null
: summary.balance.totalRemaining,
subscriptionRemaining: summary.balance.unlimited
? null
: summary.balance.subscriptionRemaining,
purchasedRemaining: summary.balance.purchasedRemaining,
subscriptionGranted: summary.balance.unlimited
? null
: summary.balance.subscriptionGranted,
subscriptionSpent: summary.balance.subscriptionSpent,
spentThisPeriod: summary.balance.spentThisPeriod,
unlimited: summary.balance.unlimited,
},
breakdown: summary.breakdown,
// legacy
quotas,
})
} catch (error) {
console.error('[usage/current] Failed to fetch quotas:', error);
console.error('[usage/current] Failed to fetch usage data:', error)
return NextResponse.json(
{ error: 'Failed to fetch usage data' },
{ status: 503 },
);
)
}
}