Files
weval-l99/wevia-site-builder-v5-b8-BROKEN.php
opus-wire 7f67eb6bdf auto-push
2026-04-18 14:33:55 +02:00

1205 lines
90 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
// wevia-site-builder.php v2.0 — 2026-04-18 — Phase B1 doctrine 108 §9 (light default + toggle)
// Génère pages produit WEVAL en thème clair par défaut avec toggle jour/nuit
declare(strict_types=1);
const FORBIDDEN_TERMS = [
'Abbott', 'AbbVie', 'Johnson & Johnson', 'Johnson and Johnson',
'Servier', 'Rim Pharma', 'IQVIA', "L'Oréal", 'LVMH', 'Nestlé',
'Chanel', 'Carrefour', 'Intermarché', 'Michelin', 'Valeo', 'Safran',
'Vinci', 'Bombardier', 'Faiveley', 'RATP', 'Geodis', 'Deloitte', 'PwC',
'CGI', 'Sage', 'Markem', 'Givaudan', 'Lesaffre', 'Nocibe', 'Fnac',
'Pixmania', 'Shell', 'Total', 'Daher', 'Telenor', 'SNTL', 'Saham Bank',
'OCP Group', 'Reunicaa',
'SAP Gold', 'Gold Partner',
'Paperclip', 'DeerFlow', 'MiroFish', 'OSS Discovery', 'Cowork',
'131K+', '131000', '131 000', 'Tunisie · Maroc · Algérie',
'TN/MA/DZ', 'TN · MA · DZ',
];
const PRODUCTS = [
'wevia-em' => [
'name' => 'WEVIA EM',
'tagline' => "Enterprise Model - L'IA souveraine qui orchestre la valeur de bout en bout",
'suite' => 'WEVIA Enterprise',
'accent' => 'purple',
'badge' => 'FLAGSHIP - Enterprise Model - En production',
'h1_a' => "L'IA souveraine qui",
'h1_b' => "<em>orchestre la valeur</em> de bout en bout.",
'desc' => "Plateforme d'orchestration multi-agents IA qui couvre l'integralite de votre value chain et de vos process metier. Finance, RH, Marketing, Commerce, Supply Chain, Achats, Production, SI, QA et Cyber - un seul Brain Center, pilote par votre comex. Lean Six Sigma et BPMN integres, methodologie DMAIC, deploiement in-house. Vos donnees restent chez vous.",
'stats' => [['9', 'Metiers orchestres'], ['-40%', 'Delais de pilotage'], ['ROI', '4 mois moyen'], ['6sigma', 'DMAIC zero regression']],
'features' => [
['Finance', "P and L, previsions, facturation et audit automatises. Cloture mensuelle acceleree, consolidation multi-entites, alertes derives en temps reel."],
['RH and Talents', "Sourcing, onboarding, formation et gestion des talents. Agents de matching, parcours d'integration, developpement des competences automatises."],
['Marketing', "Ciblage, creation de contenu, campagnes et analytics en continu. Optimisation budget, A/B testing industriel, attribution multi-touch."],
['Commerce', "Qualification de leads, redaction de proposals, CRM et closing. Agents commerciaux specialises par secteur, scoring IA, handover fluide."],
['Supply Chain', "Collecte, enrichissement, routage et livraison. Previsions demande, optimisation stock, suivi transport, alertes rupture."],
['Achats', "RFP, evaluation fournisseurs, negociation et contrats. Sourcing automatise, scoring risque, benchmarks marche continus."],
['Production', "Qualite, assemblage, tests et expedition. Controle qualite vision IA, maintenance predictive, optimisation OEE."],
['SI and Infrastructure', "Monitoring, deploiement, scaling et securite. Observability IA, auto-remediation, rightsizing cloud, DevOps augmente."],
['QA and Cybersecurity', "Tests automatises, audits, patching et conformite. SAST/DAST IA, threat intelligence, compliance continue RGPD et AI Act."],
],
],
'wevia-master' => [
'name' => 'WEVIA Master', 'tagline' => 'IA autonome propriétaire — orchestration multi-agents',
'suite' => 'WEVIA Enterprise', 'accent' => 'teal',
'badge' => 'IA Souveraine · En production',
'h1_a' => "L'agent qui <em>exécute</em>.", 'h1_b' => 'Pas juste répond.',
'desc' => 'Agent IA autonome propriétaire. Ne se contente pas de conseiller : scanne votre infrastructure, exécute des décisions contrôlées, apprend en continu sur votre domaine métier. Cascade multi-modèles intelligente pour combiner performance, coût maîtrisé et souveraineté des données.',
'stats' => [['Multi-model', 'Cascade intelligente'], ['Sovereign', 'EU certified'], ['<200ms', 'Latence médiane'], ['6σ', 'Qualité L99']],
'features' => [
['Orchestration multi-agents', 'Décompose les demandes complexes en sous-tâches distribuées sur agents spécialisés.'],
['Exécution contrôlée', 'Actions réelles avec journalisation, audit trail complet et gouvernance fine.'],
['Raisonnement métier', 'Fine-tuning possible sur votre domaine pour précision supérieure aux modèles génériques.'],
['Intégration système', 'API REST, webhooks, SSE streaming, hooks dans CRM, ERP, Slack, email, outils internes.'],
['Cascade souveraine', 'Combine plusieurs providers IA avec fallback intelligent, optimisation coût-qualité dynamique.'],
['Monitoring natif', 'Dashboard temps réel, métriques Six Sigma, alerting proactif sur dérive de qualité.'],
],
],
'wevia-inference' => [
'name' => 'WEVIA Inference', 'tagline' => 'GPU dédié souverain · multi-modèles',
'suite' => 'WEVIA Enterprise', 'accent' => 'teal',
'badge' => 'Infrastructure IA · Haute disponibilité',
'h1_a' => 'Inférence IA <em>sans compromis</em>', 'h1_b' => 'sur vos données.',
'desc' => "Plateforme d'inférence IA sur GPU dédiés, hébergée en souveraineté européenne. Déploiement multi-modèles (LLMs, vision, embeddings), API compatible OpenAI, zéro exfiltration, SLA 100%.",
'stats' => [['GPU dédié', 'A100 · H100'], ['EU Sovereign', 'Certifié'], ['API compatible', 'OpenAI spec'], ['100%', 'SLA garanti']],
'features' => [
['GPUs dédiés premium', 'A100 et H100 allouées exclusivement à vos workloads, aucun partage multi-tenant.'],
['Multi-modèles unifié', "LLMs, vision, audio, embeddings — une seule API pour tous les cas d'usage."],
["API drop-in OpenAI", "Migration depuis OpenAI en changeant uniquement l'URL endpoint, aucun refactor code."],
['Souveraineté stricte', 'Données et modèles hébergés en Europe, conformité RGPD, AI Act et HDS.'],
['Scaling automatique', 'Autoscaling horizontal basé sur la charge, facturation au token consommé.'],
['Fine-tuning intégré', 'Entraînement domaine métier sur vos données, versioning et rollback des modèles.'],
],
],
'projectflow' => [
'name' => 'ProjectFlow', 'tagline' => 'Orchestration projets &amp; agents IA',
'suite' => 'WEVIA Enterprise', 'accent' => 'teal',
'badge' => 'Project Intelligence · Live',
'h1_a' => 'Vos projets,', 'h1_b' => '<em>orchestrés par IA.</em>',
'desc' => "Plateforme de gestion de projets augmentée par agents IA. Planification, suivi d'objectifs, orchestration d'équipes hybrides humains-agents, reporting temps réel sur avancement et bloquants.",
'stats' => [['Agents IA', 'Spécialisés par rôle'], ['SSE', 'Streaming temps réel'], ['Kanban', '+ Agents'], ['RACI', 'Auto-généré']],
'features' => [
['Équipes hybrides', 'Humains et agents IA travaillent sur les mêmes tâches, coordination fluide.'],
['Goals &amp; OKRs', "Objectifs mesurables, suivi d'avancement, alertes dérive, boucles de rétroaction."],
['Dashboard temps réel', "Vue directeur de l'avancement global, des risques, des décisions en attente."],
['Auto-RACI', 'Matrice responsabilités générée automatiquement depuis la structure du projet.'],
['Intégration native', "Connecteurs Jira, GitHub, Slack, Gmail, Teams — pas de silo d'information."],
['Audit trail', 'Traçabilité complète des décisions, idéal pour environnements réglementés.'],
],
],
'researchflow' => [
'name' => 'ResearchFlow', 'tagline' => 'Recherche multi-agents approfondie',
'suite' => 'WEVIA Enterprise', 'accent' => 'teal',
'badge' => 'Research Intelligence · Live',
'h1_a' => 'La recherche approfondie,', 'h1_b' => '<em>automatisée.</em>',
'desc' => 'Moteur de recherche multi-agents. Décompose une question complexe en sous-requêtes, explore sources publiques et internes, synthétise un rapport structuré avec citations vérifiables.',
'stats' => [['Multi-agents', 'Spécialisés'], ['Sources', 'Web + interne'], ['Citations', 'Vérifiables'], ['Markdown', 'Structuré']],
'features' => [
['Décomposition automatique', "Une question complexe devient un arbre de sous-questions explorées en parallèle."],
['Sources internes &amp; web', 'Combine votre base documentaire privée avec les sources publiques crédibles.'],
['Citations vérifiables', "Chaque affirmation liée à sa source, lien direct, extraction du passage original."],
['Rapport Markdown', "Livrable structuré prêt à l'emploi : exec summary, détails, annexes, bibliographie."],
['Vérification croisée', 'Triangulation automatique des informations entre sources pour fiabilité.'],
['Export multi-format', 'PDF, Word, Notion, Confluence — intégration dans vos flux existants.'],
],
],
'boardflow' => [
'name' => 'BoardFlow', 'tagline' => 'Whiteboard collaboratif intelligent',
'suite' => 'WEVIA Enterprise', 'accent' => 'teal',
'badge' => 'Collaboration · Live',
'h1_a' => 'Le whiteboard', 'h1_b' => '<em>qui pense avec vous.</em>',
'desc' => "Tableau collaboratif visuel augmenté par IA. Brainstorming, architecture, mind-mapping, process design. L'IA suggère, structure, reformule, détecte les angles morts en temps réel.",
'stats' => [['Temps réel', 'Multi-user'], ['IA intégrée', 'Contextuelle'], ['Templates', 'Design thinking'], ['Export', 'Multi-format']],
'features' => [
['Canvas infini', 'Espace visuel illimité pour sketches, diagrammes, notes, connexions, structures.'],
['Co-création IA', "L'agent propose, restructure, consolide, détecte les incohérences en temps réel."],
['Templates métier', 'Bibliothèque de patterns : design thinking, BPMN, architecture, product canvas.'],
['Présence multi-user', 'Curseurs temps réel, voix-vidéo embarquée, mode focus ou revue synchrone.'],
['Versioning', 'Historique complet des évolutions, fork et merge de branches créatives.'],
['Intégration outils', 'Import depuis Figma, Lucidchart, Visio ; export multi-format.'],
],
],
'stackscan' => [
'name' => 'StackScan', 'tagline' => 'Audit &amp; inventaire OSS entreprise',
'suite' => 'WEVIA Enterprise', 'accent' => 'teal',
'badge' => 'Open Source Discovery · Live',
'h1_a' => 'Votre stack open source,', 'h1_b' => '<em>en pleine lumière.</em>',
'desc' => 'Scanner et cartographe de votre écosystème open source. Détecte dépendances, licences, vulnérabilités, versions obsolètes. Recommandations de remédiation priorisées par impact et effort.',
'stats' => [['Licences', 'SPDX complet'], ['CVE', 'Temps réel'], ['SBOM', 'CycloneDX'], ['Priorisation', 'Impact × effort']],
'features' => [
['SBOM automatique', 'Génération Software Bill of Materials au format CycloneDX ou SPDX, exports continus.'],
['Licences &amp; conformité', "Détection de toutes licences, alertes sur incompatibilités et contraintes juridiques."],
['CVE temps réel', 'Scanning continu des vulnérabilités, alertes proactives, corrélation avec contexte.'],
['Priorisation intelligente', "Impact business × effort de remédiation = file d'attente d'actions claire."],
['Intégration CI/CD', 'Hooks GitHub Actions, GitLab CI, Jenkins — bloque les déploiements non conformes.'],
['Dashboard exécutif', 'Vue directeur du risque OSS, tendances, score santé de chaque composant métier.'],
],
],
'wevia-desk' => [
'name' => 'WEVIA Desk', 'tagline' => 'Automatisation bureautique par IA',
'suite' => 'WEVIA Enterprise', 'accent' => 'teal',
'badge' => 'Desktop Automation · Live',
'h1_a' => "L'agent qui pilote", 'h1_b' => '<em>votre poste de travail.</em>',
'desc' => "Agent IA desktop. Automatise tâches répétitives : tri d'emails, extraction de données, remplissage de formulaires, génération de livrables. Contrôle des applications natives via API ou vision.",
'stats' => [['Native apps', 'Contrôle direct'], ['Vision IA', 'OCR + reconnaissance'], ['Workflows', 'Low-code'], ['Audit', 'Log complet']],
'features' => [
['Contrôle natif', "Pilote Excel, Word, Outlook, navigateur, applications métier via API ou automation visuelle."],
['Vision IA intégrée', 'OCR et reconnaissance visuelle pour interagir avec interfaces legacy sans API.'],
['Workflows low-code', "Éditeur visuel pour orchestrer des séquences complexes sans savoir coder."],
['Déclencheurs contextuels', 'Actions lancées sur email reçu, fichier déposé, heure, événement calendrier.'],
['Mode supervisé', "Validation humaine requise pour actions sensibles, audit trail exhaustif."],
['Déploiement groupé', 'Rollout sur parc de postes avec gouvernance centrale, policies par rôle.'],
],
],
'wevia-life' => [
'name' => 'WEVIA Life',
'tagline' => 'Classification IA des emails professionnels',
'suite' => 'WEVIA Enterprise',
'accent' => 'teal',
'badge' => 'Email Intelligence - En production',
'h1_a' => 'Vos emails,',
'h1_b' => '<em>classifies et actionnables.</em>',
'desc' => "Agent IA qui analyse vos emails professionnels en continu. Classification multi-axes : opportunites business, risques, actions requises. Chat RAG sur l historique, extraction automatique de decisions, deadlines, engagements. Integration IMAP multi-comptes, aucune donnee exposee a l exterieur.",
'stats' => [['Multi-compte', 'IMAP natif'], ['Classification', 'Opportunite / Risque / Action'], ['RAG chat', 'Historique complet'], ['Souverain', 'Hosting EU']],
'features' => [
['Classification multi-axes', "Chaque email score sur 3 dimensions : opportunite commerciale, risque business, action requise. Priorisation automatique."],
['Extraction de decisions', 'Detection des engagements pris, deadlines mentionnees, livrables attendus - consolides dans un journal actionnable.'],
['Chat RAG emails', 'Posez des questions en langage naturel sur votre historique email. Retrouvez contexte, pieces jointes, fils de discussion.'],
['IMAP multi-comptes', 'Connexion native IMAP, support multi-boites, synchronisation continue. OAuth2 et app-passwords supportes.'],
['Attachments intelligents', 'OCR et parsing de pieces jointes (PDF, Word, Excel) - contenu indexe et recherchable.'],
['Alerts et digests', 'Notifications ciblees sur opportunites et risques critiques. Digest quotidien synthetique pour le comex.'],
],
],
'wevia-white-label' => [
'name' => 'WEVIA White-Label',
'tagline' => 'Deployer WEVIA sous votre marque',
'suite' => 'WEVIA Enterprise',
'accent' => 'teal',
'badge' => 'Multi-tenant White-Label - Enterprise',
'h1_a' => 'Votre IA souveraine,',
'h1_b' => '<em>votre marque.</em>',
'desc' => "Deployez la stack WEVIA sous votre propre branding. Theme custom, domaine dedie, kit de marque integre, isolation tenant stricte. Ideal pour integrateurs, editeurs logiciels, cabinets de conseil qui veulent revendre WEVIA a leurs clients. Gouvernance centralisee, billing unifie.",
'stats' => [['Branding', 'Theme + domaine + logo'], ['Multi-tenant', 'Isolation stricte'], ['Billing', 'Unifie ou per-tenant'], ['Gouvernance', 'Centralisee']],
'features' => [
['Theming complet', 'Couleurs, typographie, logo, favicon, images marketing personnalisables sans code.'],
['Domaine dedie', 'Chaque deployment sur votre sous-domaine ou domaine client, SSL automatique, CDN integre.'],
['Isolation tenant', 'Donnees, modeles fine-tunes, historique conversations strictement separes entre tenants.'],
['Kit de marque', 'Emails transactionnels, PDF generes, dashboards exportes adoptent automatiquement votre charte.'],
['Billing flexible', 'Facturation unifiee pour vous ou refacturation au tenant final via API de gestion.'],
['Support partenaire', 'SLA dedie, documentation blanche, onboarding partenaires, programme revenue-share.'],
],
],
'reachhcp' => [
'name' => 'ReachHCP', 'tagline' => 'Base HCP mondiale · consent-based',
'suite' => 'WEVAL Pharma Cloud', 'accent' => 'coral',
'badge' => 'Healthcare Intelligence · Live',
'h1_a' => 'Les professionnels de santé,', 'h1_b' => '<em>atteints dans les règles.</em>',
'desc' => "Base de données de professionnels de santé vérifiés, consent-based, couverture mondiale. Segmentation fine par spécialité, zone, typologie d'exercice. Conformité RGPD, HDS, exports auditables.",
'stats' => [['Mondial', 'Multi-continents'], ['Consent', 'Opt-in vérifié'], ['RGPD', '+ HDS'], ['Update', 'Continu']],
'features' => [
['Couverture mondiale', "Europe, Amériques, MENA, Asie — spécialistes hospitaliers et libéraux, tous secteurs."],
['Consent-based strict', 'Opt-in vérifié source, traçabilité complète, retrait à tout moment, conformité maximale.'],
['Segmentation fine', "Spécialité, sous-spécialité, zone géographique, typologie d'exercice, affiliation."],
['Enrichissement continu', 'Mises à jour en continu, détection automatique des changements, déduplication ML.'],
['Exports auditables', "Logs complets de chaque extraction, justification du consent, preuves horodatées."],
['API temps réel', 'REST et GraphQL pour intégration CRM, automation marketing, analytics.'],
],
],
'campaign-studio' => [
'name' => 'Campaign Studio', 'tagline' => 'Création &amp; orchestration campagnes pharma',
'suite' => 'WEVAL Pharma Cloud', 'accent' => 'coral',
'badge' => 'Pharma Campaigns · Live',
'h1_a' => 'La campagne omnicanale,', 'h1_b' => '<em>compliant by design.</em>',
'desc' => "Studio de création et orchestration de campagnes pharma. Assets conformes (validation médicale embarquée), multicanal (email, print, meetings, digital), tracking conforme, reporting exécutif.",
'stats' => [['Multicanal', 'Email · Print · Live'], ['Validation', 'Médicale auto'], ['Compliance', 'Track complet'], ['ROI', 'Vue exec']],
'features' => [
['Studio de création', "Éditeur visuel avec bibliothèque d'assets, templates validés, versioning complet."],
['Validation médicale', 'Workflow de relecture obligatoire, audit trail, signature électronique des MRL.'],
['Orchestration multicanal', 'Une séquence = email + courrier + meeting + push — cadencement intelligent.'],
['Tracking compliant', "Attribution fine conforme RGPD, pas de cookies tiers, pixels propriétaires."],
['Dashboard ROI', "Vue exécutive par campagne, par produit, par territoire, par spécialité."],
['A/B testing rigoureux', "Plans d'expérience statistiquement signifiants, significance testing intégré."],
],
],
'consent-manager' => [
'name' => 'Consent Manager', 'tagline' => 'Gestion du consentement B2B healthcare',
'suite' => 'WEVAL Pharma Cloud', 'accent' => 'coral',
'badge' => 'B2B Consent · Live',
'h1_a' => 'Le consentement professionnel,', 'h1_b' => '<em>géré comme un asset.</em>',
'desc' => "Plateforme de gestion du consentement B2B pour les interactions avec professionnels de santé. Collecte, stockage horodaté, retrait, audit, preuve légale. Conformité RGPD, LPD, LGPD, CCPA.",
'stats' => [['Multi-juridictions', 'RGPD · LPD · LGPD'], ['Preuve', 'Horodatée'], ['Retrait', 'Un clic'], ['Audit', 'Exports complets']],
'features' => [
['Collecte multi-canal', "Formulaires web, mobile, print avec QR, signature électronique, validation téléphonique."],
['Stockage horodaté', "Chaque consent ou refus daté, sourcé, signé — preuve juridique opposable."],
['Retrait en un clic', "Liens de désinscription dans chaque communication, propagation immédiate aux systèmes."],
['Audit trail complet', "Qui, quoi, quand, depuis où — exports complets à la demande d'un régulateur."],
['Conformité multi-juridictions', 'RGPD européen, LPD suisse, LGPD brésilien, CCPA californien, mises à jour continues.'],
['API temps réel', 'Hooks vers CRM, marketing automation, data warehouse — synchro sub-seconde.'],
],
],
];
const SUITES = [
'WEVIA Enterprise' => [
'slug' => 'wevia-enterprise',
'desc' => "L'écosystème d'IA souveraine propriétaire WEVAL. Agent autonome, inférence GPU dédiée, orchestration multi-agents, whiteboard collaboratif, audit de stack, automatisation desktop — une stack complète, interopérable, souveraine.",
'siblings' => ['WEVIA EM', 'WEVIA Master', 'WEVIA Inference', 'WEVIA Life', 'WEVIA White-Label', 'ProjectFlow', 'ResearchFlow', 'BoardFlow', 'Blade AI', 'StackScan', 'WEVIA Desk'],
],
'WEVAL Pharma Cloud' => [
'slug' => 'pharma-cloud',
'desc' => "Suite dédiée aux sciences de la vie et à l'industrie pharmaceutique. Base HCP mondiale consent-based, CRM pharma, studio de campagnes compliant, gestion du consentement, dashboard exécutif.",
'siblings' => ['ReachHCP', 'ReachHCP API', 'Healthcare CRM', 'Campaign Studio', 'HCP Dashboard', 'Consent Manager'],
],
];
// Light + Dark accent palettes (per suite)
const ACCENTS = [
'teal' => ['light' => '#0d9488', 'dark' => '#00c9a7', 'soft_l' => 'rgba(13,148,136,.08)', 'soft_d' => 'rgba(0,201,167,.12)'],
'purple' => ['light' => '#6f5cff', 'dark' => '#7c5cfc', 'soft_l' => 'rgba(111,92,255,.08)', 'soft_d' => 'rgba(124,92,252,.12)'],
'gold' => ['light' => '#b88a2e', 'dark' => '#f0c674', 'soft_l' => 'rgba(184,138,46,.08)', 'soft_d' => 'rgba(240,198,116,.12)'],
'coral' => ['light' => '#dc3e3e', 'dark' => '#ff6b6b', 'soft_l' => 'rgba(220,62,62,.08)', 'soft_d' => 'rgba(255,107,107,.12)'],
];
function get_template(): string {
return <<<'HTML'
<!DOCTYPE html>
<html lang="fr" data-theme="light"><head>
<link rel="icon" href="/favicon.ico" type="image/x-icon">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>{{NAME}} — {{TAGLINE}} | WEVAL Consulting</title>
<meta name="description" content="{{NAME}} — {{DESC_SHORT}} Part of {{SUITE}} suite.">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=Space+Mono:wght@400;700&display=swap" rel="stylesheet">
<script>(function(){var t=localStorage.getItem('weval-theme')||'light';document.documentElement.setAttribute('data-theme',t);})();</script>
<style>
:root{--bg:#ffffff;--bg-alt:#fafbfc;--surface:#ffffff;--text:#1a1f3a;--text-soft:#5a6480;--text-dim:#8893a8;--border:rgba(26,31,58,.08);--border-mid:rgba(26,31,58,.14);--shadow:0 1px 3px rgba(26,31,58,.04),0 8px 24px rgba(26,31,58,.04);--shadow-hover:0 2px 6px rgba(26,31,58,.06),0 16px 40px rgba(26,31,58,.08);--a:{{A_LIGHT}};--a-soft:{{A_SOFT_L}};--btn-p:#5b4cdb;--btn-p-h:#4a3dc4}
html[data-theme="dark"]{--bg:#05080f;--bg-alt:#080c18;--surface:#0c1222;--text:#edf2f7;--text-soft:#a8b4c8;--text-dim:#7a8ba5;--border:rgba(255,255,255,.06);--border-mid:rgba(255,255,255,.12);--shadow:0 1px 3px rgba(0,0,0,.3),0 8px 24px rgba(0,0,0,.3);--shadow-hover:0 2px 6px rgba(0,0,0,.4),0 16px 40px rgba(0,0,0,.4);--a:{{A_DARK}};--a-soft:{{A_SOFT_D}};--btn-p:#7c5cfc;--btn-p-h:#9277ff}
*{margin:0;padding:0;box-sizing:border-box}
html{scroll-behavior:smooth}
body{font-family:'Inter',sans-serif;background:var(--bg);color:var(--text);-webkit-font-smoothing:antialiased;transition:background .3s,color .3s}
body::before{content:'';position:fixed;inset:0;background-image:radial-gradient(circle at 20% 10%,var(--a-soft) 0%,transparent 40%),radial-gradient(circle at 80% 60%,var(--a-soft) 0%,transparent 45%);pointer-events:none;opacity:.6;z-index:-1;transition:opacity .3s}
nav{position:fixed;top:0;width:100%;padding:1rem 4%;display:flex;justify-content:space-between;align-items:center;z-index:100;backdrop-filter:blur(20px);background:color-mix(in srgb,var(--bg) 85%,transparent);border-bottom:1px solid var(--border)}
.logo{font-weight:800;font-size:1.35rem;letter-spacing:-.035em;display:flex;align-items:center;gap:.5rem;color:var(--text);text-decoration:none}
.logo-dot{width:10px;height:10px;border-radius:50%;background:var(--a);box-shadow:0 0 18px var(--a-soft)}
.nav-r{display:flex;gap:1.6rem;align-items:center}
.nav-r a{color:var(--text-soft);text-decoration:none;font-size:.86rem;font-weight:500;transition:color .25s}
.nav-r a:hover{color:var(--a)}
.btn-n{background:var(--btn-p);color:#fff;padding:.6rem 1.3rem;border-radius:8px;font-weight:600;font-size:.84rem;text-decoration:none;transition:all .2s;border:none;cursor:pointer}
.btn-n:hover{background:var(--btn-p-h);transform:translateY(-1px)}
.theme-toggle{width:38px;height:38px;border-radius:50%;background:var(--bg-alt);border:1px solid var(--border);display:inline-flex;align-items:center;justify-content:center;cursor:pointer;transition:all .2s;color:var(--text-soft)}
.theme-toggle:hover{border-color:var(--a);color:var(--a);transform:translateY(-1px)}
.theme-toggle svg{width:18px;height:18px}
html[data-theme="light"] .icon-moon{display:none}
html[data-theme="dark"] .icon-sun{display:none}
.hero{min-height:92vh;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;padding:9rem 4% 5rem;position:relative;overflow:hidden}
.badge{display:inline-flex;align-items:center;gap:.5rem;background:var(--a-soft);border:1px solid var(--a-soft);border-radius:100px;padding:.42rem 1.05rem;font-size:.72rem;font-weight:700;color:var(--a);margin-bottom:2rem;font-family:'Space Mono',monospace;letter-spacing:.05em}
.badge::before{content:'';width:6px;height:6px;background:var(--a);border-radius:50%;animation:pulse 2s infinite}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.35}}
h1{font-size:clamp(2.4rem,5vw,4.1rem);font-weight:800;line-height:1.04;letter-spacing:-.04em;max-width:900px;margin-bottom:1.5rem;color:var(--text)}
h1 em{font-style:normal;color:var(--a)}
.sub{font-size:clamp(1rem,1.2vw,1.1rem);color:var(--text-soft);max-width:700px;line-height:1.65;margin-bottom:2.5rem;font-weight:400}
.btns{display:flex;gap:1rem;flex-wrap:wrap;justify-content:center}
.btn-p{background:var(--btn-p);color:#fff;padding:.95rem 2rem;border-radius:10px;font-weight:600;font-size:.9rem;text-decoration:none;transition:all .25s;display:inline-flex;align-items:center;gap:.4rem;box-shadow:0 4px 12px color-mix(in srgb,var(--btn-p) 25%,transparent)}
.btn-p:hover{background:var(--btn-p-h);transform:translateY(-2px);box-shadow:0 8px 24px color-mix(in srgb,var(--btn-p) 30%,transparent)}
.btn-o{background:transparent;color:var(--text);padding:.95rem 2rem;border-radius:10px;font-weight:500;font-size:.9rem;text-decoration:none;border:1px solid var(--border-mid);transition:all .25s;display:inline-flex;align-items:center;gap:.4rem}
.btn-o:hover{border-color:var(--a);color:var(--a);background:var(--a-soft)}
.suite-chip{display:inline-flex;align-items:center;gap:.5rem;margin-top:1.5rem;padding:.38rem .95rem;background:var(--bg-alt);border:1px solid var(--border);border-radius:100px;font-size:.74rem;color:var(--text-soft);font-family:'Space Mono',monospace;font-weight:600;letter-spacing:.04em;text-decoration:none;transition:all .2s}
.suite-chip:hover{color:var(--a);border-color:var(--a)}
.sec{padding:5.5rem 4%;max-width:1180px;margin:0 auto}
.sec.alt{background:var(--bg-alt);max-width:none;padding-left:max(4%,calc((100% - 1180px) / 2));padding-right:max(4%,calc((100% - 1180px) / 2))}
.stag{font-family:'Space Mono',monospace;font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.22em;color:var(--a);margin-bottom:1rem;display:inline-block}
h2{font-size:clamp(1.8rem,2.8vw,2.4rem);font-weight:800;letter-spacing:-.032em;line-height:1.1;margin-bottom:.9rem;max-width:700px;color:var(--text)}
h2 em{font-style:normal;color:var(--a)}
.sd{color:var(--text-soft);font-size:1rem;line-height:1.65;max-width:600px;margin-bottom:3rem;font-weight:400}
.stats{display:grid;grid-template-columns:repeat(4,1fr);gap:0;background:var(--surface);border:1px solid var(--border);border-radius:14px;overflow:hidden;margin:2rem 0 3rem;box-shadow:var(--shadow)}
.stat{padding:1.6rem 1rem;text-align:center;border-right:1px solid var(--border)}
.stat:last-child{border-right:none}
.stat-n{font-family:'Space Mono',monospace;font-size:1.35rem;font-weight:700;color:var(--a);line-height:1}
.stat-l{font-size:.72rem;color:var(--text-soft);margin-top:.5rem;text-transform:uppercase;letter-spacing:.1em;font-weight:500}
.g3{display:grid;grid-template-columns:repeat(3,1fr);gap:1rem;margin-top:1.5rem}
.fcd{background:var(--surface);border:1px solid var(--border);border-radius:14px;padding:1.7rem;transition:all .3s;position:relative;overflow:hidden;box-shadow:var(--shadow)}
.fcd::before{content:'';position:absolute;top:0;left:0;width:3px;height:100%;background:var(--a);opacity:0;transition:opacity .3s}
.fcd:hover{border-color:var(--a);transform:translateY(-3px);box-shadow:var(--shadow-hover)}
.fcd:hover::before{opacity:1}
.fcd h3{font-size:1.02rem;font-weight:700;margin-bottom:.55rem;letter-spacing:-.01em;color:var(--text)}
.fcd p{font-size:.87rem;color:var(--text-soft);line-height:1.6}
.suite-box{background:var(--surface);border:1px solid var(--border);border-radius:18px;padding:2.2rem;display:grid;grid-template-columns:1.2fr .8fr;gap:2.2rem;align-items:center;margin-top:2rem;box-shadow:var(--shadow)}
.suite-box-l h3{font-size:1.35rem;font-weight:700;margin-bottom:.7rem;letter-spacing:-.02em;color:var(--text)}
.suite-box-l p{color:var(--text-soft);font-size:.94rem;line-height:1.6;margin-bottom:1.2rem}
.suite-box-r{display:flex;flex-wrap:wrap;gap:.4rem}
.apptag{background:var(--bg-alt);border:1px solid var(--border);border-radius:6px;padding:.32rem .7rem;font-size:.72rem;color:var(--text);font-family:'Space Mono',monospace;font-weight:500}
.apptag.self{background:var(--a-soft);color:var(--a);border-color:var(--a)}
.cta{text-align:center;padding:4.5rem 2rem;margin:3rem 4% 2rem;background:var(--bg-alt);border:1px solid var(--border);border-radius:22px;position:relative;overflow:hidden;max-width:1100px;margin-left:auto;margin-right:auto}
.cta h2{margin:0 auto .9rem}
.cta p{color:var(--text-soft);max-width:560px;margin:0 auto 2rem}
footer{padding:2.5rem 4% 1.5rem;max-width:1180px;margin:2rem auto 0;border-top:1px solid var(--border)}
.foot-t{display:flex;justify-content:space-between;align-items:center;margin-bottom:1rem;flex-wrap:wrap;gap:1rem}
.foot-t .logo{font-size:1.1rem}
.foot-links{display:flex;gap:1.5rem;font-size:.85rem}
.foot-links a{color:var(--text-soft);text-decoration:none;transition:color .2s}
.foot-links a:hover{color:var(--a)}
.foot-b{font-size:.74rem;color:var(--text-dim);font-family:'Space Mono',monospace;letter-spacing:.04em}
@media(max-width:900px){h1{font-size:2.2rem}.stats{grid-template-columns:1fr 1fr}.stat:nth-child(odd){border-right:1px solid var(--border)}.stat:nth-child(even){border-right:none}.stat{border-bottom:1px solid var(--border)}.g3{grid-template-columns:1fr}.suite-box{grid-template-columns:1fr;padding:1.6rem}.nav-r a:not(.btn-n):not(.theme-toggle){display:none}}
@media all{.in-iframe nav{display:none!important}.in-iframe .hero{padding-top:3rem!important;min-height:auto!important}.in-iframe footer{display:none!important}.in-iframe .cta{display:none!important}}
</style>
<script>if(window!==window.top)document.documentElement.classList.add('in-iframe');</script>
<link rel="canonical" href="https://weval-consulting.com/products/{{SLUG}}.html">
<meta property="og:title" content="{{NAME}} — {{TAGLINE}}">
<meta property="og:description" content="{{NAME}} — {{DESC_SHORT}}">
<meta property="og:url" content="https://weval-consulting.com/products/{{SLUG}}.html">
<meta property="og:type" content="website">
<meta property="og:site_name" content="WEVAL Consulting">
<meta property="og:image" content="https://weval-consulting.com/assets/logo-weval-png-DChrMGao.png">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="{{NAME}} — {{TAGLINE}}">
<meta name="twitter:description" content="{{NAME}} — {{DESC_SHORT}}">
</head><body>
<nav>
<a class="logo" href="/"><span class="logo-dot"></span>{{NAME}}<span style="color:var(--a)">.</span></a>
<div class="nav-r">
<a href="/">Accueil</a>
<a href="/products/">Produits</a>
<a href="/marketplace">Marketplace</a>
<button class="theme-toggle" onclick="(function(){var c=document.documentElement.getAttribute('data-theme')==='dark'?'light':'dark';document.documentElement.setAttribute('data-theme',c);localStorage.setItem('weval-theme',c);})()" aria-label="Basculer thème jour/nuit">
<svg class="icon-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41"/></svg>
<svg class="icon-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>
</button>
<a href="#cta" class="btn-n">Demander une démo →</a>
</div>
</nav>
<section class="hero">
<div class="badge">{{BADGE}}</div>
<h1>{{H1_A}}<br>{{H1_B}}</h1>
<p class="sub">{{DESC}}</p>
<div class="btns">
<a href="#cta" class="btn-p">Demander une démo →</a>
<a href="/solutions/{{SUITE_SLUG}}.html" class="btn-o">Explorer la suite</a>
</div>
<a href="/solutions/{{SUITE_SLUG}}.html" class="suite-chip">▸ Composant de la suite {{SUITE}}</a>
</section>
<section class="sec">
<div class="stag">// Métriques clés</div>
<h2>La <em>performance</em>, chiffrée.</h2>
<div class="stats">{{STATS_HTML}}</div>
</section>
<section class="sec alt">
<div class="stag">// Capacités</div>
<h2>Ce que {{NAME}} <em>fait pour vous.</em></h2>
<p class="sd">Fonctionnalités clés, livrées en production. Chaque capacité est éprouvée en conditions réelles et maintenue sous standard Six Sigma L99.</p>
<div class="g3">{{FEATURES_HTML}}</div>
</section>
<section class="sec">
<div class="stag">// Écosystème</div>
<h2>Intégré dans <em>{{SUITE}}.</em></h2>
<p class="sd">{{NAME}} s'inscrit dans la suite {{SUITE}}, conçue pour l'interopérabilité. Chaque application de la suite communique nativement, partage données et événements, amplifie la valeur des autres.</p>
<div class="suite-box">
<div class="suite-box-l">
<h3>Suite {{SUITE}}</h3>
<p>{{SUITE_DESC}}</p>
<a href="/solutions/{{SUITE_SLUG}}.html" class="btn-o" style="padding:.6rem 1.2rem;font-size:.82rem">Voir la suite complète →</a>
</div>
<div class="suite-box-r">{{SIBLING_TAGS}}</div>
</div>
</section>
<div class="cta" id="cta">
<div class="stag" style="text-align:center;display:block">// Commencer</div>
<h2>Prêt à <em>essayer {{NAME}}</em> ?</h2>
<p>Démonstration personnalisée sur vos données. Diagnostic cas d'usage, scoping technique, proposition de déploiement en 45 minutes.</p>
<div class="btns">
<a href="/#contact" class="btn-p">Réserver une démo →</a>
<a href="/marketplace" class="btn-o">Voir le catalogue complet</a>
</div>
</div>
<footer>
<div class="foot-t">
<a class="logo" href="/"><span class="logo-dot"></span>WEVAL<span style="color:var(--a)">.</span></a>
<div class="foot-links">
<a href="/">Accueil</a>
<a href="/products/">Produits</a>
<a href="/marketplace">Marketplace</a>
<a href="/#contact">Contact</a>
<a href="https://www.linkedin.com/company/weval" target="_blank" rel="noopener" aria-label="LinkedIn" style="display:inline-flex;align-items:center;gap:.35rem"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M19 3a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h14zM8.339 18.337V9.886H5.67v8.451h2.669zM7.003 8.687a1.549 1.549 0 1 0 0-3.097 1.549 1.549 0 0 0 0 3.097zm11.335 9.65v-4.637c0-2.475-1.332-3.625-3.109-3.625-1.434 0-2.076.788-2.436 1.342v-1.152H10.12c.037.778 0 8.451 0 8.451h2.673v-4.72c0-.24.017-.48.088-.652.193-.479.631-.975 1.367-.975.964 0 1.35.734 1.35 1.811v4.537h2.672z"/></svg> LinkedIn</a>
</div>
</div>
<div class="foot-b">© 2026 WEVAL Consulting · Cabinet de conseil &amp; éditeur IA souveraine · Partenaire Écosystème SAP · Huawei Cloud Certified</div>
</footer>
</body></html>
HTML;
}
function build_page(string $slug): array {
if (!isset(PRODUCTS[$slug])) return ['ok' => false, 'slug' => $slug, 'error' => 'Unknown slug'];
$p = PRODUCTS[$slug];
$suite_name = $p['suite'];
if (!isset(SUITES[$suite_name])) return ['ok' => false, 'slug' => $slug, 'error' => 'Unknown suite: ' . $suite_name];
$suite = SUITES[$suite_name];
$accent = ACCENTS[$p['accent']];
$stats_html = '';
foreach ($p['stats'] as [$v, $l]) {
$stats_html .= sprintf('<div class="stat"><div class="stat-n">%s</div><div class="stat-l">%s</div></div>',
htmlspecialchars($v), htmlspecialchars($l));
}
$features_html = '';
foreach ($p['features'] as [$title, $text]) {
$features_html .= sprintf('<div class="fcd"><h3>%s</h3><p>%s</p></div>',
htmlspecialchars($title), htmlspecialchars($text));
}
$sibling_tags = '';
foreach ($suite['siblings'] as $sib) {
$cls = ($sib === $p['name']) ? 'apptag self' : 'apptag';
$sibling_tags .= sprintf('<span class="%s">%s</span>', $cls, htmlspecialchars($sib));
}
$desc_short = mb_substr(strip_tags($p['desc']), 0, 140);
$html = get_template();
$vars = [
'{{SLUG}}' => $slug, '{{NAME}}' => $p['name'], '{{TAGLINE}}' => $p['tagline'],
'{{BADGE}}' => $p['badge'], '{{H1_A}}' => $p['h1_a'], '{{H1_B}}' => $p['h1_b'],
'{{DESC}}' => $p['desc'], '{{DESC_SHORT}}' => $desc_short,
'{{SUITE}}' => $suite_name, '{{SUITE_SLUG}}' => $suite['slug'], '{{SUITE_DESC}}' => $suite['desc'],
'{{STATS_HTML}}' => $stats_html, '{{FEATURES_HTML}}' => $features_html, '{{SIBLING_TAGS}}' => $sibling_tags,
'{{A_LIGHT}}' => $accent['light'], '{{A_DARK}}' => $accent['dark'],
'{{A_SOFT_L}}' => $accent['soft_l'], '{{A_SOFT_D}}' => $accent['soft_d'],
];
$html = strtr($html, $vars);
foreach (FORBIDDEN_TERMS as $term) {
$pattern = '/\b' . preg_quote($term, '/') . '\b/';
if (preg_match($pattern, $html)) {
return ['ok' => false, 'slug' => $slug, 'error' => "Forbidden term: $term"];
}
}
if (!str_contains($html, '<!DOCTYPE html>')) return ['ok' => false, 'slug' => $slug, 'error' => 'Missing DOCTYPE'];
if (!str_contains($html, '</html>')) return ['ok' => false, 'slug' => $slug, 'error' => 'Missing closing html'];
$target = "/var/www/html/products/{$slug}.html";
if (file_exists($target)) {
$gold_dir = '/opt/wevads/vault/gold-site-pages-' . date('Ymd');
if (!is_dir($gold_dir)) @mkdir($gold_dir, 0755, true);
@copy($target, $gold_dir . "/{$slug}-" . date('His') . '.html');
return ['ok' => false, 'slug' => $slug, 'error' => 'File exists — zero écrasement doctrine'];
}
$ok = @file_put_contents($target, $html);
if ($ok === false) return ['ok' => false, 'slug' => $slug, 'error' => 'Write failed'];
return ['ok' => true, 'slug' => $slug, 'file' => $target, 'bytes' => strlen($html), 'features' => count($p['features']), 'theme' => 'light+toggle'];
}
function scan_forbidden(string $dir = '/var/www/html'): array {
$hits = [];
$exts = ['html', 'htm'];
$rii = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS));
foreach ($rii as $f) {
if (!in_array(strtolower($f->getExtension()), $exts, true)) continue;
$path = $f->getPathname();
if (str_contains($path, '/node_modules/') || str_contains($path, '/.git/')) continue;
$content = @file_get_contents($path);
if ($content === false) continue;
foreach (['SAP Gold', 'Gold Partner'] as $t) {
$pattern = '/\b' . preg_quote($t, '/') . '\b/';
if (preg_match($pattern, $content)) $hits[] = ['file' => $path, 'term' => $t];
}
}
return $hits;
}
const SUITE_PAGES = [
'wevia-enterprise' => [
'name' => 'WEVIA Enterprise',
'full_name' => 'WEVIA Enterprise',
'tagline' => "L'ecosysteme d'IA souveraine pour l'entreprise",
'hero_a' => "L'IA souveraine,",
'hero_b' => "<em>orchestree de bout en bout.</em>",
'accent' => 'purple',
'badge' => 'SUITE FLAGSHIP - 11 applications',
'intro' => "Une stack complete d'IA souveraine propriete WEVAL. De l'orchestration multi-agents cross-metiers (WEVIA EM) a l'automatisation desktop (WEVIA Desk), chaque application interopere nativement pour amplifier la valeur des autres. Deploiement in-house possible, vos donnees restent chez vous.",
'value_props' => [
['Souverainete stricte', "Hosting Europe, zero exfiltration, conformite RGPD et AI Act garanties."],
['Interoperabilite native', "APIs REST, SSE streaming, events bus commun, authentification SSO unifiee."],
['Coherence methodologique', "Lean Six Sigma L99, DMAIC, BPMN - un meme standard qualite applique a chaque application."],
['TCO maitrise', "Cascade multi-modeles intelligente, GPU dedies, elasticite demande, sans lock-in vendor."],
],
'apps' => ['wevia-em', 'wevia-master', 'wevia-inference', 'wevia-life', 'wevia-white-label', 'projectflow', 'researchflow', 'boardflow', 'stackscan', 'wevia-desk'],
],
'marketing-cloud' => [
'name' => 'WEVAL Marketing Cloud',
'full_name' => 'WEVAL Marketing Cloud',
'tagline' => 'Arsenal + delivery intelligence',
'hero_a' => 'Le marketing digital,',
'hero_b' => '<em>livre ou remboursé.</em>',
'accent' => 'gold',
'badge' => 'SUITE - Plateforme marketing digital',
'intro' => 'Plateforme marketing digital complete propriete WEVAL. Envoi haute performance, intelligence IA integree, tracking end-to-end, optimisation automatique. Arsenal ERP Intelligence orchestre la couche business, 13 apps specialisees couvrent delivery, warming, reputation, SMS, ads. Infrastructure qui delivre, inbox rate 97%.',
'value_props' => [
['Inbox rate garanti', 'Infrastructure PMTA + KumoMTA + Postfix tunee, Brain Engine IA 646 configs, warming automatique, monitoring RBL continu.'],
['Multicanal integre', 'Email, SMS, ads social, affiliation - une seule stack qui orchestre tous les canaux avec attribution unifiee.'],
['Souverainete stricte', 'Hosting EU, IPs dediees, conformite RGPD et CAN-SPAM, zero partage de donnees tiers.'],
['ROI mesurable', 'Dashboard temps reel par campagne, par audience, par canal - decisions pilotees par la donnee.'],
],
'apps' => ['arsenal', 'deliverads', 'deliverscore', 'mailstream', 'mailwarm', 'mailforge', 'outreachai', 'smsforge', 'adscontrol', 'reputationai', 'ai-sdr', 'newsletterinsight', 'emailverify', 'blacklistguard'],
],
'advisory' => [
'name' => 'WEVAL Advisory',
'full_name' => 'WEVAL Advisory',
'tagline' => 'Cabinet et expertise a la demande',
'hero_a' => 'Du diagnostic',
'hero_b' => 'au <em>run operationnel.</em>',
'accent' => 'purple',
'badge' => 'SUITE - Cabinet de conseil',
'intro' => 'Notre cabinet de conseil. Missions cadrees, livrables mesurables, engagement au ROI. De la strategie IA a la transformation digitale complete. Methodologie Lean Six Sigma, BPMN, DMAIC, engagement NonReg 100%. Seniorite garantie, interventions courtes ou longues, partout en Europe et MENA.',
'value_props' => [
['Expertise senior', 'Tous nos consultants ont 10+ annees d experience terrain. Directeurs techniques, architectes IA, DSI transformes.'],
['Livrables mesurables', 'Chaque mission cadree par KPIs et SLAs contractuels. ROI prouve ou remboursement partiel negociable.'],
['Methodologie unifiee', 'Lean Six Sigma L99, DMAIC, BPMN, standards qualite 6sigma appliques a chaque deliverable.'],
['Transfert de competences', 'Academy integree, formation cloud, IA et methodes. Vos equipes autonomes apres la mission.'],
],
'apps' => ['consulting', 'consulting-pro', 'academy', 'leansixsigma', 'auditai', 'cloudcost'],
],
'productivity' => [
'name' => 'WEVAL Productivity',
'full_name' => 'WEVAL Productivity',
'tagline' => 'IA generative metier',
'hero_a' => 'Vos livrables,',
'hero_b' => '<em>generes et orchestrés.</em>',
'accent' => 'teal',
'badge' => 'SUITE - Productivite et creation',
'intro' => 'Suite d applications IA pour les metiers. De la proposale commerciale au contrat, du design visuel a la presentation, du contenu marketing a la traduction. Chaque app est une IA specialisee, fine-tunable sur votre domaine metier, deployable en souverainete.',
'value_props' => [
['Qualite constante', 'Templates et guardrails metier garantissent un niveau constant, independant de la creativite individuelle.'],
['Integration workflow', 'Chaque app s integre dans vos outils existants - Slack, Teams, Google Workspace, Microsoft 365.'],
['Fine-tuning metier', 'Entrainement sur votre corpus pour ton, style, contraintes sectorielles. Resultat indiscernable de votre equipe.'],
['Productivite mesurable', 'Gains 3-5x sur les taches de production, traces et reportes dans un dashboard unifie.'],
],
'apps' => ['proposalai', 'blueprintai', 'contractai', 'presentationai', 'canvasai', 'copyai', 'content-factory', 'creativefactory', 'dashboardai', 'translateai', 'meetingai', 'devforge', 'bizplan', 'esignature'],
],
'commerce-data' => [
'name' => 'WEVAL Commerce and Data',
'full_name' => 'WEVAL Commerce and Data',
'tagline' => 'E-commerce et lead intelligence',
'hero_a' => 'Du lead',
'hero_b' => 'a la <em>transaction.</em>',
'accent' => 'teal',
'badge' => 'SUITE - Commerce et donnees B2B',
'intro' => 'Suite dediee au commerce digital et a l intelligence des donnees. StoreForge pour le e-commerce, StoreAI pour la personalisation, LeadForge pour la generation B2B, Scout Intelligence pour la veille. Donnees enrichies en continu, integration native avec CRM et outils marketing.',
'value_props' => [
['E-commerce cle en main', 'Boutique en 5 minutes, descriptions IA, chatbot WEVIA integre, paiement international, SEO natif.'],
['Leads B2B verifies', 'Base de leads qualifies et consentis, enrichissement continu, segmentation fine par secteur et taille.'],
['Intelligence continue', 'Veille concurrentielle automatisee, detection de signaux faibles, alerting sur opportunites et menaces.'],
['Integration CRM native', 'Connecteurs Salesforce, HubSpot, Pipedrive, Zoho - pas de silo, donnees synchronisees temps reel.'],
],
'apps' => ['storeforge', 'storeai', 'wevalcrm', 'formbuilder', 'leadforge', 'datainsight', 'scoutai', 'youtubefactory'],
],
'cloud-security' => [
'name' => 'WEVAL Cloud and Security',
'full_name' => 'WEVAL Cloud and Security',
'tagline' => 'Infrastructure et SOC as a Service',
'hero_a' => 'Votre infrastructure,',
'hero_b' => '<em>souveraine et surveillee.</em>',
'accent' => 'coral',
'badge' => 'SUITE - Cloud et cybersecurite',
'intro' => 'Suite cloud et cybersecurite. Hosting souverain certifie Huawei Cloud et Scaleway, monitoring 24/7, SOC as a Service, FinOps automatise, cartographie reseau, GPU dedies pour IA. Conformite RGPD, HDS, AI Act, ISO 27001.',
'value_props' => [
['Souverainete certifiee', 'Hosting EU, certifications Huawei Cloud et Scaleway, conformite HDS pour donnees de sante.'],
['Monitoring 24/7', 'Sentinel surveille SSL, DNS, ports, RBL, OWASP en continu. Alerting Telegram, escalade automatique.'],
['FinOps integre', 'CloudCost analyse vos factures cloud, identifie les gaspillages, optimise automatiquement le rightsizing.'],
['GPU dedies IA', 'Infrastructure GPU A100/H100 pour inference, training, fine-tuning - scaling a la demande.'],
],
'apps' => ['sentinel', 'cloudcost', 'deliverscore', 'inboxtest', 'emailverify', 'cloud-providers', 'huawei-cloud', 'gpu-inference'],
],
'pharma-cloud' => [
'name' => 'WEVAL Pharma Cloud',
'full_name' => 'WEVAL Pharma Cloud',
'tagline' => "Healthcare intelligence mondiale",
'hero_a' => "La sante,",
'hero_b' => "<em>compliant by design.</em>",
'accent' => 'coral',
'badge' => 'SUITE - Sciences de la vie',
'intro' => "Suite dediee a l'industrie pharmaceutique et aux sciences de la vie. Base HCP mondiale consent-based, CRM pharma, studio de campagnes compliant, gestion du consentement B2B. Conformite RGPD, HDS, LGPD, CCPA garanties.",
'value_props' => [
['Consent-based strict', "Opt-in verifie a la source, tracabilite complete, preuve juridique opposable."],
['Couverture mondiale', "Europe, Ameriques, MENA, Asie - specialistes hospitaliers et liberaux."],
['Compliance multi-juridictions', "RGPD europeen, LGPD bresilien, CCPA californien, HDS hebergement sante."],
['Integration CRM native', "Hooks temps reel vers Salesforce Health Cloud, Veeva, Iqvia OCE et systemes maison."],
],
'apps' => ['reachhcp', 'campaign-studio', 'consent-manager'],
],
];
function get_suite_template(): string {
return <<<'HTML2'
<!DOCTYPE html>
<html lang="fr" data-theme="light"><head>
<link rel="icon" href="/favicon.ico" type="image/x-icon">
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Suite {{NAME}} - {{TAGLINE}} | WEVAL Consulting</title>
<meta name="description" content="Suite {{NAME}} - {{DESC_SHORT}}">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=Space+Mono:wght@400;700&display=swap" rel="stylesheet">
<script>(function(){var t=localStorage.getItem('weval-theme')||'light';document.documentElement.setAttribute('data-theme',t);})();</script>
<style>
:root{--bg:#ffffff;--bg-alt:#fafbfc;--surface:#ffffff;--text:#1a1f3a;--text-soft:#5a6480;--text-dim:#8893a8;--border:rgba(26,31,58,.08);--border-mid:rgba(26,31,58,.14);--shadow:0 1px 3px rgba(26,31,58,.04),0 8px 24px rgba(26,31,58,.04);--shadow-h:0 2px 6px rgba(26,31,58,.06),0 16px 40px rgba(26,31,58,.08);--a:{{A_LIGHT}};--a-soft:{{A_SOFT_L}};--btn-p:#5b4cdb;--btn-p-h:#4a3dc4}
html[data-theme="dark"]{--bg:#05080f;--bg-alt:#080c18;--surface:#0c1222;--text:#edf2f7;--text-soft:#a8b4c8;--text-dim:#7a8ba5;--border:rgba(255,255,255,.06);--border-mid:rgba(255,255,255,.12);--shadow:0 1px 3px rgba(0,0,0,.3),0 8px 24px rgba(0,0,0,.3);--shadow-h:0 2px 6px rgba(0,0,0,.4),0 16px 40px rgba(0,0,0,.4);--a:{{A_DARK}};--a-soft:{{A_SOFT_D}};--btn-p:#7c5cfc;--btn-p-h:#9277ff}
*{margin:0;padding:0;box-sizing:border-box}html{scroll-behavior:smooth}
body{font-family:'Inter',sans-serif;background:var(--bg);color:var(--text);-webkit-font-smoothing:antialiased;transition:background .3s,color .3s}
body::before{content:'';position:fixed;inset:0;background:radial-gradient(circle at 20% 10%,var(--a-soft) 0%,transparent 40%),radial-gradient(circle at 80% 60%,var(--a-soft) 0%,transparent 45%);pointer-events:none;opacity:.6;z-index:-1}
nav{position:fixed;top:0;width:100%;padding:1rem 4%;display:flex;justify-content:space-between;align-items:center;z-index:100;backdrop-filter:blur(20px);background:color-mix(in srgb,var(--bg) 85%,transparent);border-bottom:1px solid var(--border)}
.logo{font-weight:800;font-size:1.35rem;letter-spacing:-.035em;display:flex;align-items:center;gap:.5rem;color:var(--text);text-decoration:none}
.logo-dot{width:10px;height:10px;border-radius:50%;background:var(--a);box-shadow:0 0 18px var(--a-soft)}
.nav-r{display:flex;gap:1.6rem;align-items:center}
.nav-r a{color:var(--text-soft);text-decoration:none;font-size:.86rem;font-weight:500;transition:color .25s}
.nav-r a:hover{color:var(--a)}
.btn-n{background:var(--btn-p);color:#fff;padding:.6rem 1.3rem;border-radius:8px;font-weight:600;font-size:.84rem;text-decoration:none;transition:all .2s}
.btn-n:hover{background:var(--btn-p-h)}
.theme-toggle{width:38px;height:38px;border-radius:50%;background:var(--bg-alt);border:1px solid var(--border);display:inline-flex;align-items:center;justify-content:center;cursor:pointer;transition:all .2s;color:var(--text-soft)}
.theme-toggle:hover{border-color:var(--a);color:var(--a)}
.theme-toggle svg{width:18px;height:18px}
html[data-theme="light"] .icon-moon{display:none}html[data-theme="dark"] .icon-sun{display:none}
.hero{min-height:82vh;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;padding:9rem 4% 5rem;position:relative;overflow:hidden}
.badge{display:inline-flex;align-items:center;gap:.5rem;background:var(--a-soft);border:1px solid var(--a-soft);border-radius:100px;padding:.42rem 1.05rem;font-size:.72rem;font-weight:700;color:var(--a);margin-bottom:2rem;font-family:'Space Mono',monospace;letter-spacing:.05em}
.badge::before{content:'';width:6px;height:6px;background:var(--a);border-radius:50%;animation:pulse 2s infinite}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.35}}
.suite-prefix{font-family:'Space Mono',monospace;font-size:.85rem;font-weight:600;color:var(--text-soft);text-transform:uppercase;letter-spacing:.3em;margin-bottom:1rem}
h1{font-size:clamp(2.4rem,5vw,4.2rem);font-weight:800;line-height:1.04;letter-spacing:-.04em;max-width:920px;margin-bottom:1.4rem;color:var(--text)}
h1 em{font-style:normal;color:var(--a)}
.sub{font-size:clamp(1rem,1.2vw,1.1rem);color:var(--text-soft);max-width:720px;line-height:1.65;margin-bottom:2.5rem}
.btns{display:flex;gap:1rem;flex-wrap:wrap;justify-content:center}
.btn-p{background:var(--btn-p);color:#fff;padding:.95rem 2rem;border-radius:10px;font-weight:600;font-size:.9rem;text-decoration:none;transition:all .25s;box-shadow:0 4px 12px color-mix(in srgb,var(--btn-p) 25%,transparent)}
.btn-p:hover{background:var(--btn-p-h);transform:translateY(-2px)}
.btn-o{background:transparent;color:var(--text);padding:.95rem 2rem;border-radius:10px;font-weight:500;font-size:.9rem;text-decoration:none;border:1px solid var(--border-mid);transition:all .25s}
.btn-o:hover{border-color:var(--a);color:var(--a)}
.sec{padding:5.5rem 4%;max-width:1200px;margin:0 auto}
.sec.alt{background:var(--bg-alt);max-width:none;padding-left:max(4%,calc((100% - 1200px) / 2));padding-right:max(4%,calc((100% - 1200px) / 2))}
.stag{font-family:'Space Mono',monospace;font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.22em;color:var(--a);margin-bottom:1rem;display:inline-block}
h2{font-size:clamp(1.8rem,2.8vw,2.5rem);font-weight:800;letter-spacing:-.032em;line-height:1.1;margin-bottom:.9rem;max-width:720px;color:var(--text)}
h2 em{font-style:normal;color:var(--a)}
.sd{color:var(--text-soft);font-size:1rem;line-height:1.65;max-width:640px;margin-bottom:3rem}
.g2{display:grid;grid-template-columns:repeat(2,1fr);gap:1.2rem}
.vpcard{background:var(--surface);border:1px solid var(--border);border-radius:14px;padding:1.8rem;box-shadow:var(--shadow);transition:all .3s;position:relative}
.vpcard::before{content:'';position:absolute;top:0;left:0;width:3px;height:100%;background:var(--a);border-radius:14px 0 0 14px}
.vpcard h3{font-size:1.1rem;font-weight:700;margin-bottom:.6rem;color:var(--text)}
.vpcard p{font-size:.9rem;color:var(--text-soft);line-height:1.65}
.apps-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:1.2rem;margin-top:2rem}
.appcard{background:var(--surface);border:1px solid var(--border);border-radius:14px;padding:1.8rem;transition:all .3s;text-decoration:none;color:inherit;display:block;box-shadow:var(--shadow);position:relative;overflow:hidden}
.appcard:hover{border-color:var(--a);transform:translateY(-3px);box-shadow:var(--shadow-h)}
.appcard.flagship{border:2px solid var(--a);background:linear-gradient(180deg,var(--a-soft) 0%,var(--surface) 100%)}
.flagship-tag{position:absolute;top:1rem;right:1rem;background:var(--a);color:#fff;font-family:'Space Mono',monospace;font-size:.6rem;font-weight:700;padding:.22rem .55rem;border-radius:100px;letter-spacing:.08em}
.appcard h3{font-size:1.1rem;font-weight:700;margin-bottom:.4rem;color:var(--text);letter-spacing:-.01em}
.appcard .app-tagline{font-size:.82rem;color:var(--a);font-weight:600;margin-bottom:.9rem;font-family:'Space Mono',monospace}
.appcard p{font-size:.86rem;color:var(--text-soft);line-height:1.6;margin-bottom:1rem}
.appcard-link{font-size:.82rem;color:var(--a);font-weight:600;text-decoration:none;display:inline-flex;align-items:center;gap:.3rem}
.cta{text-align:center;padding:4.5rem 2rem;margin:3rem 4% 2rem;background:var(--bg-alt);border:1px solid var(--border);border-radius:22px;max-width:1080px;margin-left:auto;margin-right:auto}
.cta p{color:var(--text-soft);max-width:560px;margin:0 auto 2rem}
footer{padding:2.5rem 4% 1.5rem;max-width:1200px;margin:2rem auto 0;border-top:1px solid var(--border)}
.foot-t{display:flex;justify-content:space-between;align-items:center;margin-bottom:1rem;flex-wrap:wrap;gap:1rem}
.foot-t .logo{font-size:1.1rem}
.foot-links{display:flex;gap:1.3rem;font-size:.85rem;align-items:center;flex-wrap:wrap}
.foot-links a{color:var(--text-soft);text-decoration:none;transition:color .2s;display:inline-flex;align-items:center;gap:.35rem}
.foot-links a:hover{color:var(--a)}
.foot-b{font-size:.74rem;color:var(--text-dim);font-family:'Space Mono',monospace;letter-spacing:.04em}
.foot-b a{color:var(--a);text-decoration:none}
@media(max-width:900px){h1{font-size:2.2rem}.g2,.apps-grid{grid-template-columns:1fr}.nav-r a:not(.btn-n):not(.theme-toggle){display:none}}
</style>
</head><body>
<nav>
<a class="logo" href="/"><span class="logo-dot"></span>WEVAL<span style="color:var(--a)">.</span></a>
<div class="nav-r">
<a href="/">Accueil</a>
<a href="/products/">Produits</a>
<a href="/marketplace">Marketplace</a>
<button class="theme-toggle" onclick="(function(){var c=document.documentElement.getAttribute('data-theme')==='dark'?'light':'dark';document.documentElement.setAttribute('data-theme',c);localStorage.setItem('weval-theme',c);})()" aria-label="Basculer theme jour/nuit"><svg class="icon-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41"/></svg><svg class="icon-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg></button>
<a href="#cta" class="btn-n">Demander une demo -></a>
</div>
</nav>
<section class="hero">
<div class="badge">{{BADGE}}</div>
<div class="suite-prefix">Suite {{SUITE_CODE}}</div>
<h1>{{HERO_A}}<br>{{HERO_B}}</h1>
<p class="sub">{{INTRO}}</p>
<div class="btns">
<a href="#apps" class="btn-p">Voir les {{N_APPS}} applications -></a>
<a href="/#contact" class="btn-o">Demander une demo</a>
</div>
</section>
<section class="sec">
<div class="stag">// Pourquoi cette suite</div>
<h2>Quatre atouts, <em>une meme promesse.</em></h2>
<p class="sd">Ce qui distingue la suite {{NAME}} des solutions fragmentees du marche.</p>
<div class="g2">{{VALUE_PROPS}}</div>
</section>
<section class="sec alt" id="apps">
<div class="stag">// Applications de la suite</div>
<h2>{{N_APPS}} applications, <em>interoperables.</em></h2>
<p class="sd">Chaque application est aussi consommable en standalone. Ensemble, elles constituent la suite {{NAME}} - amplification mutuelle des capacites.</p>
<div class="apps-grid">{{APPS_HTML}}</div>
</section>
<div class="cta" id="cta">
<div class="stag" style="text-align:center;display:block">// Commencer</div>
<h2>Deployer <em>{{NAME}}</em> chez vous.</h2>
<p>POC gratuit 2 semaines. MVP operationnel en 1 mois. Deploiement Enterprise complet en 3 mois. IA souveraine, donnees hebergees chez vous.</p>
<div class="btns">
<a href="/#contact" class="btn-p">Reserver un POC -></a>
<a href="/marketplace" class="btn-o">Voir le catalogue complet</a>
</div>
</div>
<footer>
<div class="foot-t">
<a class="logo" href="/"><span class="logo-dot"></span>WEVAL<span style="color:var(--a)">.</span></a>
<div class="foot-links">
<a href="/">Accueil</a>
<a href="/products/">Produits</a>
<a href="/marketplace">Marketplace</a>
<a href="/#contact">Contact</a>
<a href="https://www.linkedin.com/company/weval" target="_blank" rel="noopener" aria-label="LinkedIn"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M19 3a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h14zM8.339 18.337V9.886H5.67v8.451h2.669zM7.003 8.687a1.549 1.549 0 1 0 0-3.097 1.549 1.549 0 0 0 0 3.097zm11.335 9.65v-4.637c0-2.475-1.332-3.625-3.109-3.625-1.434 0-2.076.788-2.436 1.342v-1.152H10.12c.037.778 0 8.451 0 8.451h2.673v-4.72c0-.24.017-.48.088-.652.193-.479.631-.975 1.367-.975.964 0 1.35.734 1.35 1.811v4.537h2.672z"/></svg> LinkedIn</a>
</div>
</div>
<div class="foot-b">&copy; 2026 WEVAL Consulting &middot; Cabinet de conseil &amp; editeur IA souveraine &middot; Partenaire Ecosysteme SAP &middot; Huawei Cloud Certified &middot; <a href="https://www.linkedin.com/company/weval" target="_blank" rel="noopener">Suivez-nous sur LinkedIn -></a></div>
</footer>
</body></html>
HTML2;
}
function build_suite_page(string $slug): array {
if (!isset(SUITE_PAGES[$slug])) return ['ok' => false, 'slug' => $slug, 'error' => 'Unknown suite slug'];
$s = SUITE_PAGES[$slug];
$accent = ACCENTS[$s['accent']];
// Value props HTML
$vp_html = '';
foreach ($s['value_props'] as [$t, $d]) {
$vp_html .= sprintf('<div class="vpcard"><h3>%s</h3><p>%s</p></div>',
htmlspecialchars($t), htmlspecialchars($d));
}
// Apps HTML — check file_exists for clickable vs roadmap card
$apps_html = '';
foreach ($s['apps'] as $app_slug) {
$page_path = "/var/www/html/products/{$app_slug}.html";
$page_exists = file_exists($page_path);
// Pull display data : prefer PRODUCTS const, else use slug-derived name
if (isset(PRODUCTS[$app_slug])) {
$p = PRODUCTS[$app_slug];
$name = $p['name'];
$tagline = strip_tags($p['tagline']);
$desc = mb_substr(strip_tags($p['desc']), 0, 160);
if (mb_strlen(strip_tags($p['desc'])) > 160) $desc .= '...';
} else {
// Derive from slug
$name = ucwords(str_replace('-', ' ', $app_slug));
$tagline = 'Application de la suite';
$desc = 'Details a venir. Partie integrante de la suite ' . $s['name'] . '.';
}
$flagship_cls = ($app_slug === 'wevia-em') ? ' flagship' : '';
$flagship_tag = ($app_slug === 'wevia-em') ? '<span class="flagship-tag">FLAGSHIP</span>' : '';
if ($page_exists) {
$apps_html .= sprintf(
'<a class="appcard%s" href="/products/%s.html">%s<h3>%s</h3><div class="app-tagline">%s</div><p>%s</p><span class="appcard-link">Voir la fiche produit -&gt;</span></a>',
$flagship_cls, htmlspecialchars($app_slug), $flagship_tag,
htmlspecialchars($name), htmlspecialchars($tagline),
htmlspecialchars($desc)
);
} else {
// Roadmap card — no link, clear expectation setting
$apps_html .= sprintf(
'<div class="appcard%s" style="cursor:default;opacity:.92">%s<h3>%s</h3><div class="app-tagline">%s</div><p>%s</p><span class="appcard-link" style="color:var(--text-dim);font-family:\'Space Mono\',monospace;font-size:.68rem;letter-spacing:.08em">INCLUS DANS LA SUITE - FICHE PRODUIT A VENIR</span></div>',
$flagship_cls, $flagship_tag,
htmlspecialchars($name), htmlspecialchars($tagline),
htmlspecialchars($desc)
);
}
}
$desc_short = mb_substr(strip_tags($s['intro']), 0, 140);
$html = get_suite_template();
$vars = [
'{{SLUG}}' => $slug, '{{NAME}}' => $s['name'], '{{SUITE_CODE}}' => $s['full_name'],
'{{TAGLINE}}' => $s['tagline'], '{{BADGE}}' => $s['badge'],
'{{HERO_A}}' => $s['hero_a'], '{{HERO_B}}' => $s['hero_b'],
'{{INTRO}}' => $s['intro'], '{{DESC_SHORT}}' => $desc_short,
'{{VALUE_PROPS}}' => $vp_html, '{{APPS_HTML}}' => $apps_html,
'{{N_APPS}}' => (string)count($s['apps']),
'{{A_LIGHT}}' => $accent['light'], '{{A_DARK}}' => $accent['dark'],
'{{A_SOFT_L}}' => $accent['soft_l'], '{{A_SOFT_D}}' => $accent['soft_d'],
];
$html = strtr($html, $vars);
foreach (FORBIDDEN_TERMS as $term) {
$pattern = '/\b' . preg_quote($term, '/') . '\b/';
if (preg_match($pattern, $html)) return ['ok' => false, 'slug' => $slug, 'error' => "Forbidden term: $term"];
}
$target_dir = '/var/www/html/solutions';
if (!is_dir($target_dir)) @mkdir($target_dir, 0755, true);
$target = "$target_dir/{$slug}.html";
if (file_exists($target)) {
$gold_dir = '/opt/wevads/vault/gold-suite-pages-' . date('Ymd');
if (!is_dir($gold_dir)) @mkdir($gold_dir, 0755, true);
@copy($target, $gold_dir . "/{$slug}-" . date('His') . '.html');
return ['ok' => false, 'slug' => $slug, 'error' => 'File exists - zero ecrasement'];
}
$ok = @file_put_contents($target, $html);
if ($ok === false) return ['ok' => false, 'slug' => $slug, 'error' => 'Write failed'];
return ['ok' => true, 'slug' => $slug, 'file' => $target, 'bytes' => strlen($html), 'apps' => count($s['apps'])];
}
// ============================================================
// PRODUCTS INDEX BUILDER (/products/index.html)
// 4 flagships + 13 produits rebrandes + 7 suites
// ============================================================
const FLAGSHIPS = [
['wevia-em', 'purple', "L IA souveraine qui orchestre la valeur de bout en bout", "Orchestration multi-agents value chain. 930 agents, 9 metiers, POC 2 semaines."],
['wevia-master', 'teal', "L agent qui execute", "Agent IA autonome proprietaire. Scanne, execute, apprend sur votre domaine."],
['arsenal', 'gold', "Framework ERP Intelligence", "150+ ecrans modulaires. Brain Engine IA. Comble les 20% que votre ERP ne fait pas."],
['reachhcp', 'coral', "Base HCP mondiale consent-based", "Professionnels de sante verifies, segmentation fine, conformite RGPD et HDS."],
];
function get_index_template(): string {
return <<<'HTMLIDX'
<!DOCTYPE html>
<html lang="fr" data-theme="light"><head>
<link rel="icon" href="/favicon.ico" type="image/x-icon">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Produits WEVAL - 13 applications IA souveraine et 7 suites | WEVAL Consulting</title>
<meta name="description" content="Catalogue complet WEVAL : 4 flagships, 13 produits rebrandes, 7 suites metier. IA souveraine, conformite EU, Lean Six Sigma.">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=Space+Mono:wght@400;700&display=swap" rel="stylesheet">
<script>(function(){var t=localStorage.getItem('weval-theme')||'light';document.documentElement.setAttribute('data-theme',t);})();</script>
<style>
:root{--bg:#ffffff;--bg-alt:#fafbfc;--surface:#ffffff;--text:#1a1f3a;--text-soft:#5a6480;--text-dim:#8893a8;--border:rgba(26,31,58,.08);--border-mid:rgba(26,31,58,.14);--shadow:0 1px 3px rgba(26,31,58,.04),0 8px 24px rgba(26,31,58,.04);--shadow-h:0 2px 6px rgba(26,31,58,.06),0 16px 40px rgba(26,31,58,.08);--purple:#6f5cff;--teal:#0d9488;--gold:#b88a2e;--coral:#dc3e3e;--btn-p:#5b4cdb;--btn-p-h:#4a3dc4}
html[data-theme="dark"]{--bg:#05080f;--bg-alt:#080c18;--surface:#0c1222;--text:#edf2f7;--text-soft:#a8b4c8;--text-dim:#7a8ba5;--border:rgba(255,255,255,.06);--border-mid:rgba(255,255,255,.12);--shadow:0 1px 3px rgba(0,0,0,.3),0 8px 24px rgba(0,0,0,.3);--shadow-h:0 2px 6px rgba(0,0,0,.4),0 16px 40px rgba(0,0,0,.4);--purple:#7c5cfc;--teal:#00c9a7;--gold:#f0c674;--coral:#ff6b6b;--btn-p:#7c5cfc;--btn-p-h:#9277ff}
*{margin:0;padding:0;box-sizing:border-box}html{scroll-behavior:smooth}
body{font-family:'Inter',sans-serif;background:var(--bg);color:var(--text);-webkit-font-smoothing:antialiased;transition:background .3s,color .3s}
body::before{content:'';position:fixed;inset:0;background:radial-gradient(circle at 15% 10%,rgba(111,92,255,.06) 0%,transparent 40%),radial-gradient(circle at 85% 60%,rgba(13,148,136,.06) 0%,transparent 45%);pointer-events:none;opacity:.7;z-index:-1}
nav{position:fixed;top:0;width:100%;padding:1rem 4%;display:flex;justify-content:space-between;align-items:center;z-index:100;backdrop-filter:blur(20px);background:color-mix(in srgb,var(--bg) 85%,transparent);border-bottom:1px solid var(--border)}
.logo{font-weight:800;font-size:1.35rem;letter-spacing:-.035em;display:flex;align-items:center;gap:.5rem;color:var(--text);text-decoration:none}
.logo-dot{width:10px;height:10px;border-radius:50%;background:var(--purple);box-shadow:0 0 18px rgba(111,92,255,.25)}
.nav-r{display:flex;gap:1.6rem;align-items:center}
.nav-r a{color:var(--text-soft);text-decoration:none;font-size:.86rem;font-weight:500;transition:color .25s}
.nav-r a:hover{color:var(--purple)}
.btn-n{background:var(--btn-p);color:#fff;padding:.6rem 1.3rem;border-radius:8px;font-weight:600;font-size:.84rem;text-decoration:none;transition:all .2s;border:none;cursor:pointer}
.btn-n:hover{background:var(--btn-p-h);transform:translateY(-1px)}
.theme-toggle{width:38px;height:38px;border-radius:50%;background:var(--bg-alt);border:1px solid var(--border);display:inline-flex;align-items:center;justify-content:center;cursor:pointer;transition:all .2s;color:var(--text-soft)}
.theme-toggle:hover{border-color:var(--purple);color:var(--purple)}
.theme-toggle svg{width:18px;height:18px}
html[data-theme="light"] .icon-moon{display:none}html[data-theme="dark"] .icon-sun{display:none}
.hero{padding:8rem 4% 4rem;text-align:center;position:relative}
.badge{display:inline-flex;align-items:center;gap:.5rem;background:rgba(111,92,255,.08);border:1px solid rgba(111,92,255,.15);border-radius:100px;padding:.42rem 1.05rem;font-size:.72rem;font-weight:700;color:var(--purple);margin-bottom:2rem;font-family:'Space Mono',monospace;letter-spacing:.05em}
.badge::before{content:'';width:6px;height:6px;background:var(--purple);border-radius:50%;animation:pulse 2s infinite}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.35}}
h1{font-size:clamp(2.5rem,5vw,4.3rem);font-weight:800;line-height:1.04;letter-spacing:-.04em;max-width:960px;margin:0 auto 1.5rem;color:var(--text)}
h1 em{font-style:normal;background:linear-gradient(135deg,var(--purple),var(--teal));-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text}
.sub{font-size:clamp(1rem,1.2vw,1.1rem);color:var(--text-soft);max-width:720px;margin:0 auto 3rem;line-height:1.65}
.kpis{display:inline-flex;gap:3rem;flex-wrap:wrap;justify-content:center;margin-top:1rem}
.kpi{text-align:center}
.kpi-n{font-family:'Space Mono',monospace;font-size:1.8rem;font-weight:700;color:var(--purple)}
.kpi-l{font-size:.72rem;color:var(--text-soft);text-transform:uppercase;letter-spacing:.12em;margin-top:.3rem}
.sec{padding:5rem 4%;max-width:1200px;margin:0 auto}
.sec.alt{background:var(--bg-alt);max-width:none;padding-left:max(4%,calc((100% - 1200px)/2));padding-right:max(4%,calc((100% - 1200px)/2))}
.stag{font-family:'Space Mono',monospace;font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.22em;margin-bottom:1rem;display:inline-block}
.stag.p{color:var(--purple)}.stag.t{color:var(--teal)}.stag.g{color:var(--gold)}.stag.c{color:var(--coral)}
h2{font-size:clamp(1.8rem,2.8vw,2.6rem);font-weight:800;letter-spacing:-.032em;line-height:1.1;margin-bottom:.9rem;color:var(--text)}
h2 em{font-style:normal}
.sd{color:var(--text-soft);font-size:1rem;line-height:1.65;max-width:680px;margin-bottom:3rem}
.flag-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:1.2rem;margin-top:1.5rem}
.flag-card{background:var(--surface);border:2px solid var(--border);border-radius:16px;padding:2rem;transition:all .3s;text-decoration:none;color:inherit;display:block;box-shadow:var(--shadow);position:relative;overflow:hidden}
.flag-card::before{content:'';position:absolute;top:0;left:0;right:0;height:3px;background:var(--accent)}
.flag-card.p{--accent:var(--purple)}.flag-card.t{--accent:var(--teal)}.flag-card.g{--accent:var(--gold)}.flag-card.c{--accent:var(--coral)}
.flag-card:hover{transform:translateY(-4px);box-shadow:var(--shadow-h);border-color:var(--accent)}
.flag-tag{display:inline-flex;align-items:center;gap:.35rem;font-family:'Space Mono',monospace;font-size:.64rem;font-weight:700;letter-spacing:.15em;color:var(--accent);text-transform:uppercase;margin-bottom:1rem}
.flag-tag::before{content:'';width:6px;height:6px;background:var(--accent);border-radius:50%}
.flag-card h3{font-size:1.5rem;font-weight:800;letter-spacing:-.02em;margin-bottom:.4rem;color:var(--text)}
.flag-card .flag-tagline{font-size:.85rem;color:var(--accent);font-weight:600;font-family:'Space Mono',monospace;margin-bottom:.9rem}
.flag-card p{font-size:.92rem;color:var(--text-soft);line-height:1.6;margin-bottom:1rem}
.flag-card-link{font-size:.82rem;color:var(--accent);font-weight:600;text-decoration:none;display:inline-flex;align-items:center;gap:.3rem}
.prod-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:1rem;margin-top:2rem}
.prod-card{background:var(--surface);border:1px solid var(--border);border-radius:12px;padding:1.4rem;transition:all .25s;text-decoration:none;color:inherit;display:block;box-shadow:var(--shadow)}
.prod-card:hover{border-color:var(--purple);transform:translateY(-2px);box-shadow:var(--shadow-h)}
.prod-card h4{font-size:1rem;font-weight:700;margin-bottom:.3rem;color:var(--text);letter-spacing:-.01em}
.prod-card .suite-tag{font-size:.66rem;font-family:'Space Mono',monospace;font-weight:600;color:var(--text-dim);text-transform:uppercase;letter-spacing:.08em;margin-bottom:.55rem;display:block}
.prod-card p{font-size:.82rem;color:var(--text-soft);line-height:1.55}
.suite-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:1rem;margin-top:2rem}
.suite-tile{background:var(--surface);border:1px solid var(--border);border-radius:14px;padding:1.6rem 1.4rem;text-decoration:none;color:inherit;display:block;transition:all .25s;box-shadow:var(--shadow);position:relative;overflow:hidden;min-height:190px}
.suite-tile::before{content:'';position:absolute;top:0;left:0;width:100%;height:3px;background:var(--accent)}
.suite-tile.p{--accent:var(--purple)}.suite-tile.t{--accent:var(--teal)}.suite-tile.g{--accent:var(--gold)}.suite-tile.c{--accent:var(--coral)}
.suite-tile:hover{transform:translateY(-3px);border-color:var(--accent);box-shadow:var(--shadow-h)}
.suite-tile h4{font-size:1.02rem;font-weight:700;color:var(--text);margin-bottom:.5rem;letter-spacing:-.01em}
.suite-tile .suite-cnt{display:inline-block;font-family:'Space Mono',monospace;font-size:.66rem;font-weight:700;color:var(--accent);background:color-mix(in srgb,var(--accent) 10%,transparent);padding:.18rem .5rem;border-radius:4px;margin-bottom:.8rem;letter-spacing:.06em}
.suite-tile p{font-size:.82rem;color:var(--text-soft);line-height:1.55}
.cta{text-align:center;padding:4.5rem 2rem;margin:3rem 4% 2rem;background:linear-gradient(135deg,rgba(111,92,255,.04),rgba(13,148,136,.04));border:1px solid var(--border);border-radius:22px;max-width:1100px;margin-left:auto;margin-right:auto}
.cta p{color:var(--text-soft);max-width:560px;margin:0 auto 2rem}
.btn-p{background:var(--btn-p);color:#fff;padding:.95rem 2rem;border-radius:10px;font-weight:600;font-size:.9rem;text-decoration:none;transition:all .25s;display:inline-flex;align-items:center;gap:.4rem;box-shadow:0 4px 12px rgba(91,76,219,.25)}
.btn-p:hover{background:var(--btn-p-h);transform:translateY(-2px)}
.btn-o{background:transparent;color:var(--text);padding:.95rem 2rem;border-radius:10px;font-weight:500;font-size:.9rem;text-decoration:none;border:1px solid var(--border-mid);transition:all .25s;display:inline-flex;align-items:center;gap:.4rem}
.btn-o:hover{border-color:var(--purple);color:var(--purple)}
.btns{display:flex;gap:1rem;flex-wrap:wrap;justify-content:center}
footer{padding:2.5rem 4% 1.5rem;max-width:1200px;margin:2rem auto 0;border-top:1px solid var(--border)}
.foot-t{display:flex;justify-content:space-between;align-items:center;margin-bottom:1rem;flex-wrap:wrap;gap:1rem}
.foot-t .logo{font-size:1.1rem}
.foot-links{display:flex;gap:1.3rem;font-size:.85rem;align-items:center;flex-wrap:wrap}
.foot-links a{color:var(--text-soft);text-decoration:none;transition:color .2s;display:inline-flex;align-items:center;gap:.35rem}
.foot-links a:hover{color:var(--purple)}
.foot-b{font-size:.74rem;color:var(--text-dim);font-family:'Space Mono',monospace;letter-spacing:.04em}
.foot-b a{color:var(--purple);text-decoration:none}
@media(max-width:900px){.flag-grid{grid-template-columns:1fr}.prod-grid{grid-template-columns:1fr}.suite-grid{grid-template-columns:1fr 1fr}.nav-r a:not(.btn-n):not(.theme-toggle){display:none}}
@media(max-width:600px){.suite-grid{grid-template-columns:1fr}.kpis{gap:1.5rem}}
</style>
</head><body>
<nav>
<a class="logo" href="/"><span class="logo-dot"></span>WEVAL<span style="color:var(--purple)">.</span></a>
<div class="nav-r">
<a href="/">Accueil</a>
<a href="/products/">Produits</a>
<a href="/marketplace">Marketplace</a>
<button class="theme-toggle" onclick="(function(){var c=document.documentElement.getAttribute('data-theme')==='dark'?'light':'dark';document.documentElement.setAttribute('data-theme',c);localStorage.setItem('weval-theme',c);})()" aria-label="Basculer theme jour/nuit"><svg class="icon-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41"/></svg><svg class="icon-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg></button>
<a href="#flagships" class="btn-n">Voir les flagships -&gt;</a>
</div>
</nav>
<section class="hero">
<div class="badge">Catalogue produits WEVAL</div>
<h1>{{N_PRODS}} applications, <em>{{N_SUITES}} suites.</em><br>Une stack IA souveraine.</h1>
<p class="sub">De l orchestration multi-agents a l automatisation bureautique, de l intelligence pharmaceutique au marketing haute performance. Tout est propriete WEVAL, deployable chez vous, conforme RGPD et AI Act.</p>
<div class="kpis">
<div class="kpi"><div class="kpi-n">{{N_PRODS}}</div><div class="kpi-l">Produits rebrandes</div></div>
<div class="kpi"><div class="kpi-n">{{N_SUITES}}</div><div class="kpi-l">Suites metier</div></div>
<div class="kpi"><div class="kpi-n">4</div><div class="kpi-l">Flagships</div></div>
<div class="kpi"><div class="kpi-n">6sigma</div><div class="kpi-l">Qualite L99</div></div>
</div>
</section>
<section class="sec" id="flagships">
<div class="stag p">// Flagships</div>
<h2>Quatre <em style="color:var(--purple)">produits phares</em> qui portent la stack.</h2>
<p class="sd">Quatre applications qui structurent l offre WEVAL. Chacune se suffit a elle-meme, ensemble elles forment le coeur de la proposition de valeur.</p>
<div class="flag-grid">{{FLAGSHIPS_HTML}}</div>
</section>
<section class="sec alt" id="catalogue">
<div class="stag t">// Catalogue rebrandes</div>
<h2>{{N_PRODS}} produits <em style="color:var(--teal)">rebrandes, documentes, deployes.</em></h2>
<p class="sd">Toutes les applications WEVAL rebrandees depuis les fondations open source ou developpees in-house. Chaque fiche comporte : positionnement, KPIs, 6 a 9 capacites cles, integration dans une suite.</p>
<div class="prod-grid">{{PRODUCTS_HTML}}</div>
</section>
<section class="sec" id="suites">
<div class="stag g">// Suites metier</div>
<h2>{{N_SUITES}} suites pour <em style="color:var(--gold)">couvrir tous les metiers.</em></h2>
<p class="sd">Chaque application est aussi consommable en standalone. Regroupees en suites, elles amplifient mutuellement leur valeur. Choisissez l entree qui colle a votre contexte : par produit ou par suite.</p>
<div class="suite-grid">{{SUITES_HTML}}</div>
</section>
<div class="cta">
<h2>Pret a <em style="color:var(--purple)">tester</em> ?</h2>
<p>Demonstration personnalisee sur vos donnees. Diagnostic cas d usage, scoping technique, proposition POC en 45 minutes. POC gratuit 2 semaines. MVP 1 mois. Deploiement Enterprise 3 mois.</p>
<div class="btns">
<a href="/#contact" class="btn-p">Reserver un POC -&gt;</a>
<a href="/marketplace" class="btn-o">Voir la marketplace</a>
</div>
</div>
<footer>
<div class="foot-t">
<a class="logo" href="/"><span class="logo-dot"></span>WEVAL<span style="color:var(--purple)">.</span></a>
<div class="foot-links">
<a href="/">Accueil</a>
<a href="/products/">Produits</a>
<a href="/marketplace">Marketplace</a>
<a href="/#contact">Contact</a>
<a href="https://www.linkedin.com/company/weval" target="_blank" rel="noopener" aria-label="LinkedIn"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M19 3a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h14zM8.339 18.337V9.886H5.67v8.451h2.669zM7.003 8.687a1.549 1.549 0 1 0 0-3.097 1.549 1.549 0 0 0 0 3.097zm11.335 9.65v-4.637c0-2.475-1.332-3.625-3.109-3.625-1.434 0-2.076.788-2.436 1.342v-1.152H10.12c.037.778 0 8.451 0 8.451h2.673v-4.72c0-.24.017-.48.088-.652.193-.479.631-.975 1.367-.975.964 0 1.35.734 1.35 1.811v4.537h2.672z"/></svg> LinkedIn</a>
</div>
</div>
<div class="foot-b">&copy; 2026 WEVAL Consulting &middot; Cabinet de conseil &amp; editeur IA souveraine &middot; Partenaire Ecosysteme SAP &middot; Huawei Cloud Certified &middot; <a href="https://www.linkedin.com/company/weval" target="_blank" rel="noopener">Suivez-nous sur LinkedIn -&gt;</a></div>
</footer>
</body></html>
HTMLIDX;
}
function build_products_index(): array {
// Build FLAGSHIPS html (fetch page data from /products/*.html)
$flag_html = '';
$class_map = ['purple' => 'p', 'teal' => 't', 'gold' => 'g', 'coral' => 'c'];
foreach (FLAGSHIPS as [$slug, $color, $tagline, $desc]) {
$page = "/var/www/html/products/{$slug}.html";
if (!file_exists($page)) continue;
// Get display name from PRODUCTS const or derive
$name = isset(PRODUCTS[$slug]) ? PRODUCTS[$slug]['name'] : ucwords(str_replace('-', ' ', $slug));
$cls = $class_map[$color] ?? 'p';
$flag_html .= sprintf(
'<a class="flag-card %s" href="/products/%s.html"><div class="flag-tag">FLAGSHIP</div><h3>%s</h3><div class="flag-tagline">%s</div><p>%s</p><span class="flag-card-link">Voir la fiche produit -&gt;</span></a>',
$cls, htmlspecialchars($slug),
htmlspecialchars($name), htmlspecialchars($tagline), htmlspecialchars($desc)
);
}
// Build PRODUCTS grid (only rebranded ones from PRODUCTS const, excluding flagships already shown)
$flagship_slugs = array_column(FLAGSHIPS, 0);
$prod_html = '';
$prod_count = 0;
foreach (PRODUCTS as $slug => $p) {
if (in_array($slug, $flagship_slugs, true)) continue;
$page = "/var/www/html/products/{$slug}.html";
if (!file_exists($page)) continue;
$desc_short = mb_substr(strip_tags($p['desc']), 0, 120);
if (mb_strlen(strip_tags($p['desc'])) > 120) $desc_short .= '...';
$prod_html .= sprintf(
'<a class="prod-card" href="/products/%s.html"><span class="suite-tag">%s</span><h4>%s</h4><p>%s</p></a>',
htmlspecialchars($slug), htmlspecialchars($p['suite']),
htmlspecialchars($p['name']), htmlspecialchars($desc_short)
);
$prod_count++;
}
// Build SUITES grid
$accent_map = ['purple' => 'p', 'teal' => 't', 'gold' => 'g', 'coral' => 'c'];
$suite_html = '';
$suite_count = 0;
// 2 legacy SUITES first (wevia-enterprise, pharma-cloud) then extended SUITE_PAGES
foreach (SUITE_PAGES as $slug => $s) {
$page = "/var/www/html/solutions/{$slug}.html";
if (!file_exists($page)) continue;
$cls = $accent_map[$s['accent']] ?? 'p';
$n_apps = count($s['apps']);
$intro_short = mb_substr(strip_tags($s['intro']), 0, 110) . '...';
$suite_html .= sprintf(
'<a class="suite-tile %s" href="/solutions/%s.html"><div class="suite-cnt">%d APPS</div><h4>%s</h4><p>%s</p></a>',
$cls, htmlspecialchars($slug), $n_apps,
htmlspecialchars($s['name']), htmlspecialchars($intro_short)
);
$suite_count++;
}
$html = get_index_template();
$total_prods = count(FLAGSHIPS) + $prod_count;
$vars = [
'{{N_PRODS}}' => (string)$total_prods,
'{{N_SUITES}}' => (string)$suite_count,
'{{FLAGSHIPS_HTML}}' => $flag_html,
'{{PRODUCTS_HTML}}' => $prod_html,
'{{SUITES_HTML}}' => $suite_html,
];
$html = strtr($html, $vars);
// Doctrine 108 check
foreach (FORBIDDEN_TERMS as $term) {
$pattern = '/\b' . preg_quote($term, '/') . '\b/';
if (preg_match($pattern, $html)) {
return ['ok' => false, 'error' => "Forbidden term: $term"];
}
}
return ['ok' => true, 'html' => $html, 'bytes' => strlen($html),
'flagships' => count(FLAGSHIPS), 'products' => $prod_count, 'suites' => $suite_count];
}
";if (PHP_SAPI !== 'cli') { http_response_code(403); echo "CLI only"; exit; }
$action = $argv[1] ?? 'help';
switch ($action) {
case 'build':
$slug = $argv[2] ?? null;
if (!$slug) { echo "Usage: build SLUG\n"; exit(1); }
echo json_encode(build_page($slug), JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . "\n";
break;
case 'build_all':
$ok = 0; $fail = 0;
foreach (array_keys(PRODUCTS) as $slug) {
$r = build_page($slug);
if ($r['ok']) { $ok++; } else { $fail++; }
echo sprintf("[%s] %-20s %s\n", $r['ok'] ? 'OK' : 'XX', $slug,
$r['ok'] ? ($r['bytes'] . 'B, ' . $r['features'] . ' features, theme=' . $r['theme']) : $r['error']);
}
echo sprintf("\n=== %d OK · %d FAIL ===\n", $ok, $fail);
break;
case 'list':
foreach (PRODUCTS as $s => $p) echo sprintf("%-20s | %-25s | %s\n", $s, $p['suite'], $p['tagline']);
break;
case 'scan_forbidden':
$hits = scan_forbidden('/var/www/html');
if (!$hits) { echo "Aucune occurrence interdite trouvée.\n"; exit(0); }
foreach ($hits as $h) echo sprintf("FOUND: %s in %s\n", $h['term'], $h['file']);
echo sprintf("\n=== %d fichiers à nettoyer ===\n", count($hits));
break;
case 'validate':
$slug = $argv[2] ?? null;
if (!$slug) { echo "Usage: validate SLUG\n"; exit(1); }
$target = "/var/www/html/products/{$slug}.html";
if (!file_exists($target)) { echo "NOT FOUND: $target\n"; exit(1); }
$c = file_get_contents($target);
$report = [
'exists' => true, 'size' => strlen($c),
'has_doctype' => str_contains($c, '<!DOCTYPE html>'),
'has_title' => str_contains($c, '<title>'),
'has_og' => str_contains($c, 'og:title'),
'has_suite_link' => str_contains($c, '/solutions/'),
'has_theme_toggle' => str_contains($c, 'weval-theme'),
'light_by_default' => str_contains($c, 'data-theme="light"'),
'forbidden_hits' => [],
];
foreach (FORBIDDEN_TERMS as $t) {
$pattern = '/\b' . preg_quote($t, '/') . '\b/';
if (preg_match($pattern, $c)) $report['forbidden_hits'][] = $t;
}
$report['doctrine_108_pass'] = empty($report['forbidden_hits']);
echo json_encode($report, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . "\n";
break;
case 'build_suite':
$slug = $argv[2] ?? null;
if (!$slug) { echo "Usage: build_suite SLUG\n"; exit(1); }
echo json_encode(build_suite_page($slug), JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . "\n";
break;
case 'build_all_suites':
$ok = 0; $fail = 0;
foreach (array_keys(SUITE_PAGES) as $slug) {
$r = build_suite_page($slug);
if ($r['ok']) { $ok++; } else { $fail++; }
echo sprintf("[%s] %-20s %s\n", $r['ok'] ? 'OK' : 'XX', $slug,
$r['ok'] ? ($r['bytes'] . 'B, ' . $r['apps'] . ' apps') : $r['error']);
}
echo sprintf("\n=== %d OK - %d FAIL ===\n", $ok, $fail);
break;
default:
case 'build_index':
$r = build_products_index();
if (!$r['ok']) { echo json_encode($r) . "\n"; exit(1); }
$target = '/var/www/html/products/index.html';
if (file_exists($target)) {
$gold_dir = '/opt/wevads/vault/gold-products-index-' . date('Ymd');
if (!is_dir($gold_dir)) @mkdir($gold_dir, 0755, true);
@copy($target, $gold_dir . "/index-builder-" . date('His') . '.html');
}
// Write alongside — caller must unlock chattr + move to target
$tmp = '/tmp/products-index.html';
file_put_contents($tmp, $r['html']);
echo json_encode(['ok' => true, 'tmp' => $tmp, 'bytes' => $r['bytes'], 'flagships' => $r['flagships'], 'products' => $r['products'], 'suites' => $r['suites']], JSON_UNESCAPED_SLASHES) . "\n";
break;
echo "wevia-site-builder.php v3 (light+toggle, EM flagship, suites, LinkedIn)\n";
echo " build SLUG | build_all | build_suite SLUG | build_all_suites\n";
echo " list | scan_forbidden | validate SLUG\n";
}