['name'=>'Auth multi-user (SSO/SAML)', 'dev_days'=>5, 'critical'=>true], 'rbac' => ['name'=>'RBAC (roles/permissions)', 'dev_days'=>3, 'critical'=>true], 'billing' => ['name'=>'Billing Stripe (plans/quotas)', 'dev_days'=>4, 'critical'=>true], 'tenant_isolation' => ['name'=>'Multi-tenant DB isolation', 'dev_days'=>6, 'critical'=>true], 'rate_limit' => ['name'=>'Rate limiting per user', 'dev_days'=>2, 'critical'=>true], 'monitoring' => ['name'=>'Monitoring/alerts production', 'dev_days'=>2, 'critical'=>false], 'logs' => ['name'=>'Logs centralisés (audit trail)', 'dev_days'=>2, 'critical'=>false], 'backup' => ['name'=>'Backup + disaster recovery', 'dev_days'=>3, 'critical'=>true], 'docs_api' => ['name'=>'API docs (Swagger/OpenAPI)', 'dev_days'=>2, 'critical'=>false], 'docs_user' => ['name'=>'User docs + onboarding flow', 'dev_days'=>3, 'critical'=>true], 'i18n' => ['name'=>'i18n (EN/FR/AR)', 'dev_days'=>4, 'critical'=>false], 'gdpr' => ['name'=>'GDPR compliance (data export/delete)', 'dev_days'=>3, 'critical'=>true], 'email_tx' => ['name'=>'Emails transactionnels (welcome/reset/invoice)', 'dev_days'=>2, 'critical'=>true], 'support' => ['name'=>'Support system (helpdesk/chat)', 'dev_days'=>3, 'critical'=>false], 'mobile' => ['name'=>'Mobile responsive/PWA', 'dev_days'=>4, 'critical'=>false], 'tests' => ['name'=>'Tests E2E Playwright + coverage', 'dev_days'=>5, 'critical'=>true], 'perf' => ['name'=>'Performance (Lighthouse 90+)', 'dev_days'=>3, 'critical'=>false], 'security' => ['name'=>'Pentest + security audit', 'dev_days'=>4, 'critical'=>true], 'landing' => ['name'=>'Landing page + demo flow', 'dev_days'=>3, 'critical'=>true], 'pricing' => ['name'=>'Pricing page + ROI calculator', 'dev_days'=>2, 'critical'=>true], ]; } // Solutions catalog avec capability scan (what's done vs what's needed) function solutions_catalog() { return [ [ 'id'=>'ethica-hcp', 'rank'=>1, 'name'=>'Ethica HCP Database MENA', 'category'=>'Pharma Data', 'status'=>'PROD', 'maturity'=>95, 'effort'=>2, 'reward'=>9, 'mad_est'=>600000, 'days_to_prod'=>28, 'tam_mad'=>120000000, // 12M€ * 10 for MAD 'market_match_score'=>0, // computed 'capabilities_done' => ['auth','rbac','tenant_isolation','logs','gdpr','email_tx','docs_user','rate_limit','landing','pricing','backup','monitoring','docs_api','tests'], 'capabilities_todo' => ['billing','i18n','support','mobile','perf','security'], 'signals' => ['Pharma 11 leads MQL 80', '157K HCPs DB', 'Kaouther Najar SQL', 'MENA expansion'], 'target_segment'=>'Pharma', ], [ 'id'=>'weval-saas', 'rank'=>2, 'name'=>'WEVAL SaaS Freemium', 'category'=>'AI Platform', 'status'=>'BETA', 'maturity'=>70, 'effort'=>6, 'reward'=>9, 'mad_est'=>800000, 'days_to_prod'=>45, 'tam_mad'=>80000000, 'market_match_score'=>0, 'capabilities_done' => ['auth','logs','landing','docs_api','tests'], 'capabilities_todo' => ['rbac','tenant_isolation','billing','rate_limit','gdpr','email_tx','docs_user','i18n','support','mobile','perf','security','backup','pricing','monitoring'], 'signals' => ['Software MQL 95', 'Cloud MQL 90', 'Freemium viral'], 'target_segment'=>'Software', ], [ 'id'=>'wevads-brain', 'rank'=>3, 'name'=>'WEVADS Brain Outreach', 'category'=>'Email Engine', 'status'=>'PROD', 'maturity'=>92, 'effort'=>3, 'reward'=>8, 'mad_est'=>450000, 'days_to_prod'=>21, 'tam_mad'=>40000000, 'market_match_score'=>0, 'capabilities_done' => ['auth','rbac','tenant_isolation','monitoring','logs','rate_limit','backup','email_tx','security','tests'], 'capabilities_todo' => ['billing','docs_api','docs_user','i18n','support','mobile','landing','pricing','gdpr','perf'], 'signals' => ['PMTA+Kumo+Postfix triple', '9 winners SACRED', '95%+ delivery'], 'target_segment'=>'B2B outreach', ], [ 'id'=>'docuseal', 'rank'=>4, 'name'=>'DocuSeal E-signature MENA', 'category'=>'Legal Tech', 'status'=>'PROD', 'maturity'=>85, 'effort'=>2, 'reward'=>7, 'mad_est'=>250000, 'days_to_prod'=>14, 'tam_mad'=>35000000, 'market_match_score'=>0, 'capabilities_done' => ['auth','rbac','logs','gdpr','docs_user','docs_api','mobile','backup','tests'], 'capabilities_todo' => ['tenant_isolation','billing','rate_limit','i18n','support','email_tx','landing','pricing','perf','security','monitoring'], 'signals' => ['Banque 11 leads MQL 76', 'Retail 6 MQL 76', 'E-sign MENA gap'], 'target_segment'=>'Banque/Retail/Pharma', ], [ 'id'=>'dark-scout', 'rank'=>5, 'name'=>'Dark Scout Intel', 'category'=>'Competitive Intel', 'status'=>'PROD', 'maturity'=>75, 'effort'=>4, 'reward'=>7, 'mad_est'=>300000, 'days_to_prod'=>30, 'tam_mad'=>20000000, 'market_match_score'=>0, 'capabilities_done' => ['auth','logs','monitoring','docs_api','tests'], 'capabilities_todo' => ['rbac','tenant_isolation','billing','rate_limit','gdpr','email_tx','docs_user','i18n','support','mobile','landing','pricing','perf','security','backup'], 'signals' => ['Software MQL 95', '34 scans', 'Intel MENA gap'], 'target_segment'=>'Software/Consulting', ], [ 'id'=>'wevia-master', 'rank'=>6, 'name'=>'WEVIA Master Orchestrator', 'category'=>'AI Orchestration', 'status'=>'BETA', 'maturity'=>65, 'effort'=>5, 'reward'=>9, 'mad_est'=>700000, 'days_to_prod'=>60, 'tam_mad'=>150000000, 'market_match_score'=>0, 'capabilities_done' => ['auth','logs','docs_api','tests','monitoring'], 'capabilities_todo' => ['rbac','tenant_isolation','billing','rate_limit','gdpr','email_tx','docs_user','i18n','support','mobile','landing','pricing','perf','security','backup'], 'signals' => ['269 tools', '17 providers cascade', '0€ inference'], 'target_segment'=>'Enterprise AI', ], [ 'id'=>'blade-ai', 'rank'=>7, 'name'=>'Blade AI Web Agent', 'category'=>'Automation', 'status'=>'PROD', 'maturity'=>80, 'effort'=>3, 'reward'=>6, 'mad_est'=>200000, 'days_to_prod'=>21, 'tam_mad'=>15000000, 'market_match_score'=>0, 'capabilities_done' => ['auth','logs','monitoring','tests','docs_api','mobile'], 'capabilities_todo' => ['rbac','tenant_isolation','billing','rate_limit','gdpr','email_tx','docs_user','i18n','support','landing','pricing','perf','security','backup'], 'signals' => ['232 tasks automated', 'Selenium+Chrome', 'Cloud MQL 90'], 'target_segment'=>'Cloud/Software', ], [ 'id'=>'wepredict', 'rank'=>8, 'name'=>'WePredict AI Cockpits', 'category'=>'Predictive Analytics', 'status'=>'BETA', 'maturity'=>72, 'effort'=>4, 'reward'=>7, 'mad_est'=>350000, 'days_to_prod'=>35, 'tam_mad'=>30000000, 'market_match_score'=>0, 'capabilities_done' => ['auth','logs','monitoring','docs_api','tests'], 'capabilities_todo' => ['rbac','tenant_isolation','billing','rate_limit','gdpr','email_tx','docs_user','i18n','support','mobile','landing','pricing','perf','security','backup'], 'signals' => ['16 cockpits', '64 predictions', 'Deal close probability'], 'target_segment'=>'Software/Sales', ], [ 'id'=>'arena', 'rank'=>9, 'name'=>'WEVAL Arena Command Center', 'category'=>'Multi-LLM', 'status'=>'PROD', 'maturity'=>88, 'effort'=>3, 'reward'=>6, 'mad_est'=>180000, 'days_to_prod'=>14, 'tam_mad'=>10000000, 'market_match_score'=>0, 'capabilities_done' => ['auth','logs','monitoring','docs_api','tests','mobile','perf'], 'capabilities_todo' => ['rbac','tenant_isolation','billing','rate_limit','gdpr','email_tx','docs_user','i18n','support','landing','pricing','security','backup'], 'signals' => ['409 options', '715 agents', '17 providers'], 'target_segment'=>'Developers', ], [ 'id'=>'paperclip', 'rank'=>10, 'name'=>'Paperclip PM + CRM', 'category'=>'Project Mgmt', 'status'=>'BETA', 'maturity'=>60, 'effort'=>6, 'reward'=>5, 'mad_est'=>150000, 'days_to_prod'=>45, 'tam_mad'=>8000000, 'market_match_score'=>0, 'capabilities_done' => ['auth','logs','docs_api'], 'capabilities_todo' => ['rbac','tenant_isolation','billing','rate_limit','gdpr','email_tx','docs_user','i18n','support','mobile','landing','pricing','perf','security','backup','tests','monitoring'], 'signals' => ['48 leads tracked', 'Self-host'], 'target_segment'=>'SMB', ], ]; } // WePredict-style regression prediction: market_match_score // Formula: weighted market signals (industry MQL + lead count + SQL qualification rate) function predict_market_score($solution) { $pg = pg_c(); if (!$pg) return 50; // Map solution target to industries $target_map = [ 'Pharma' => ['Pharma'], 'Banque/Retail/Pharma' => ['Banque','Retail','Pharma'], 'Software' => ['Software','Cloud'], 'Software/Consulting' => ['Software','Cloud','Streaming'], 'Software/Sales' => ['Software','Cloud'], 'Cloud/Software' => ['Cloud','Software'], 'Enterprise AI' => ['Pharma','Banque','Software','Cloud','Retail'], 'Developers' => ['Software','Cloud'], 'SMB' => ['Retail','Telecom','Mining'], 'B2B outreach' => ['Banque','Retail','Pharma','Software','Telecom'], ]; $industries = $target_map[$solution['target_segment']] ?? ['Pharma','Banque']; $in_list = "'" . implode("','", array_map(function($i){return pg_escape_string($i);}, $industries)) . "'"; $sql = "SELECT COUNT(*) AS n, ROUND(AVG(mql_score)) AS avg_mql, SUM(CASE WHEN sql_qualified THEN 1 ELSE 0 END) AS sql_q, ROUND(SUM(CASE WHEN sql_qualified THEN 1 ELSE 0 END)::numeric / NULLIF(COUNT(*),0) * 100) AS sql_pct FROM weval_leads WHERE industry IN ($in_list)"; $r = @pg_query($pg, $sql); $stats = $r ? pg_fetch_assoc($r) : []; pg_close($pg); $leads = (int)($stats['n'] ?? 0); $avg_mql = (int)($stats['avg_mql'] ?? 70); $sql_q = (int)($stats['sql_q'] ?? 0); $sql_pct = (int)($stats['sql_pct'] ?? 0); // Predictive score: // - Lead density (normalized 0-100): leads/48 * 100 // - Avg MQL (0-100 already) // - SQL qualification rate (0-100) // - Maturity (product readiness, 0-100) $lead_density = min(100, ($leads / 48) * 100); $maturity = (int)$solution['maturity']; $score = round( $lead_density * 0.25 + $avg_mql * 0.30 + $sql_pct * 0.15 + $maturity * 0.30 ); return [ 'score' => $score, 'breakdown' => [ 'lead_density' => round($lead_density, 1), 'avg_mql' => $avg_mql, 'sql_pct' => $sql_pct, 'maturity' => $maturity, 'leads_in_target' => $leads, 'sql_qualified_in_target' => $sql_q, ], 'recommendation' => $score >= 75 ? 'LAUNCH NOW' : ($score >= 60 ? 'ACCELERATE' : ($score >= 45 ? 'NURTURE' : 'PIVOT')), ]; } // Dev effort estimation for multi-user production function dev_effort_to_production($solution) { $checklist = mup_checklist(); $todo = $solution['capabilities_todo'] ?? []; $total_days = 0; $critical_days = 0; $done_days = 0; $nice_days = 0; foreach ($todo as $cap) { if (!isset($checklist[$cap])) continue; $d = $checklist[$cap]['dev_days']; $total_days += $d; if ($checklist[$cap]['critical']) $critical_days += $d; else $nice_days += $d; } // Done $done = $solution['capabilities_done'] ?? []; foreach ($done as $cap) { if (isset($checklist[$cap])) $done_days += $checklist[$cap]['dev_days']; } // Dev cost estimate: 1 senior dev = 2500 MAD/day, 1 junior = 1200 MAD/day // Assume 1 senior + 1 junior in parallel = 3700 MAD/day but -30% parallel overhead $dev_cost_per_day = 3700 * 0.7; // 2590 MAD/day effective $dev_cost_mad = round($total_days * $dev_cost_per_day); // Parallelizable? Yes, roughly 60% of tasks can overlap $calendar_days = round($total_days * 0.65); return [ 'total_dev_days' => $total_days, 'critical_path_days' => $critical_days, 'nice_to_have_days' => $nice_days, 'calendar_days_est' => $calendar_days, 'dev_cost_mad' => $dev_cost_mad, 'breakeven_customers' => $solution['mad_est'] > 0 ? round($dev_cost_mad / $solution['mad_est'] * 10, 1) / 10 : null, 'completion_pct' => count($done) > 0 ? round(count($done) / (count($done) + count($todo)) * 100) : 0, ]; } // Main action routing $action = $_GET['action'] ?? 'full_analysis'; if ($action === 'full_analysis') { $solutions = solutions_catalog(); $checklist = mup_checklist(); foreach ($solutions as &$s) { $prediction = predict_market_score($s); $s['market_prediction'] = $prediction; $s['dev_effort'] = dev_effort_to_production($s); // Winning formula: combine market prediction + ICE + maturity $ice_raw = ($s['reward'] * ($s['mad_est'] / 10000)) / max(1, $s['effort']); $s['ice_score'] = round($ice_raw, 1); // FINAL WINNING SCORE: combines all predictors $s['winning_score'] = round( $prediction['score'] * 0.40 + min(100, $ice_raw / 3) * 0.25 + $s['maturity'] * 0.25 + (100 - min(100, $s['dev_effort']['calendar_days_est'])) * 0.10 ); // Decision: SHIP IT vs DEV vs PIVOT if ($s['winning_score'] >= 78) $s['decision'] = 'SHIP_IT'; elseif ($s['winning_score'] >= 68) $s['decision'] = 'ACCELERATE'; elseif ($s['winning_score'] >= 55) $s['decision'] = 'DEV_SPRINT'; elseif ($s['winning_score'] >= 40) $s['decision'] = 'NURTURE'; else $s['decision'] = 'PIVOT_OR_PARK'; } unset($s); // Sort by winning_score desc usort($solutions, function($a,$b){return $b['winning_score'] - $a['winning_score'];}); // Overall GAP analysis $all_missing = []; foreach ($solutions as $s) { foreach ($s['capabilities_todo'] as $cap) { $all_missing[$cap] = ($all_missing[$cap] ?? 0) + 1; } } arsort($all_missing); $top_gaps = []; foreach ($all_missing as $cap => $n) { if (isset($checklist[$cap])) { $top_gaps[] = [ 'capability' => $cap, 'name' => $checklist[$cap]['name'], 'dev_days' => $checklist[$cap]['dev_days'], 'critical' => $checklist[$cap]['critical'], 'missing_in_solutions' => $n, ]; } } echo json_encode([ 'ok' => true, 'wave' => 252, 'ts' => date('c'), 'solutions_count' => count($solutions), 'solutions' => $solutions, 'top_gaps' => array_slice($top_gaps, 0, 15), 'mup_checklist' => $checklist, 'summary' => [ 'ship_it' => count(array_filter($solutions, function($s){return $s['decision']==='SHIP_IT';})), 'accelerate' => count(array_filter($solutions, function($s){return $s['decision']==='ACCELERATE';})), 'dev_sprint' => count(array_filter($solutions, function($s){return $s['decision']==='DEV_SPRINT';})), 'nurture' => count(array_filter($solutions, function($s){return $s['decision']==='NURTURE';})), 'pivot' => count(array_filter($solutions, function($s){return $s['decision']==='PIVOT_OR_PARK';})), 'total_mad_pipeline' => array_sum(array_column($solutions, 'mad_est')), 'total_dev_days' => array_sum(array_map(function($s){return $s['dev_effort']['total_dev_days'];}, $solutions)), 'total_dev_cost_mad' => array_sum(array_map(function($s){return $s['dev_effort']['dev_cost_mad'];}, $solutions)), ], ], JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT); exit; } if ($action === 'checklist') { echo json_encode(['ok'=>true, 'wave'=>252, 'checklist'=>mup_checklist()], JSON_PRETTY_PRINT); exit; } http_response_code(400); echo json_encode(['error'=>'unknown action']);