fix(audit): nettoyage accès, garde-fous build, unification quotas
All checks were successful
CI / Lint, Unit Tests & Build (push) Successful in 7m59s
CI / Deploy production (on server) (push) Successful in 24s

Semaine 1 — fuites et accès :
- /archive rendu accessible via sidebar (était invisible)
- Suppression pages orphelines : /chat, /graph, /support, test-title-suggestions
- Fixes i18n : search-modal (clé non interpolée), sidebar tooltips, export PDF
- 15 locales mises à jour

Semaine 2 — garde-fous :
- 8 erreurs TS fixees → ignoreBuildErrors: false (build type-safe)
- reactStrictMode: true (dev-only, zero impact prod)
- reserveUsageOrThrow → wrapper deprecie vers reserveAiUsageOrThrow
- auth-guard.ts : requireAuthOrResponse() + requireAdminOrResponse()

Tests 212/212 | Lint 0 erreur | Build OK | tsc 0 erreur
This commit is contained in:
Antigravity
2026-07-17 18:47:44 +00:00
parent e8ee53c815
commit 88a7d2ad0a
42 changed files with 216 additions and 2081 deletions

View File

@@ -7,6 +7,7 @@ import {
parseRedisInt,
isValidFeature,
VALID_FEATURES,
type FeatureName,
} from './quota-utils';
import {
getLimitAsync,
@@ -261,6 +262,11 @@ export async function getEffectiveTier(
return 'BASIC';
}
// NOTE: canUseFeature reads the old per-feature Redis counters + UsageLog table.
// Since reserveUsageOrThrow now delegates to the unified credits engine (AiCreditAccount),
// these counters are no longer written to — this function returns stale/zero usage data.
// Only caller: checkEntitlementOrThrow → app/api/ai/tags/route.ts (pre-check that always passes).
// Actual enforcement happens via reserveAiUsageOrThrow at the debit site.
export async function canUseFeature(
userId: string,
feature: string,
@@ -365,10 +371,10 @@ function featureToAiLane(feature: string): 'chat' | 'tags' | 'embedding' {
}
/**
* Réserve des crédits globaux (modèle A).
* @deprecated Use `reserveAiUsageOrThrow` from `@/lib/ai-quota` instead.
* Thin wrapper kept for backward compat — delegates to the unified credits engine.
* `amount` = coût en crédits (ex. slides multi-étapes : 1+N).
* Si l'utilisateur a une clé perso (BYOK) pour la voie concernée, aucun débit.
* Conserve le nom historique pour ne pas casser tous les appelants.
*/
export async function reserveUsageOrThrow(
userId: string,
@@ -378,17 +384,8 @@ export async function reserveUsageOrThrow(
if (!isValidFeature(feature)) {
throw new QuotaExceededError('PRO', feature, 0, 0, false, { currentTier: 'BASIC' });
}
const { getSystemConfig } = await import('@/lib/config');
const { willUseByokForLane } = await import('@/lib/ai/provider-for-user');
const config = await getSystemConfig();
const lane = featureToAiLane(feature);
const { usedByok } = await willUseByokForLane(lane, config, userId);
if (usedByok) return;
const { reserveCreditsOrThrow, resolveCreditCost } = await import('@/lib/credits');
const cost = resolveCreditCost(feature, { amount });
await reserveCreditsOrThrow(userId, cost, { feature });
const { reserveAiUsageOrThrow } = await import('@/lib/ai-quota');
await reserveAiUsageOrThrow(userId, feature as FeatureName, { amount });
}
/** Units charged for one multi-step slide generation (outline + per-slide expand). */