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); });