// acceptancePatternsCore.ts — S-P3-1: split da acceptancePatterns.ts // Sezioni: Auth / Login, CRUD, Dashboard, API / Backend, Database, // Pagamenti, SaaS / Multi-tenant, Test suite, Package.json / deps import type { AcceptanceTest } from './acceptanceTypes'; // anti-ciclo: tipo estratto da goalTestDeriver export interface GoalPattern { re: RegExp; tests: Array>; } export const CORE_PATTERNS: GoalPattern[] = [ // ── Auth / Login / Registration ───────────────────────────────────────────── { re: /login|signin|sign.?in|sign.?up|signup|registr(?:az|ation|ati)?|autenticaz|authentication|auth(?:orization|entication)?|logout|sessione?|password|jwt|bearer|token.?auth|oauth|2fa|mfa|otp/i, tests: [ { requirement: "File di autenticazione presente", critical: true, checkFn: ` const authFiles = files.filter(f => /auth|login|signin|session/i.test(f.path) && f.content ); return { pass: authFiles.length > 0, detail: authFiles.length > 0 ? "Trovato: " + authFiles.map(f=>f.path).join(", ") : "Mancano file auth/login nel VFS" }; `, }, { requirement: "Form di login con input email/password", critical: false, checkFn: ` const loginFile = files.find(f => /login|signin/i.test(f.path) && /email|password|input/i.test(f.content||"") ); return { pass: !!loginFile, detail: loginFile ? loginFile.path : "Nessun form login con email+password trovato" }; `, }, ], }, // ── CRUD (crud|crm|list|crea|create|gestione) ─────────────────────────────── { re: /\bcrud\b|(?:crea|aggiungi|add).{0,50}(?:modifica|edit|update).{0,50}(?:elimina|delete|rimuovi)|(?:insert|update|delete).{0,30}(?:insert|update|delete)|gestione.{0,40}(?:utenti|prodotti|ordini|clienti|record|entit)|lista.*(?:crea|aggiungi|modifica|elimina)|tabella.*modificabil/i, tests: [ { requirement: "Operazioni CRUD presenti nel codice", critical: true, checkFn: ` const crudOps = { create: false, read: false, update: false, delete: false }; for (const f of files) { const c = (f.content||"").toLowerCase(); if (/insert|create|post.*body|supabase.*insert|\.add\(/i.test(c)) crudOps.create = true; if (/select|find|get.*list|fetch.*all|supabase.*select/i.test(c)) crudOps.read = true; if (/update|patch|put.*body|supabase.*update|\.set\(/i.test(c)) crudOps.update = true; if (/delete|remove|supabase.*delete|\.destroy\(/i.test(c)) crudOps.delete = true; } const missing = Object.entries(crudOps).filter(([,v])=>!v).map(([k])=>k); return { pass: missing.length === 0, detail: missing.length === 0 ? "C/R/U/D tutte presenti" : "Mancano operazioni: " + missing.join(", ") }; `, }, ], }, // ── Dashboard ─────────────────────────────────────────────────────────────── { re: /dashboard|pannello|statistiche|analytics|chart|grafico|kpi/i, tests: [ { requirement: "Componente dashboard / statistiche presente", critical: true, checkFn: ` const dash = files.find(f => /dashboard|stats|analytics/i.test(f.path) && f.content ); return { pass: !!dash, detail: dash ? dash.path : "Manca file dashboard/stats nel VFS" }; `, }, { requirement: "Dati / metriche visualizzati (chart o tabella)", critical: false, checkFn: ` const hasChart = files.some(f => /recharts|chart\.js|apex|d3|nivo|canvas| /route|endpoint|controller|api\//i.test(f.path) && /(app\.(get|post|put|delete|patch)|router\.|@app\.|@router\.)/i.test(f.content||"") ); return { pass: !!route, detail: route ? route.path : "Nessun route/endpoint trovato" }; `, }, { requirement: "Almeno 1 endpoint GET e 1 POST", critical: false, checkFn: ` const allCode = files.map(f=>f.content||"").join("\\n"); const hasGet = /(app|router)\.(get|route)\(|@app\.get|@router\.get/i.test(allCode); const hasPost = /(app|router)\.(post|route)\(|@app\.post|@router\.post/i.test(allCode); return { pass: hasGet && hasPost, detail: (!hasGet ? "Manca GET " : "") + (!hasPost ? "Manca POST" : "GET e POST presenti") }; `, }, ], }, // ── Database ──────────────────────────────────────────────────────────────── { re: /database|supabase|postgresql|postgres|mysql|mongodb|sqlite|prisma|drizzle/i, tests: [ { requirement: "Schema / modello dati presente", critical: true, checkFn: ` const schema = files.find(f => /schema|model|migration|\.sql$|prisma/i.test(f.path) && f.content ); const hasTableDef = files.some(f => /create table|defineTable|pgTable|model.*{|Schema\(/i.test(f.content||"") ); return { pass: !!(schema || hasTableDef), detail: schema ? schema.path : (hasTableDef ? "Schema trovato in codice" : "Manca schema/modello dati") }; `, }, ], }, // ── Pagamenti ─────────────────────────────────────────────────────────────── { re: /pagamento|stripe|payment|checkout|abbonamento|subscription/i, tests: [ { requirement: "Integrazione pagamenti (Stripe / checkout)", critical: true, checkFn: ` const payment = files.find(f => /stripe|payment|checkout/i.test(f.content||"") ); return { pass: !!payment, detail: payment ? payment.path : "Nessuna integrazione pagamenti trovata" }; `, }, ], }, // ── SaaS / Multi-tenant ───────────────────────────────────────────────────── { re: /saas|multi.?tenant|organization|workspace|team/i, tests: [ { requirement: "Isolamento tenant (organization_id / workspace_id)", critical: true, checkFn: ` const allCode = files.map(f=>f.content||"").join("\\n"); const hasTenant = /organization_id|tenant_id|workspace_id|org_id|team_id/i.test(allCode); return { pass: hasTenant, detail: hasTenant ? "Tenant isolation trovata" : "Manca organization_id/tenant_id nei modelli" }; `, }, ], }, // ── Test suite ────────────────────────────────────────────────────────────── { re: /test.*suite|unit test|integration test|vitest|jest|pytest/i, tests: [ { requirement: "File di test presenti", critical: true, checkFn: ` const tests = files.filter(f => /\\.test\\.|spec\\.|__tests__/i.test(f.path)); return { pass: tests.length > 0, detail: tests.length > 0 ? tests.length + " file di test: " + tests.slice(0,3).map(f=>f.path).join(", ") : "Nessun file .test.ts / spec.ts trovato" }; `, }, ], }, // ── Package.json / deps ───────────────────────────────────────────────────── { re: /\bapp\b|\bsito\b|progetto|project|applicazione/i, tests: [ { requirement: "package.json o requirements.txt presente", critical: false, checkFn: ` const pkg = files.find(f => f.path === "package.json" || f.path === "/package.json" || f.path === "requirements.txt"); return { pass: !!pkg, detail: pkg ? pkg.path + " trovato" : "Manca package.json / requirements.txt" }; `, }, ], }, ];