Pulse — guide technique
Pour les mainteneurs du paramétrage, des réponses par lien partagé et des notifications. Les constats d’implémentation sont Vérifiés dans le code local ; la parité déployée est Non vérifiée. Voir Fonctionnel et Configuration.
Architecture et responsabilités
Implémentation legacy : Symfony, Twig, jQuery/Ajax et Doctrine. Les chemins suivants sont relatifs à smartmobility-legacy.
Compte entreprise → Setting → Pulse + Assessment(type=pulse)
├─ PulseUser → User / School (population d’invitation)
├─ Email(entity=pulse) → commande planifiée → transport mail
└─ lien hash partagé → questionnaire externe → PulseForm
└─ PulseFormAnswer → AssessmentQuestion
Synthèse entreprise → participants + formulaires + dates/durées
| Composant | Responsabilité |
|---|---|
src/Company/PulseBundle/Controller/DefaultController.php | Liste/synthèse, brouillon immédiat, informations, questionnaire, population et planification. |
src/Company/PulseBundle/Resources/views/Default/ | Assistant et synthèse ; verrou de sélection dans assessment.html.twig. |
src/External/PulseBundle/Controller/DefaultController.php | Résolution du hash, accès au formulaire et persistance des réponses. |
src/External/PulseBundle/Resources/views/Default/test.html.twig | Types de questions, durée, soumission Ajax. |
src/Main/ConfigBundle/Entity/Pulse*.php et mappings Doctrine | Campagne, invitation, formulaire et réponse. |
src/Command/Notifications/EmailProgramationCampaignCommand.php | Emails planifiés des campagnes publiées. |

L’étape limite le sélecteur Assessment aux formulaires Pulse et aucune trame n’est sélectionnée. Un formulaire Pulse éligible doit être disponible pour être rattaché ; ce sélecteur vide n’est pas le questionnaire répondant. Observé dans l’application : assistant accessible malgré l’absence de Pulse dans le menu Performance visible. Interface anglaise, avec le sélecteur Assessment tel qu’il a été observé.
Contrats et circulation des données
config/routes.yaml monte les bundles sous /company/pulse et /external/form. Il s’agit de contrats du navigateur legacy, sans version d’API publique. Hors entrée externe GET, le fichier de routes ne restreint généralement pas la méthode ; les méthodes ci-dessous décrivent l’appel ou le handler.
| Opération | Requête | Résultat |
|---|---|---|
| Liste/synthèse | Entreprise /{id}, ID optionnel | Liste tenant ou campagne ; redirection si absente. |
| Création | Navigation entreprise /new | Persistance immédiate Draft puis /parameters/{id}. |
| Informations | POST /update | Formulaire Symfony et métadonnées ; JSON succès ou erreur. |
| Questionnaire | POST /assessment, pulse, assessment | Affectation ; entité absente → not-found. |
| Population | POST /userupdate, pulse, collaborateur[] | Synchronisation d’une sélection non vide ; précondition fin → HTTP 412 possible. |
| Email prévu | /notifications/{id}, formulaire event=create | Persistance Email puis rendu de la planification. |
| Entrée répondant | GET externe /{hash} | Questionnaire ou écran d’indisponibilité/déjà répondu. |
| Soumission | Ajax externe /success | Formulaire/réponses ; requête non Ajax → HTTP 400. |
Exemple illustratif de mise à jour, sans jeton : utiliser le formulaire rendu et son jeton CSRF.
pulse[pulse_id]=<campaign-id>
nameCampaign=Point equipe
descriptionCampaign=Questionnaire court
statusCampaign=brouillon
start_date=02/11/2026&start_hour=09:00
end_date=09/11/2026&end_hour=18:00
Les mutations renvoient souvent {"response":"success"}. La validation des informations peut renvoyer {"response":"error","message":"Erreurs de validation","errors":["…"]} sans statut HTTP d’erreur explicite. Examiner le corps : le callback de succès du template ne garantit pas la bonne remontée de chaque erreur métier.
La soumission externe utilise pulse=<shared-hash>, duration et name_<question-id>. Les sélections multiples utilisent des tableaux ; certains choix utilisent name_<question-id>_<item-id>. Une valeur scalaire produit une réponse, un tableau plusieurs réponses, et une sélection vide peut produire une réponse nulle. Ces exemples décrivent l’implémentation sans contourner le formulaire.
Modèle et cycle de vie
| Entité | Données |
|---|---|
Pulse | Setting, School, Assessment ; nom, description, target, statut, création/début/fin, hash ; users et forms. |
PulseUser | Pulse, User, School ; updated, done/date, hash. Initialisé à done=false. |
PulseForm | Pulse ; création, durée, hash de réponse généré ; collection answers. Pas de relation User directe. |
PulseFormAnswer | PulseForm, AssessmentQuestion ; texte nullable. |
La création écrit avant la complétion de l’assistant. updateAction recherche la campagne par Setting, traite le formulaire, parse d/m/Y H:i dans le fuseau serveur par défaut puis persiste les métadonnées.
Le GET externe vérifie dates absentes, début futur/brouillon, fin passée et cookie. Le save vérifie Ajax et cookie, écrit un cookie de 30 jours et crée formulaire/réponses, sans marquer de participant done. Le flush est dans la branche questionnaire contenant des questions ; ne pas supposer qu’un questionnaire vide produit une réponse durable.
La synchronisation des participants ne s’exécute que si collaborateur n’est pas vide. Une requête vide n’est pas une méthode vérifiée de suppression de toute la population. Les compteurs de population et de formulaires sont distincts et ne prouvent pas la complétion nominative.
Configuration, droits et coexistence
Menu : module_pulse_bo et module_pulse_view, ou repli sur permissions vides. Création : pulse_create ; synthèse : accès racine également autorisé. Plusieurs écrans comparent le Setting courant et celui de la campagne, mais les contrôles diffèrent selon l’action. La visibilité du menu n’est pas une preuve de contrôle complet des endpoints.
Le sélecteur liste les Assessments tenant de type pulse. Le template bloque la sélection après début/publication ou réponse ; le handler d’affectation ne répète pas ce verrou et ne revérifie pas explicitement type/tenant de l’Assessment sélectionné dans la méthode inspectée. C’est une règle de présentation.
La recherche dans nextgen-front, nextgen-back et AIHub n’a pas identifié de module Pulse dédié, appel AI, job d’inférence ni pont de migration. La conclusion porte sur les sources inspectées, pas sur chaque déploiement.
Exécution, notifications et observabilité
Dépendances : application Symfony legacy, base Doctrine, ressources Twig/jQuery et définitions des questionnaires. Les emails exigent transport configuré et exécution planifiée de EmailNotification:Campaign. Fréquence et câblage du scheduler Non vérifiés.
La commande obtient les emails dus via EmailRepository::getCurrentScheduledEmail(). sendPulseEmail exige Published, déduplique les adresses de participants, remplace prénom/nom, envoie le HTML puis renseigne sendedDate. Le handler ne filtre ni complétion ni fenêtre de réponse. Pour diagnostiquer : sélection des emails dus, statut, population, transport et horodatage. Ne pas exécuter cette commande sur une population réelle pour une simple vérification documentaire.
L’éditeur observé annonce [[formLink]], mais le sender inspecté ne remplace explicitement que [[firstname]] et [[lastname]]. Traitement complémentaire Non vérifié ; contrôler le message livré avant de s’appuyer sur cette variable.
Échecs et points d’extension
Constats Vérifiés dans le code, effet en production Non vérifié :
- Entrée et save externes déréférencent Pulse avant leur contrôle d’absence ; un hash inconnu peut échouer avant l’erreur prévue.
- Le save ne répète pas les contrôles date/statut du GET et n’établit pas l’appartenance à la population.
- Cookie de 30 jours : aucune unicité persistante par personne garantie.
- Compteur de description 500 contre mapping 255 ; schéma réel à vérifier, avec surcoût du HTML.
- Dates/questionnaire absents, fuseau, questionnaire vide et traitement JSON peuvent produire un résultat incomplet ou trompeur.
- Certains anciens templates de tableau référencent des routes absentes du fichier de routes Pulse inspecté : leur présence ne prouve pas un reporting/export pris en charge.
Pour étendre : aligner rendu et persistance de chaque type de question, contrôler droits/tenant/type côté écriture et valider l’intégrité des réponses avant de changer schéma ou sélection. Ce sont des recommandations, pas des garanties déjà implémentées.
Confidentialité, preuves et limites
Les invitations identifient les employés. Les formulaires n’ont pas de relation utilisateur directe mais conservent dates, durée et contenu. Traiter les liens partagés comme des éléments donnant accès ; ne pas documenter de vrais hashes ni garantir anonymat ou complétion individuelle. Les relations campagne-users/forms et form-answers utilisent cascade: [all] ; restauration non vérifiée.
Sources : composants ci-dessus ; config/routes.yaml ; routes des deux bundles ; src/Main/ConfigBundle/Resources/config/doctrine/Pulse*.orm.yml ; src/Company/PulseBundle/Form/Type/PulseType.php ; web/assets/js/pulse-characters-limitation.js ; app/Resources/views/core_company_theme_v3.html.twig.
Observé dans l’application, le 25 octobre 2026 : vérification exclusivement sur PS Testing 2026 avec Jim Carter. Pulse était absent du menu Performance visible, mais /company/pulse ouvrait Engagement campaign Pulse, initialement sans campagne. Création et enregistrement du brouillon Documentation - Pulse - 2026-10-25 (331), puis réouverture pour vérifier sa persistance. La synthèse indiquait zéro participant, zéro réponse et aucun questionnaire. Le sélecteur Assessment était vide ; la planification indiquait No notification scheduled. La fenêtre Schedule an email a été ouverte puis fermée sans enregistrement. Aucun participant ajouté, aucune publication et aucun email planifié. Soumission, livraison et verrouillage après démarrage non testés.
Non vérifié : versions serveur/schéma, exécution du scheduler, livraison, soumission, parité du code déployé et reporting au-delà de la synthèse vide observée.
Sources du guide fonctionnel
Ces références d’implémentation et de produit étayent le guide fonctionnel. Le code local n’établit pas la révision ou les options déployées. Les observations dans l’application restent distinctes du code et des sources documentaires.
Vérifié dans le code : smartmobility-legacy/src/Company/PulseBundle/Controller/DefaultController.php, ses vues Resources/views/Default/, src/External/PulseBundle/Controller/DefaultController.php et test.html.twig.
Dernière mise à jour : 3 novembre 2026