edtech / apps /api /src /scripts /audit-inventory.ts
CognxSafeTrack
feat: Genspark-Standard upgrade, MLOps audit fixes, and XAMLÉ branding
eac938a
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
async function runAudit() {
console.log("🔍 Démarrage de l'audit d'inventaire XAMLÉ V1...");
console.log("=================================================");
const tracks = await prisma.track.findMany({
include: {
days: {
orderBy: { dayNumber: 'asc' }
}
}
});
const report: {
secteur: string;
lang: string;
day: number;
errors: string[]
}[] = [];
// Group tracks by "Secteur" intuitively from title or id (e.g. T1-FR -> T1 is not a sector maybe?)
// Actually the user mentioned "Couture", "Restauration", so these might be in track titles!
for (const track of tracks) {
// Find language
const lang = track.language || (track.id.endsWith('-WO') ? 'WOLOF' : 'FR');
for (const day of track.days) {
const errors: string[] = [];
// 1. Audio check
if (lang === 'WOLOF' && !day.audioUrl) {
errors.push("🎵 Audio manquant (Obligatoire en Wolof)");
}
// 2. Visual check
if (!day.imageUrl && !day.videoUrl) {
errors.push("🖼️ Visuel manquant (Image ou Vidéo absente)");
}
// 3. Multilingual JSON Validation
// Let's check buttonsJson or criteria to see if it's explicitly malformed
if (day.buttonsJson) {
try {
// const parsed = typeof day.buttonsJson === 'string' ? JSON.parse(day.buttonsJson) : day.buttonsJson;
// If parsed is not fine, it will throw
} catch (e) {
errors.push("⚠️ JSON Multilingue Invalide (buttonsJson corrompu)");
}
}
// 4. Pitch Deck Validation on Day 12
if (day.dayNumber === 12) {
let hasPitchTrigger = false;
// Check if badges include PITCH_DECK or exerciseType is FINAL, or buttonsJson has specific trigger
if (day.badges && JSON.stringify(day.badges).includes("PITCH_DECK")) hasPitchTrigger = true;
if (day.badges && JSON.stringify(day.badges).includes("PITCH_AI")) hasPitchTrigger = true;
if (day.badges && JSON.stringify(day.badges).includes("DOCUMENT")) hasPitchTrigger = true;
if (JSON.stringify(day.buttonsJson || "").includes("DOCUMENT_GENERATION")) hasPitchTrigger = true;
if (!hasPitchTrigger) {
// Let's record metadata found to help debug
errors.push(`📝 Métadonnées Pitch Deck (fin de parcours) absentes (Badges: ${JSON.stringify(day.badges)})`);
}
}
if (errors.length > 0) {
report.push({
secteur: track.title,
lang,
day: day.dayNumber,
errors
});
}
}
}
console.log(`\n📋 RÉSULTAT DU SCAN : ${report.length} problèmes trouvés.\n`);
// Print Table format
for (const item of report) {
console.log(`[${item.lang}] ${item.secteur} - Jour ${item.day} :`);
item.errors.forEach(err => console.log(` ❌ ${err}`));
console.log("-".repeat(40));
}
if (report.length === 0) {
console.log("✅ Audit parfait ! Tous les parcours sont complets et prêts pour la V1.");
}
await prisma.$disconnect();
}
runAudit().catch(e => {
console.error(e);
process.exit(1);
});