Spec-Driven Development

À la demande de Fabrice, j'utilise l'IA pour tenter de créer un nouveau module. Je vais appliquer la technique SDD (Spec-Driven Development ou d'eveloppement orienté par les spécifications). Cette technique consiste à élaborer des fichiers texte (généralement du markdown) dans lesquels on va spécifier tous les éléments contextuels nécessaires au développement d'un application. Ces spécifications doivent être rigoureuses et vont servir à guide l'IA dans la génération du code.


Création d'un nouveau module

Je vais tester le SDD sur la création d'un nouveau module Vrai/Faux todd_vf très simple : une question est posée à l'observateur à laquelle on peut répondre "vrai" ou "faux". Il peut cliquer sur vrai ou faux pour répondre. L'observateur pourra aussi avoir accès au statistiques courantes de ce mini sondage.

Organisation

Nous allons utiliser deux fichiers :

  • un fichier sdd_architecture.md de spécifications générales qui servira de maître dans le guidage de l'IA. Nous y mettons :
    • un descriptif du contexte ;
    • le découpage du développement avec les différentes phases (qu'est-ce qui est de la responsabilité du l'agent IA et qu'est-ce qui relève de de celle du développeur) ;
    • une description générale de l'architecture à respecter ;
    • certains standards spécifiques concernant l'utilisation de certains composant. Nous y enjoignons aussi une documentaiton minimal sur le noyau de l'environnement dans lequel va évoluer l'extebsion TODD.
  • un fichier sdd_module_vf.md dédié aux spécifications du module. Il contiendra :
    • les métadonnées du module pour l'intégraiton à l'extension ;
    • un descriptif rigoureux des fonctionnalités désirées ;
    • le schéma de la base de donnée avec les propriétés sur lesquelles va reposer le fonctionnement du module ;
    • un descriptif de l'interface d'administration ;
    • un cas d'utilisation ;
    • une liste de tâches à l'attention de l'agent IA ;
    • une liste de critères d'acceptation ;
    • une liste de contraintes à respecter
    • des spécifications particulière liées au fonctionnement du modules (valeurs par défaut de certaines variables par exemple).

Comme on peut le voir, la rédaction de ces documents demande du temps, de la préparation et une certaine rigueur pour ne rien oublier.


Fichier maître sdd_architecture.md

Ce document définit les règles architecturales strictes pour la création de modules au sein de l'écosystème TODD (basé sur le framework MMI v3). Ce fichier sert de "langage de programmation Markdown" : un Agent IA (Gemini, Copilot, etc.) doit lire ce fichier et s'y conformer rigoureusement lors de la génération de code pour un nouveau module.

1. Contexte & Environnement Technique

  • Framework Core : Framework PHP maison "MMI" v3.
  • UI Admin et Vues publiques : Limitless 4.0 (Bootstrap 5).
  • Icônes : Phosphor Icons (ph- prefix).
  • Frontend Core : jQuery est massivement utilisé côté admin.
  • Database : MySQL. Les tables doivent obligatoirement utiliser le préfixe {DBPFX} (ex: SELECT * FROM {DBPFX}todd_contents).
  • Standard de référence : Le module todd_information est l'étalon-or MVC de l'écosystème.

2. Workflow Feature-First (SDD)

Le développement se fait en deux phases distinctes :

  1. Phase 1 (Agent IA) : L'Agent lit la spécification markdown du module (ex: sdd_weather.md). Il génère toute la plomberie MVC : Modèle de données, Contrôleurs, Assets externes, UI d'Administration (formulaire + comportement de la modale). Le rendu public (view.php) reste basique (fil de fer).
  2. Phase 2 (Développeur / Design) : Une fois la logique et les données accessibles, le développeur ou l'intégrateur se concentre exclusivement sur l'esthétique finale de la vue publique (view.php et view.css).

3. Architecture MVC Obligatoire

Chaque module todd_[nom] doit respecter l'arborescence suivante (exemple pris sur todd_information) :

plugins/todd/modules/todd_[nom]/
├── admin.php                    # Vue de l'UI d'administration (Formulaire + Conteneur Preview)
├── handler.php                  # Point d'entrée pour la validation et l'enregistrement
├── view.php                     # Vue publique (affichage sur la borne)
├── install.php                  # Transfert des éléments nécessaires au fonctionnement du module dans la base de données
├── controllers/
│   ├── admin.inc.php            # Contrôleur d'admin (chargement CSS/JS, hydratation)
│   ├── payload.inc.php          # Parsing du payload JSON et valeurs par défaut
│   └── view.inc.php             # Contrôleur public (récupération DB, chargement CSS)
├── models/
│   └── Todd[Nom]Model.php       # Classes PHP pour interagir avec la DB (séparation DB stricte)
└── assets/
    ├── css/
    │   ├── admin.css            # Styles purement spécifiques au formulaire métier
    │   └── view.css             # Styles de l'affichage public
    └── js/
        ├── admin.js             # Écouteurs d'événements jQuery pour l'UI d'admin du module
        └── script.js            # Logique front-end publique (si nécessaire)

4. Règles d'Implémentation Spécifiques

4.1 Modèle (Model)

Toutes les requêtes SQL propres au module doivent être encapsulées dans la classe Modèle (ex: models/ToddInformationModel.php). Le handler.php et le view.inc.php ne font qu'appeler ces méthodes statiques.

4.2 L'Aperçu en Direct (Live Preview)

Ne réinventez pas la roue pour la mise à l'échelle de l'aperçu ! Utilisez les composants Core existants de TODD, notamment le composant global ToddPreview (plugins/todd/assets/js/pages/components/preview.js).

Mise en place HTML dans admin.php :

<!-- Côté Droit : Aperçu -->
<div class="col-md-7">
  <div class="todd-preview-container" id="preview_bg_layer">
    <div class="todd-preview-overlay"></div>
    <div id="preview_scale_wrapper" class="todd-preview-scaler">
      <!-- Contenu spécifique au module ici (ex: logo, textes) -->
      <div class="todd-preview-content">
        <div id="preview_message_text"></div>
      </div>
    </div>
  </div>
</div>

Le composant Core ToddPreview détectera ces classes et s'occupera de la mathématique (calcul du ratio 1920x1080 et de la propriété transform: scale()). Le fichier admin.js du module ne s'occupe QUE d'écouter les inputs (ex: keyup sur un champ texte) pour injecter la valeur dans le #preview_message_text.

4.3 Valeurs par défaut et Initialisation

Le contrôleur d'administration (admin.php via admin.inc.php) DOIT injecter les valeurs par défaut officielles du module dans un attribut data-defaults encodé en JSON sur la div racine :

<div
  class="module-editor hidden"
  data-module="todd_[nom]"
  data-defaults="<?= htmlspecialchars(json_encode($default_payload)); ?>"
></div>

Lors de la création d'un nouveau contenu, admin.js lira cet attribut pour simuler un payload vierge parfait via l'événement local :

$("#form_edit_content").trigger("todd:module:load", [defaultData, "todd_[nom]"]);

4.4 Séparation des Assets

INTERDICTION FORMELLE d'écrire des balises <style> ou <script> en ligne dans view.php ou admin.php.

  • Utilisez le gestionnaire d'assets Core dans les contrôleurs (admin.inc.php ou view.inc.php) avec un cache-buster :
$css_v = filemtime(__DIR__ . '/../assets/css/view.css');
App::registerCSS('todd_[nom]_view', SITE_URL . 'plugins/todd/modules/todd_[nom]/assets/css/view.css?v=' . $css_v, false, false);
App::enqueueCSS('todd_[nom]_view');

4.5 Installation

Le fichier install.php est exécuté lors de l'activation du module pour l'enregistrer dans la base de données. L'Agent IA doit générer ce fichier en respectant le pattern d'idempotence suivant. Il doit dynamiquement récupérer les variables de nom, label et icône depuis la section "Méta-données" de la spécification du module courant (ex: sdd_module_vf.md).

Modèle de code obligatoire pour install.php :
<?php
// Ces valeurs doivent être injectées dynamiquement par l'Agent selon la spécification du module
$module_code = 'todd_[nom]';
$module_label = 'Titre du module';
$module_icon = 'ph-icone-specifiee';

// 1. Vérification de l'existence du module pour éviter les doublons
$check = $db->get1x1("SELECT id
                        FROM {DBPFX}todd_modules
                        WHERE code = :code",
    [':code' => $module_code]
);

// 2. Insertion si le module n'existe pas
if (!$check) {
    // Calcul automatique du prochain ordre d'affichage
    $maxOrder = $db->get1x1("SELECT MAX(sort_order) FROM {DBPFX}todd_modules") + 10;

    $sql = "INSERT INTO {DBPFX}todd_modules (code, label, icon, sort_order, is_active, requires_moderation)
            VALUES (:code, :label, :icon, :order, 1, 0)";

    $db->dml($sql, [
        ':code' => $module_code,
        ':label' => $module_label,
        ':icon' => $module_icon,
        ':order' => $maxOrder
    ]);
}

4.6 Gestion des Dates et Heures (Pickers)

Pour les modules nécessitant la sélection de dates ou d'heures (ex: todd_vf), il est impératif d'utiliser les composants natifs de la librairie Limitless 4.0 (Daterangepicker).

Règles d'implémentation :

  1. Dépendances : Enregistrez et enfilez moment et daterangepicker dans le contrôleur (admin.inc.php).
  2. UI HTML : Utilisez un seul champ de type text avec une icône ph-calendar pour l'interaction utilisateur.
  3. Payload natif : Maintenez les champs cachés (<input type="hidden">) séparés pour la date (YYYY-MM-DD) et l'heure (HH:mm). C'est ce que lira le modèle MVC natif.
  4. Synchronisation JS : Dans admin.js, écoutez l'événement apply.daterangepicker pour mettre à jour les champs cachés. Écoutez cancel.daterangepicker pour vider les champs.

Exemple de code dans admin.php :

<div class="col-md-12 form-group">
  <label>Date et heure de révélation</label>
  <div class="input-group">
    <span class="input-group-text"> </span>
    <input
      type="text"
      class="form-control daterange-time"
      id="input_vf_reveal_datetime"
      placeholder="Sélectionner une date et heure..."
    />
  </div>
  <!-- Payload natif pour le modèle MVC -->
  <input
    type="hidden"
    name="vf_reveal_date"
    id="payload_vf_reveal_date"
    value="<?php echo htmlspecialchars($vf_reveal_date); ?>"
  />
  <input
    type="hidden"
    name="vf_reveal_time"
    id="payload_vf_reveal_time"
    value="<?php echo htmlspecialchars($vf_reveal_time); ?>"
  />
</div>

5 ANNEXE : Documentation Technique MMI (Tiria Cpanel v3)

Cette partie regroupe les règles essentielles, l'architecture et le fonctionnement du noyau MMI.

5.1 Standards de Code

Conventions de Nommage
  • Classes : PascalCase (ex: class MaClasse {}).
  • Fichiers de Classe : camelCase avec préfixe class. (ex: class.maClasse.php).
  • Fonctions : camelCase (ex: function maFonction() {}).
  • Variables : camelCase ou snake_case (cohérence requise).
  • Droits (Constantes) : PascalCase avec verbe descriptif (ex: 'ViewUsers', 'DoAction').
  • Templates : snake_case (ex: nom_de_page.php).
  • Contrôleurs : snake_case avec extension .inc.php (ex: nom_de_page.inc.php).
  • Scripts/Webservices : snake_case avec extension .ws.php (ex: nom_de_page.ws.php).
  • Javascript : snake_case avec extension .js (ex: nom_de_page.js).
Structures de Classe
  • Nouveaux Objets : Toute nouvelle classe d'objet doit respecter la structure définie dans class.example.php.sample.
Règles d'Écriture
  • Indentation : Utiliser des tabulations, pas des espaces.
  • Accolades : Ouvrantes sur la même ligne (if($i == 1){).
  • Structure de contrôle :
    • case et break au même niveau d'indentation.
    • else/catch peuvent être à la ligne.
  • Espaces :
    • Facultatifs après mots-clés/parenthèses (if($i==1) ok).
    • Facultatifs autour des comparateurs ($i==1 ok).
    • Recommandés après les virgules dans les arguments (func($a, $b)).
  • Tags PHP : Toujours utiliser <?php, jamais <? (short tags désactivés).
  • Opérateurs Logiques : Utiliser || et &&, jamais OR ni AND.
  • Icônes : Toujours utiliser le format SVG <svg class="icon"><use href="#ph-icon-name" /></svg> (pas de balises <i>).

5.2 Architecture & Pattern Override

Arborescence du Projet

Liste des dossiers à la racine du projet et leur rôle :

  • api/ : Points d'entrée de l'API (génération de token, endpoints REST).
  • assets/ : Ressources statiques publiques (CSS, JS, images, polices).
  • controllers/ : Logique PHP des pages (appelés avant le rendu).
  • includes/ : Fichiers de configuration et d'initialisation du noyau (init.php, config.php).
  • languages/ : Fichiers de traduction (.po, .mo).
  • libraries/ : Classes PHP et bibliothèques tierces.
  • logs/ : Fichiers de log de l'application.
  • plugins/ : Modules d'extension (contiennent leur propre MVC).
  • scripts/ : Scripts autonomes, tâches CRON et WebServices (.ws.php).
  • templates/ : Vues et gabarits HTML/PHP.
  • tmp/ : Fichiers temporaires (cache, uploads en cours).
  • uploads/ : Stockage des fichiers persistants uploadés par les utilisateurs.
Pattern Override

MMI utilise un pattern "Core vs Override" pour permettre les mises à jour du noyau sans écraser les modifications projet.

Structure des Dossiers
  • core/ : Contient les fichiers originaux du framework.
  • Racine ou dossier parent : Contient les surcharges (overrides) du projet.
Logique de Fallback (Cascade)

Le système charge les fichiers dans cet ordre de priorité :

  1. Projet (templates/pages/ma_page.php)
  2. Plugin (plugins/mon_plugin/templates/pages/ma_page.php)
  3. Core (templates/core/pages/ma_page.php)

Cela s'applique aux :

  • Contrôleurs (controllers/)
  • Templates (templates/)
  • Assets JS (assets/js/)
  • Scripts/Webservices (scripts/ via .htaccess)
  • Librairies (libraries/ via checks file_exists)

5.3 Fonctionnement du Noyau (Kernel)

Cycle de Vie d'une Requête
  1. Init : includes/init.php initialise l'app, la DB, la session user.
  2. Routing : Basé sur les paramètres URL :
    • ?page= : Charge le contrôleur et le template correspondants.
    • ?param= : Paramètre secondaire (ex: edit, add).
    • ?option= : Paramètre tertiaire (ex: ID d'un item).
  3. Dispatch :
    • index.php charge le contrôleur (controllers/...).
    • Puis charge le header, le menu, la page (templates/...), et le footer.
Routing des Scripts (AJAX/WS)
  • Les scripts .ws.php dans scripts/ sont appelés directement.
  • Si un script n'existe pas à la racine, le .htaccess redirige vers scripts/router.php.
  • Le routeur cherche alors dans les Plugins puis dans le Core.
  • Tri : Les éléments de menu peuvent être ordonnés via la clé order.
  • Administration : Tout élément avec un order > 100 sera automatiquement placé dans la section administration.

5.4 Système de Plugins

Les plugins sont situés dans plugins/{id_plugin}/ et étendent les fonctionnalités sans toucher au core.

Structure d'un Plugin
  • plugin.json : Métadonnées et dépendances.
  • autoload.php : Chargé globalement si le plugin est actif (pour CSS/JS global, modifs menu).
  • install.php, activate.php, etc. : Scripts de cycle de vie.
  • controllers/, templates/, assets/ : Surchargent ou ajoutent des pages/composants.
Intégration
  • Pages : Un plugin peut déclarer être le "propriétaire" d'une page via la BDD.
  • Menu : Le fichier autoload.php peut injecter des entrées dans le tableau global $sidebarMenu.
  • Composants : App::loadComponent() cherche automatiquement dans les plugins actifs, ils doivent être nommés plugin_id.component_name pour êtres pris en charge.

5.5 Référence des Utilitaires (Classe App)

La classe App regroupe l'ensemble des méthodes utilitaires. Toute nouvelle fonction globale doit être ajoutée en étendant cette classe (dans libraries/client/class.app.php par exemple) et non plus dans des fichiers fnc.*.php.

Affichage & Traduction
  • App::__($s) : Alias de gettext.
  • App::_e($s) : Affiche une chaîne traduite.
  • App::_a($s, $arg, $echo=false) : Traduction avec arguments (sprintf).
  • App::_ae($s, $arg) : Affiche tradition avec arguments.
  • App::_n($sin, $plu, $nb, $echo=false) : Gestion des pluriels.
  • App::my_strftime($format, $timestamp) : Formatage de date (remplace strftime déprécié PHP 8.1+).
  • App::localDate($timestamp, $format, $custom) : Formate une date selon la locale du user.
  • App::accentsToHTMLEntities($str) : Convertit les caractères accentués en entités HTML.
  • App::getTranslation($name, $lng) : Récupère une traduction depuis un fichier JSON.
  • App::getLogo($context, $mode) : Récupère l'URL du logo approprié (SVG/PNG) selon le contexte.
Assets & Composants
  • App::registerCSS($name, $url, $path, $dep) : Enregistre une feuille de style.
  • App::registerJS($name, $url, $path, $dep) : Enregistre un script JS.
  • App::enqueueCSS($name) : Ajoute le CSS à la file d'attente de chargement.
  • App::enqueueJS($name, $place) : Ajoute le JS à la file d'attente (header/footer).
  • App::loadCSS($name) / App::loadJS($name) : Charge directement un asset enregistré.
  • App::registerJsVariable($name, $val) / App::registerJsVariables($arr) : Passe des variables PHP vers le JS.
  • App::minimize_css($css) : Minifie une chaîne CSS.
  • App::getExcerpt($text, $len) : Tronque un texte proprement.
  • App::buildCustomIconsSet() : Génère le sprite SVG des icônes demandées.
  • App::loadComponent($name) : Charge le contrôleur et les assets d'un composant.
  • App::displayComponent($name, $params) : Affiche le template d'un composant.
  • App::enqueueIcons($name...) : Ajoute des icônes à charger dans le set SVG de la page.
Templates & Rendu
  • App::getTemplate($tpl, $type, $subpath, $lng) : Récupère le contenu d'un fichier template.
  • App::getMailTemplate($tpl, $type, $lng) : Récupère un template d'email.
  • App::getPdfTemplate($tpl, $type, $lng) : Récupère un template PDF.
  • App::tplReplace($replace, $html) : Remplace des variables {{var}} dans une chaîne.
  • App::displayMenu($menu) : Affiche un menu récursivement (supporte tri order et classes).
Système & Config
  • App::getOption($name, $default) : Récupère une option (désérialisation JSON auto).
  • App::setOption($name, $value) : Définit une option (sérialisation JSON auto).
  • App::writeLog($file, $msg, $level) : Écrit dans les logs (avec rotation auto).
  • App::getVariable($name) : Récupère une variable globale (ou via Webservice).
  • App::getPage($page) : Récupère les infos d'une page (DB) et gère les métadonnées.
  • App::printCode($var) : Affiche un dump de variable pour débug (sauf en prod/si force).
  • App::getArrayVariable($arr, $key) / App::setArrayVariable(...) : Accès tableau via notation par point (dot notation).
  • App::compareValues($v1, $op, $v2) : Compare deux valeurs avec opérateur string (>, <, =, etc.).
  • App::getSSEVariable($file, $var) / App::setSSEVariable(...) : Échange de données pour Server-Side Events.
Sécurité & Utilisateurs
  • App::checkLogin($login) : Vérifie si un login existe.
  • App::checkPswd($login, $pass) : Vérifie le mot de passe.
  • App::checkRights($type, $right, $mask) : Vérifie un droit spécifique dans un masque binaire.
  • App::combineRightsStr($s1, $s2) : Fusionne deux chaînes de droits binaires.
  • App::getGravatar($email) : Récupère l'URL Gravatar.
  • App::tiriaCrypt($data, $key) / App::tiriaDecrypt($data, $key) : Chiffrement AES-256-GCM.
  • App::pswdgen($len, $specialchars) : Génère un mot de passe aléatoire.
  • App::pswdcreate($pswd) : Crée un hash de mot de passe.
Divers
  • App::sendMail($title, $html, $txt, $dest...) : Envoi d'email via PHPMailer.
  • App::redirectResponse($res, $page, $type) : Redirection avec message (AlertBox).
  • App::exitRedirection($page, $param, $option) : Redirection et arrêt du script.
  • App::createSlug($text) : Nettoie une chaîne pour URL.
  • App::evalMath($formula) : Évalue une expression mathématique.
  • App::my_date_diff($h1, $h2) : Calcule la différence entre deux dates.
  • App::secondsToLisible($sec) / App::bytesToLisible($bytes) : Formatage humain.
  • App::imageFixOrientation($img, $file) : Corrige l'orientation d'une image selon EXIF.

5.6 Règles de Développement Spécifiques

Plugins
  • ID Plugin : Le nom de dossier (ID) d'un plugin doit impérativement respecter le pattern ^[a-z0-9_-]+$.
  • Nommage : Les composants d'un plugin doivent être appelés via plugin_id.nom_composant.
Fonctions
  • Dépréciation : Les fichiers fnc.*.php ne doivent plus être créés.
  • Extension : Pour ajouter une fonction globale, surchargez la classe App dans libraries/client/class.app.php et ajoutez-y votre méthode statique public static function myFunc(). Cela permet d'appeler App::myFunc() partout.

5.7 Resources Externes


Fichier pour le module sdd_module_vf.md

Ce document est une spécification destinée à guider un Agent IA (Gemini) dans la création formelle d'un module TODD. Lisez le fichier sdd_architecture.md pour les règles d'architecture applicables.

1. Méta-données du Module

  • Code du Module : todd_vf
  • Titre (label) : Vrai/Faux
  • Icône Globale : ph-question

2. Objectifs et Fonctionnalités

Ce module permet la réalisation de quiz à réponse unique (Vrai/Faux). Une image peut-être associée à la question.

  • Interactivité :
    • Un clic/touch sur les boutons vraiou faux dans la vue publique permet de répondre à une unique question. L'utilisateur

Lorsque la période du vote est terminée (basée sur une date et une heure décidée lors de la création du contenu de type Vrai/Faux), les statistiques sont affichées.

3. Schéma de Données (Modèle)

Le champ payload_json dans {DBPFX}todd_contents devra stocker les clés suivantes :

  • vf_question (string) : La question posée.
  • vf_answer (string) : La réponse (vrai ou faux).
  • vf_image_question (string) : L'image associée à la question.
  • vf_image_bg (string) : L'image associée à la question.
  • vf_color_text (string) : valeur HEX de la couleur du texte.
  • vf_color_bg (string) : valeur HEX de la couleur du fond.
  • vf_stats_true (int) : Nombre de réponses vraies.
  • vf_stats_total (int) : Nombre total de réponses.
  • vf_reveal_date (datetime) : Date de révélation.
  • vf_reveal_time (time) : Heure de révélation.

Créez la classe models/ToddVfModel.php avec des méthodes statiques comme getPayloadById($db, $id) pour extraire spécifiquement le JSON.

4. Interface d'Administration (admin.php & admin.js)

L'interface de création/modification (colonne de gauche) comprendra :

  • Des champs texte pour écrire la question et la réponse.
  • Des boutons pour éventuellement uploader une image de question et une image de fond avec rappel du nom du fichier à côté du label (mettre Aucun si aucune image n'est sélectionnée).
  • Des color pickers pour décider des couleurs du texte et du fond.
  • Un date picker et un time picker pour décider de la date et l'heure de révélation.

L'Aperçu en Direct (Live Preview)

L'aperçu situé dans la colonne de droite utilisera obligatoirement le composant ToddPreview.

<div class="col-md-7">
  <div class="todd-preview-container" id="preview_vf_bg">
    <div class="todd-preview-overlay"></div>
    <div id="preview_vf_scale" class="todd-preview-scaler">
      <div class="todd-preview-content">
        <!-- Squelette statique pour la Phase Question -->
        <div class="vf-question-container">
          <h1 id="preview_vf_question">Question</h1>
          <img id="preview_vf_image_question" src="" alt="" />
        </div>
        <!-- Squelette statique pour la Phase Révéler laRéponse -->
        <div class="vf-answer-container">
          <h2 id="preview_vf_answer">Réponse</h2>
          <img id="preview_vf_image" src="" alt="" />
        </div>
        <!-- Squelette statique pour la Phase Statistiques -->
        <div class="vf-stats-container">
          <h2 id="preview_vf_stats">Statistiques</h2>
          <div class="vf-stats-true">
            <h3 id="preview_vf_stats_true">Vrais</h3>
            <p id="preview_vf_stats_true_count">0</p>
          </div>
          <div class="vf-stats-false">
            <h3 id="preview_vf_stats_false">Faux</h3>
            <p id="preview_vf_stats_false_count">0</p>
          </div>
          <!-- graphique en barres -->
          <div class="vf-stats-graph">
            <div class="vf-stats-graph-true">
              <div class="vf-stats-graph-true-count">0</div>
            </div>
            <div class="vf-stats-graph-false">
              <div class="vf-stats-graph-false-count">0</div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

Le Javascript (assets/js/admin.js) écoutera le changement de phase (Question, Réponse, Statistiques) et mettra à jour l'aperçu en conséquence.

Trois boutons sous le preview permettront de basculer entre les phases.

5. Cas d'utilisation

L'utilisateur voit à l'écran une question et deux boutons : Vrai et Faux. Il clique sur l'un des deux boutons. Le système enregistre la réponse et affiche les statistiques.

6. Instructions pour l'Agent IA

  • Crée les 3 dossiers de base (assets, controllers, models) et leurs sous-fichiers selon le standard MVC.
  • Dans admin.php, utilise des classes Bootstrap 5 (Limitless). Construit le formulaire à gauche et l'aperçu dynamique à droite avec todd-preview-container.
  • Gère les requêtes jQuery dans assets/js/admin.js pour hydrater l'aperçu et populer le payload lors de l'enregistrement.
  • Dans les contrôleurs, utilise absolument App::enqueueCSS() et cache-buster.
  • Génère un rendu sommaire dans view.php (Phase 2 viendra plus tard pour le CSS immersif).
  • Crée les fichiers CSS et JS nécessaires pour l'affichage public.
  • Utilise les classes Bootstrap 5 (Limitless) pour l'affichage public.

Ne générez aucun CSS complexe pour le moment, concentrez-vous sur la connexion des données et la validité du payload.

7. Crittères d'acceptation

  • Le module est fonctionnel.
  • Le module est conforme à l'architecture MVC.
  • Le preview dans l'admin est fonctionnel et correspond à la description.
  • Étant donné qu'un utilisateur clique sur 'Vrai', le contrôleur public doit appeler le modèle et faire un UPDATE en base de données pour incrémenter vf_stats_true et vf_stats_total.
  • Étant donné qu'un utilisateur clique sur 'Faux', le contrôleur public doit appeler le modèle et faire un UPDATE en base de données pour incrémenter UNIQUEMENT vf_stats_total.
  • Étant donné que l'utilisateur vient de voter, le contrôleur public doit afficher les statistiques (sans la réponse).
  • Étant donné que la date et l'heure de révélation sont atteintes, le contrôleur public doit afficher la question, la réponse et les statistiques.

8. Contraintes

  • Le module doit être conforme à l'architecture MVC.
  • Le module doit être conforme aux règles d'architecture de TODD.
  • Le module doit être conforme aux règles d'architecture de MMI v3.
  • Le module doit utiliser les composants de Limitless 4.0.
  • Le module doit utiliser les icônes de Phosphor Icons.
  • Le module doit vérifier la validité de la date et de l'heure de révélation (postérieures à la date et l'heure de création du contenu).

9. Addendum

Utiliser ce payload pour l'initialisation du module :

{
  "vf_question": "Posez votre question ici ?",
  "vf_answer": "vrai",
  "vf_image_question": "",
  "vf_image_bg": "",
  "vf_color_text": "#FFFFFF",
  "vf_color_bg": "#333333",
  "vf_stats_true": 0,
  "vf_stats_total": 0,
  "vf_reveal_date": "",
  "vf_reveal_time": ""
}