Référentiel des équipements de Scénario Studio
Technologie

Dans le moteur de Scénario Studio : architecture, données et invariants

Quatre couches et une règle de dépendance, seize tables, des invariants tenus par la base plutôt que par la vigilance, et un millier de tests qui tournent sans rien installer.

Scénario Studio est une application web unique, servie par un seul processus, sans interface monopage ni étape de compilation JavaScript. Cet article décrit sa structure interne : les couches, les modules qui portent les décisions, le modèle de données, et surtout où sont tenus les invariants — car c'est là que se joue la fiabilité d'un outil qui écrit dans une maison réelle.

Quatre couches et une règle de dépendance

web/       écrans : routes et gabarits          → présentation
api/       points d'entrée JSON
services/  toute la logique métier               → décisions
ha/        dialogue avec le système domotique    → extérieur
models/    tables et schéma de données           → état

La règle tient en une ligne : web et api appellent services ; services appelle ha et models ; jamais l'inverse. Un écran ne construit pas de YAML et n'ouvre pas de connexion réseau — il demande à un service.

La conséquence est directement utile : la logique se teste sans écran et sans réseau. Le générateur est un module pur qui transforme une période et un planning en configurations d'automatisations, sans rien envoyer nulle part. Le validateur aussi : on lui passe le constat déjà formulé — « cette entité ne répond pas » — il ne sait pas interroger la base. Ce qui n'a pas d'effet de bord se teste exhaustivement pour presque rien.

Les modules qui portent les décisions

  • Le générateur traduit une période en automatisations. Ses identifiants sont déterministes — dérivés par UUID v5 des éléments d'origine — ce qui garantit qu'un même scénario produit toujours les mêmes identifiants, et donc que les différentiels entre deux déploiements restent lisibles.
  • Le validateur applique quatorze règles sur trois niveaux de gravité.
  • Le simulateur de journée rejoue une journée complète pour en déduire l'état de chaque équipement heure par heure. C'est lui qui permet d'affirmer « ce volet reste ouvert toute la nuit » — une propriété qu'on ne peut pas lire dans la liste des étapes, il faut la calculer.
  • La grille est une mise en page pure : 76 créneaux de quinze minutes, de 5 h à minuit. Aucune logique métier, donc aucune surprise à l'affichage.
  • Le garde-fou filtre toute écriture et toute suppression vers le système domotique.

Le modèle de données

Seize tables, regroupées par rôle : le matériel (miroir des entités du système domotique et référentiel métier des équipements), le planning (plannings, jours-types, affectations, étapes, actions), le contrôle (routines, conditions, actions, placement dans un planning), l'application dans le temps (périodes, exceptions de date, historique des déploiements avec l'instantané de ce qui a été écrit) et l'exploitation (comptes, journal d'audit).

Le temps : deux notions à ne jamais confondre

Les heures d'un planning sont des heures d'horloge, stockées sans fuseau : « 22:30 » signifie 22 h 30 à la pendule, avant comme après un changement d'heure. Les instants techniques — dernière synchronisation, date d'un déploiement, connexion — utilisent un type dédié qui refuse bruyamment une valeur sans fuseau et rend toujours de l'UTC.

Confondre les deux est l'erreur classique du domaine, avec un symptôme désagréable : tout fonctionne huit mois par an. Un test dédié couvre spécifiquement le passage à l'heure d'été.

Des invariants tenus par la base, pas seulement par le code

  • une seule période déployée à la fois — index unique partiel ;
  • un identifiant de connexion local unique — index unique partiel ;
  • une fermeture temporisée a forcément une durée — contrainte de vérification ;
  • une routine sur plage horaire a forcément deux bornes — contrainte de vérification.

Validateur affichant ses avertissements dans l'éditeur

Le validateur et le simulateur de journée travaillent en amont de tout envoi : les avertissements affichés en tête d'éditeur sont calculés à chaque enregistrement.

Le raisonnement est simple : une règle appliquée par le code peut être contournée par le prochain chemin d'écriture que l'on ajoutera. Une règle appliquée par le moteur de base de données ne peut pas l'être.

Un déploiement qui ne laisse pas d'état bâtard

Écrire dans un système extérieur, c'est accepter qu'il refuse. Le déploiement est donc enregistré en attente, puis confirmé ou marqué en échec : un appel refusé n'écrase jamais la trace du déploiement précédent. On sait toujours ce qui est réellement en place, y compris après une panne réseau au mauvais moment.

Mille quatorze tests, sans rien à installer

L'exigence tenue depuis le début : la suite s'exécute sans système domotique, sans base préexistante et sans fichier de configuration. Quatre décisions le permettent.

  • Une fausse instance domotique sert les mêmes réponses qu'une vraie, en HTTP comme en WebSocket. Elle contient délibérément les pièges qui comptent : un volet dont le nom ne correspond pas à sa pièce, une entité indisponible, un éclairage branché sur une prise, un capteur de batterie en pourcent qu'il ne faut pas confondre avec une humidité.
  • Le vrai client est exercé, pas contourné : c'est le même code qui parle au simulateur et à la maison. Un test qui court-circuite le client ne prouve rien sur le client.
  • Les migrations sont testées par la vraie ligne de commande, dans un sous-processus. Le test le plus utile de toute la suite vérifie qu'aucune dérive n'existe entre le schéma décrit par le code et celui produit par les migrations — l'oubli le plus fréquent du quotidien.
  • L'isolement est explicite : base en mémoire, fichiers de réglages, de journal et d'environnement déroutés vers des chemins jetables. Deux de ces déroutages doivent être posés avant l'import de l'application, parce que la configuration et le journal sont lus à ce moment-là.

Les tests portent aussi sur les messages : ils sont en français et disent quoi faire. Vérifier qu'un refus explique la marche à suivre a autant de valeur que vérifier un calcul — c'est ce qui distingue un outil utilisable d'un outil correct.

Ce que cette structure permet

Une couverture de test à la mesure du code applicatif, qui n'est pas un objectif chiffré : elle vient de ce que chaque défaut trouvé a donné lieu à un test qui l'empêche de revenir. Et surtout la possibilité de reprendre le projet dans six mois — ou par quelqu'un d'autre — en modifiant une règle métier sans avoir à comprendre comment un écran est dessiné.

Retour au blog