Skip to content

Superviseur — Supervision d'alarmes incendie Desautel ​

Logiciel professionnel de supervision en temps réel de centrales de détection incendie via les protocoles Modbus TCP et RTU, compatible avec les centrales INIS-E16 et AVISS.

Documentation : docs/README.md — index « quel document pour quel besoin ».

Notices :


Fonctionnalités clés ​

  • Supervision temps réel multi-centrales — état consolidé de l'ensemble du parc, mises à jour poussées par SignalR.
  • Compatibilité INIS-E16 et AVISS — Modbus TCP et RTU, y compris bus série multi-drop (plusieurs centrales partageant la même liaison).
  • Acquittement granulaire par type d'incident — feu, dérangement, hors-service, évacuation… traités indépendamment sur chaque zone et chaque point, un acquittement valant pour tout ce que son échelon contient : synthèse → zones → points.
  • États d'exploitation supervisés — neutralisation, mode manuel seul, arrêt d'urgence et inhibition remontés par zone et en synthèse générale, signalés dans le chrome de l'application par la couleur qui leur est propre, sans clignotement.
  • Plans interactifs — positionnement des zones et points sur le plan du site, statut en temps réel et tooltips détaillés ; chaque synthèse active d'une centrale dessine son anneau autour de son implantation.
  • Statistiques et rapports — agrégation par type d'événement, tendances, exports CSV et PDF.
  • Alerte sonore — signalisation audio différenciée par type d'incident et par état système, avec reprise après acquittement, doublée de retours sonores d'interface discrets et réglables à part.
  • Accès distant — supervision accessible à distance en complément du poste opérateur local.
  • Journal d'audit horodaté — chaque détection, acquittement et commande tracé en base PostgreSQL.
  • Sécurité — authentification JWT (session liée au processus), contrôle d'accès par rôles (RBAC), secret applicatif unique, fermeture du client protégée par mot de passe administrateur.

Fonctionnement global ​

Le Superviseur interroge en permanence les centrales incendie via le bus Modbus. Chaque centrale expose des tables de bits : un bit passe de 0 à 1 lorsqu'un événement se produit (alarme feu, dérangement, hors-service, etc.). Le logiciel détecte ces changements, les affiche en temps réel et permet aux opérateurs d'acquitter chaque incident individuellement.


Cycle de surveillance ​

Chaque centrale est supervisée par sa propre tâche, indépendante des autres : une centrale injoignable ne retarde pas la lecture des suivantes. À chaque cycle, la tâche lit les tables déclarées par le profil et compare l'état lu à l'état précédent.

RéglageValeurOù
Intervalle de cycle par défaut2 sSupervisionSettings:PollingIntervalSeconds — appsettings.json
Intervalle effectifpollingInterval de la configuration globale, en millisecondes, quand il est renseignéRéglages → Paramètres système, stocké en base
Plancher200 ms, appliqué quel que soit le réglageSupervisionSettings:MinPollingIntervalMs
Cycles de confirmation2SupervisionSettings:StateConfirmationCycles
Recul maximal après échecs consécutifs10 sSupervisionSettings:MaxReconnectBackoffMs

Tables Modbus — Ce qu'on surveille ​

Chaque centrale expose plusieurs tables de bits. Chaque table représente un type d'incident et chaque bit dans cette table correspond à un élément (zone, point, ou paramètre système). Les adresses ci-dessous font foi dans dotnet/shared/Profiles/StandardPanelProfiles.cs, lu par le backend comme par le simulateur.

TablePortéeINIS-E16AVISS
Paramètres système — bit 1 feu général, bit 2 dérangement général, puis défautsCentrale1, 25 bits1, 23 bits
Hors-service pointPoint9531001
Feu pointPoint20012001
Dérangement pointPoint30013001
Hors-service zoneZone40014001
Feu zoneZone50015001
Dérangement zoneZone60016001
Essai zoneZone70017001
Évacuation zoneZone80018001
Émission zoneZone80218021
DM extinction zoneZone80418041
Neutralisation zoneZone8061—
Mode manuel seul zoneZone8081—
Arrêt d'urgence zoneZone8101—
Inhibition zoneZone8121—
Écriture de commandeCentrale500500

La taille lue n'est pas la taille de la table. La fenêtre de lecture s'arrête au plus haut numéro de zone ou de point configuré sur la centrale, l'adressage pouvant être clairsemé — points 1 et 31 sans les intermédiaires. Une AVISS dont aucun point n'est configuré retombe sur une fenêtre de 508 points (PanelAdapterFactory).

Un même élément peut avoir plusieurs incidents simultanés. Par exemple, la Zone 3 peut avoir son bit à 1 dans la table Feu et dans la table Dérangement en même temps. Chaque type d'incident est traité indépendamment.

Changer une adresse ​

Toutes les valeurs du tableau vivent dans un seul fichier, dotnet/shared/Profiles/StandardPanelProfiles.cs, sous deux cartographies : InisE16 et Aviss. Le backend et le simulateur lisent la même, donc une adresse corrigée là s'applique des deux côtés au prochain build — il n'existe pas de seconde copie à tenir à jour. Les valeurs déclarées sont les adresses fil JBUS brutes, telles que la table d'échange les donne ; AddressOffset porte le décalage propre à la centrale et CommandTargetOffset celui des cibles d'écriture.

Deux positions de tête, à ne pas confondre. L'unité système n'occupe pas la tête de toutes les tables : le cahier dimensionne les tables de zones de base pour 999 zones, où une entrée de tête trouve sa place, et les tables d'exploitation pour les seize zones physiques, où il n'y en a pas.

FamilleAdressesChamp du profilZone physique 1
Zones de base — HS, feu, dérangement, essai4001 5001 6001 7001BaseZoneHeadOffset = 1seconde position — feu zone 1 = 5002
Zones d'exploitation — évacuation à inhibition8001 … 8121OperationZoneHeadOffset = 0première position — neutralisation zone 1 = 8061

Déplacer une adresse sans regarder à quelle famille elle appartient décale d'un cran tout ce que la table porte.

Le test à mettre à jour dans le même commit : ModbusProfileTests (dotnet/tests/backend/Domain/ValueObjects/)

Le reste — codes de commande, sens de lecture, ajout d'un type de centrale — est dans docs/project/PROFILS-MODBUS.md.


Cycle de vie d'un incident ​

Un incident naît quand un bit passe à 1 et suit un parcours précis jusqu'à sa disparition complète de l'écran.

Ce que voit l'opérateur à chaque étape ​

ÉtatCe qui s'afficheAction disponibleCe qui se passe en coulisse
ActifBadge rouge vif (ex. « Alarme feu »)Bouton AcquitterBit = 1, AckStatus = None
AcquittéBadge atténué + icône check—Bit = 1, AckStatus = SoftwareAcked
En attenteBadge vert + icône checkBouton EffacerBit = 0, AckStatus = HardwareCleared
RésoluDisparaît—Bit = 0 après acquittement

Le réarmement est une commande adressée à la centrale, pas à un incident : un seul bouton « Réarmer la centrale » apparaît sur la carte une fois tous ses états acquittés, et il est réservé au SuperAdmin — visible pour les autres rôles, qui savent ainsi qu'une action est attendue, mais inerte.


Acquittement par type d'incident ​

L'acquittement est granulaire : chaque type d'incident sur chaque élément est traité indépendamment. Acquitter le feu sur la Zone 3 ne touche pas au dérangement sur cette même zone.

Cascade hiérarchique ​

Un acquittement vaut pour tout ce que son échelon contient, et jamais pour ce qui le contient. Acquitter la synthèse d'une centrale entraîne les zones qu'elle résume, et par elles leurs points ; acquitter une zone entraîne ses points ; acquitter un point n'entraîne rien. L'effacement d'un état rétabli suit la même descente.

Chaque échelon entraîné est consigné au journal sous le nom de l'opérateur : l'acquittement est hérité, non automatique, et l'historique doit pouvoir en rendre compte. Une synthèse qui ne résume aucune zone — alimentation, liaison, communication — n'entraîne rien.

Un acquittement ne remonte jamais : acquitter un point laisse sa zone et la synthèse en l'état, car rien ne dit que les autres points de la zone ont été traités.


Hiérarchie des incidents ​

L'interface organise les incidents en 3 niveaux, du plus global au plus précis.


Traçabilité et journal d'audit ​

Chaque action est enregistrée dans la base de données avec horodatage, utilisateur et type d'événement.

MomentCe qui est enregistréExemple
DétectionType + localisationPanel-1 — Zone 3 — Fire Alarm Detected
AcquittementUtilisateur + typePanel-1 — Zone 3 Fire Alarm Acknowledged by john.doe
Réarmement hardwareTransition d'étatPanel-1 — Zone 3 — Fire Alarm Restored (Awaiting Ack)
RéapparitionMême incident revientPanel-1 — Zone 3 — Fire Alarm Reappeared
NettoyageFin de cyclePanel-1 — Zone 3 Fire Alarm Reset by john.doe

Architecture technique ​

Le code est réparti entre dotnet/ (les projets .NET), vue/ (l'interface web) et docs/ (la documentation) ; deployment/ et scripts/ portent l'outillage. Pour le détail de l'architecture, voir docs/project/ARCHITECTURE.md.

ComposantTechnologieRôle
dotnet/backendC# .NET 9, ASP.NET Core, EF Core, PostgreSQL (Npgsql), SignalRService Windows : polling Modbus, API REST, temps réel, journal d'audit
vueVue 3, TypeScript, Tailwind CSS, DaisyUI, PiniaInterface web bilingue (FR/EN) : tableau de bord, carte SVG, historique
dotnet/clientWPF .NET 9, WebView2Fenêtre native Windows redimensionnable ; interface servie depuis le disque (hôte virtuel), fermeture protégée par mot de passe administrateur
dotnet/managerWinForms .NET 9Gestionnaire de service (barre des tâches)
dotnet/simulatorWPF .NET 9Simulateur de centrale Modbus (interface graphique)
dotnet/simulator.coreC# .NET 9Cœur du simulateur : serveurs Modbus TCP/RTU, centrales, scénarios
dotnet/simulator.headlessC# .NET 9 (console)Simulateur sans interface, piloté par HTTP (tests de bout en bout)
dotnet/sharedC# .NET 9Modèles et configuration partagés
dotnet/license-generatorWPF .NET 9Générateur de licences (outil interne technicien)
dotnet/tools/TsEnumGeneratorC# .NET 9 (console)Génère vue/src/config/generated/enums.ts depuis les enums C# ; hors solution
dotnet/tests/xUnit (backend, client, manager, simulator, tools), Vitest (vue/src/), Playwright (vue/e2e/)Tests unitaires, d'intégration et de bout en bout
deployment/PowerShell + Inno Setup 6Compilation, packaging et installateur Windows — deployment/README.md
scripts/PowerShell, NodeGénération des enums TS, analyse SonarQube, plans de démonstration
docs/VitePress + DocFX + TypeDocPortail documentaire — docs/README.md

Chaque module porte son propre README : backend · frontend · client · gestionnaire de service · simulateur · shared · TsEnumGenerator · licences · tests .NET · scripts · déploiement.


Développement ​

Prérequis ​

OutilRequis pourNotes
SDK .NET 9Toutglobal.json épingle 9.0.100 (rollForward: latestFeature) : un SDK plus récent installé sans son runtime est ignoré
Node.js 20.19+ ou 22.12+Frontend, docsVoir engines dans vue/package.json
PostgreSQL 17Backendwinget install PostgreSQL.PostgreSQL.17. Le backend y puise initdb et pg_ctl pour monter son cluster de développement ; l'installateur y prend les binaires qu'il embarque
Runtime WebView2Client de bureauPrésent d'origine sur Windows 10 1803+ et Windows 11 ; l'installateur de production le pose si le poste ne le porte pas
Inno Setup 6InstallateurUniquement pour deployment\build-all.ps1 — voir deployment/README.md
Visual Studio 2022 ou JetBrains RiderConfortLa ligne de commande dotnet suffit
dotnet/backend/appsettings.Crypto.dev.jsonCodes revendeursCopier depuis appsettings.Crypto.dev.exemple.json. Facultatif : un dépôt fraîchement cloné démarre sans lui (voir La base PostgreSQL en développement)

Secret applicatif unique — Security:SuperAdminPassword (dans appsettings.Crypto.dev.json en développement, appsettings.Crypto.prod.json en production) sert à la fois au compte SuperAdmin desautel (haché BCrypt au premier démarrage) et au mot de passe du rôle PostgreSQL (injecté dans la chaîne de connexion au démarrage). Le service refuse de démarrer si ce secret est absent (aucune valeur par défaut). En production Windows, le fichier est scellé au repos via DPAPI dès le premier démarrage, en appsettings.Crypto.prod.protected. Aucun secret n'est embarqué dans l'installateur : l'opérateur le saisit à la première installation, et provision-admin-secret.ps1 l'applique au rôle PostgreSQL puis l'écrit dans appsettings.Crypto.prod.json sur le poste. Le fichier crypto livré porte un SuperAdminPassword vide ; seules les clés revendeurs y subsistent.

Premier lancement après un clone ​

powershell
git clone https://github.com/RD-Desautel/Superviseur.git
cd Superviseur

dotnet restore                        # solution .NET
cd vue && npm install && cd ..        # dépendances du frontend

dotnet run --project dotnet/backend   # crée le cluster PostgreSQL puis la base, API sur :5264

Le premier démarrage du backend construit le cluster, la base et le compte SuperAdmin desautel ; il prend quelques dizaines de secondes, les suivants sont immédiats. L'interface se lance à part, dans un second terminal (cd vue && npm run dev) : le proxy Vite dirige /api et /modbusHub vers :5264.

Lancement en mode développement ​

bash
# Backend normal (service + API sur :5264 en développement, :5000 en production)
dotnet run --project dotnet/backend

# Backend Demo (Fixtures à cumuler avec le mode charge du simulateur situé dans l'ui pour créer et lancer toutes les centrales de test)
dotnet run --project dotnet/backend --launch-profile "Superviseur.Api (démo)"

# Frontend (dans un autre terminal, HMR sur :5173)
cd vue && npm install && npm run dev

# Sous une marque revendeur, pour l'éprouver sans poste installé (compilation DEBUG seule)
dotnet run --project dotnet/backend -- --brand <identifiant>

Le front reçoit son habillage du service : l'argument suffit à voir l'interface entière sous la marque demandée. Le client de bureau et le gestionnaire lisent le même réglage par la variable d'environnement SUPERVISEUR_BRAND. Détail dans la marque blanche.

Les autres exécutables se lancent de la même façon, chacun dans son terminal :

ExécutableCommandeCe qu'il faut avoir démarré
Client de bureau (WPF)dotnet run --project dotnet/clientVite sur :5173 — en DEBUG le client charge le serveur de développement et vise l'API sur :5264
Simulateur de centrales (WPF)dotnet run --project dotnet/simulatorRien : il sert lui-même les centrales que le backend interroge
Simulateur sans interfacedotnet run --project dotnet/simulator.headlessRien : centrales de demo-fixtures.json, pilotage HTTP sur :7000
Gestionnaire de servicedotnet run --project dotnet/managerLe service Windows installé : le gestionnaire pilote Superviseur-Service, pas un backend lancé depuis le dépôt

En production, le client WPF charge l'interface depuis le disque via un hôte virtuel WebView2 (https://superviseur.local/) et appelle l'API du backend sur https://localhost:5000 ; en développement, il pointe sur le serveur Vite http://localhost:5173 (API proxifiée vers :5264).

La base PostgreSQL en développement ​

Le poste de développement monte son propre serveur PostgreSQL, indépendant de toute installation du Superviseur : au premier dotnet run, le backend initialise un cluster dans le profil de l'utilisateur et le démarre.

Cluster%LOCALAPPDATA%\Superviseur_Dev\pgdata
Port5433 — un service installé occupe le 5432
Base / rôlefiresupervisor / firesupervisor_app, créés au démarrage du backend
SecretSecurity:SuperAdminPassword, lu dans appsettings.Development.json
Journal%LOCALAPPDATA%\Superviseur_Dev\postgres.log

Les exécutables viennent d'une installation de PostgreSQL 17, déjà nécessaire pour construire l'installateur — qui y puise les binaires qu'il embarque (winget install PostgreSQL.PostgreSQL.17). Le serveur tourne sous le compte de l'utilisateur, sans service Windows.

Les deux emplacements connus sont ceux de l'installateur officiel, C:\Program Files\PostgreSQL\17\bin et son prédécesseur en 16. Un poste qui installe ailleurs — autre disque, version portable, droits refusés sur Program Files — désigne le sien par la variable d'environnement SUPERVISEUR_PG_BIN, qui passe devant :

powershell
$env:SUPERVISEUR_PG_BIN = "D:\pgsql\bin"

Le secret de développement est versionné dans appsettings.Development.json : il n'ouvre qu'un cluster local et n'a aucune valeur ailleurs. appsettings.Crypto.dev.json reste hors du dépôt, puisqu'il porte les clés revendeurs ; chargé après, il remplace ce secret dès qu'il existe. Un dépôt fraîchement cloné démarre donc sans ce fichier, qui n'est requis que pour éprouver les codes revendeurs.

Pour inspecter la base (extension PostgreSQL de VS Code, psql, DBeaver…) :

ParamètreValeur
Hôte / Serverlocalhost
Port5433 — dans l'extension VS Code, il se règle sous Advanced
Base / Databasefiresupervisor
Utilisateurfiresupervisor_app
Mot de passeSecurity:SuperAdminPassword de votre configuration de développement

Le mot de passe du rôle est le secret applicatif : le backend l'applique à PostgreSQL au démarrage. Lancez-le donc au moins une fois avant de vous connecter avec un outil externe.

Repartir d'une base vierge revient à supprimer le cluster ; le démarrage suivant le reconstruit :

powershell
& "C:\Program Files\PostgreSQL\17\bin\pg_ctl.exe" -D "$env:LOCALAPPDATA\Superviseur_Dev\pgdata" -m fast stop
Remove-Item -Recurse -Force "$env:LOCALAPPDATA\Superviseur_Dev"

Elle emporte tout le dossier : la base, mais aussi les plans téléversés, les sons remplacés et la clé de session. Supprimer le seul pgdata laisse ces derniers en place.

Si le démarrage échoue sur could not locate a valid checkpoint record, le journal des transactions du cluster a disparu — ses fichiers de données, eux, sont intacts. Le backend le constate au démarrage, repose un journal neuf avec pg_resetwal et réessaie : il n’y a rien à faire. Il ne s’y risque que sur un cluster arrêté proprement ; sinon il s’arrête en le disant, et forcer la réinitialisation — au risque d’une base incohérente — se fait à la main :

powershell
& "C:\Program Files\PostgreSQL\17\bin\pg_resetwal.exe" -f -D "$env:LOCALAPPDATA\Superviseur_Dev\pgdata"

Tests ​

bash
# Backend (xUnit)
dotnet test

# Frontend (Vitest)
cd vue && npm run test:run

# Bout en bout dans un navigateur (Playwright, local)
cd vue && npm run test:e2e

Les tests de bout en bout démarrent eux-mêmes le simulateur sans interface, le backend et Vite. Ils requièrent un PostgreSQL local et dotnet/backend/appsettings.Crypto.dev.json (prérequis de développement).

Le simulateur sans interface sert les centrales de demo-fixtures.json — le fichier dont le backend tire aussi son jeu de démonstration — et se lance seul pour développer sans l'interface graphique :

bash
# Toutes les centrales de démonstration, canal de pilotage sur :7000
dotnet run --project dotnet/simulator.headless

# Un sous-ensemble choisi
dotnet run --project dotnet/simulator.headless -- --panels demo-inis-01,demo-aviss-01 --control-port 7000

curl http://127.0.0.1:7000/sim/health                          # centrales servies
curl -X POST -d '' http://127.0.0.1:7000/sim/demo-inis-01/zone/3/fire   # poser une alarme
curl http://127.0.0.1:7000/sim/demo-inis-01/zone/3             # état réel de la centrale

Documentation ​

powershell
# Génération complète + serveur local sur http://localhost:3008/
.\docs\generate-docs.ps1 -Serve

# Sans l'API C# (plus rapide)
.\docs\generate-docs.ps1 -SkipBackend -Serve

# Développement avec hot-reload (guides + API TypeScript) — outillage docs sous docs/
cd docs && npm run docs:dev
SectionURLOutil
Portail et guideshttp://localhost:3008/VitePress
API TypeScripthttp://localhost:3008/api/TypeDoc
Référence C#http://localhost:3008/backend/DocFX

Build et déploiement ​

Superviseur ​

powershell
cd deployment
.\build-all.ps1

Le script compile tout en Release, télécharge le runtime WebView2 si nécessaire, embarque les binaires PostgreSQL 17 et génère Installer/Superviseur-Setup-<version>.exe via Inno Setup 6. Voir deployment/README.md pour les détails.

Le poste à équiper n'a besoin d'aucun prérequis. Les quatre exécutables sont publiés autonomes (runtime .NET inclus), PostgreSQL est embarqué avec ses bibliothèques — dont le runtime C de Visual C++, dont tous ses exécutables dépendent sans que sa distribution ne le livre —, et le runtime WebView2 n'est posé que si Windows ne le porte pas déjà. Un Windows 11 fraîchement installé suffit.

Outil de licences ​

Outil interne Desautel, publié par build-all.ps1 dans staging/license-tool/ et volontairement absent de l'installateur : les logiciels livrés ne contiennent que la clé publique de vérification.

powershell
dotnet publish dotnet/license-generator/LicenseGenerator.csproj -c Release -r win-x64 `
  --self-contained true `
  -p:PublishSingleFile=true `
  -p:IncludeNativeLibrariesForSelfExtract=true `
  -p:EnableCompressionInSingleFile=true `
  -p:DebugType=none `
  -p:GenerateDocumentationFile=false `
  -o staging/license-tool

Les quatre dernières options sont nécessaires au fichier unique : PublishSingleFile seul laisse à côté de l'exécutable les cinq bibliothèques natives de WPF, les symboles de débogage et la documentation XML.

Le poste à équiper n'a besoin d'aucun outil : le client de supervision et le gestionnaire de service produisent la demande d'activation et appliquent la licence reçue. Circuit complet, format et rotation des clés dans dotnet/license-generator/README-licences.md.


Sécurité et rôles ​

Le système implémente un contrôle d'accès strict (RBAC) avec authentification JWT. Trois rôles : le SuperAdmin (installateur/configurateur du site), l'Admin (exploitant avancé) et l'Utilisateur (opérateur). Le tableau suivant fait autorité — l'application applique ces droits côté frontend (visibilité) et côté backend (autorisation des endpoints).

FonctionSuperAdminAdminUtilisateur
Carte live, supervision, incidents, acquittements✅✅✅
Historique / rapports / statistiques (consultation)✅✅✅
Réseau INIS — consultation✅✅✅
Réseau INIS — édition (réseaux, matrices, assignations)✅✅❌
Commandes centrale hors réarmement (silence, hors/en service, essai)✅✅✅
Réarmement d'une centrale (reset, tout type)✅❌❌
Gestion des comptes (hors SuperAdmin)✅✅❌
Options générales (nom du site, apparence, sons, logo)✅✅❌
Paramètres systèmes, maintenance, réinitialisation d'usine✅❌❌
Configuration des centrales✅❌❌
Sauvegarde / restauration✅❌❌
Éditeur de plans✅❌❌
Export intégral de la base / suppression d'archives✅✅❌
Scanner Modbus & console de diagnostic✅❌❌

Le bouton « Réarmer » proposé après un acquittement reste visible pour tous (il signale que la centrale doit être réarmée) mais n'est cliquable que par le SuperAdmin ; pour les autres rôles il est inerte, sans curseur cliquable, afin d'être compris comme une instruction et non comme un dysfonctionnement.

Protections supplémentaires :

  • Chiffrement des fichiers de configuration INIS (algorithme SimpleCrypt Desautel)
  • Clés revendeurs et mots de passe sensibles dans appsettings.Crypto.{dev,prod}.json (non versionnés)
  • Fermeture du client protégée par mot de passe administrateur (autorisée sans mot de passe si le backend est injoignable)
  • Session liée au processus : déconnexion à la fermeture de la fenêtre, au redémarrage du poste, à la désinstallation/mise à jour ; maintien de la session en veille
  • Mot de passe SuperAdmin (compte desautel, également mot de passe du rôle PostgreSQL) saisi par l'installateur à la première installation ; voir la notice installateur.
  • Journal d'audit réglementaire inaltérable (traçabilité des actions sensibles, conservation cinq ans).

Sauvegarde et restauration ​

Le SuperAdmin exporte une archive ZIP qui porte la configuration du poste et les fichiers téléversés — logos, plans, sons. Elle contient les comptes, les centrales avec leurs zones et points, les plans, la configuration générale, les profils Modbus, les réseaux INIS, les modèles de rapport et les notes d'exploitation ; le journal des événements n'y entre que si on le demande.

En sont écartés, chacun pour une raison tenue à jour dans BackupCoverageTests : le journal d'audit réglementaire, qui retrace ce qui s'est produit sur cette machine et qu'une restauration ne réécrit pas ; l'état lu sur les centrales, reconstruit à la relecture de la configuration ; les mesures de qualité de liaison ; les rapports déjà produits, archivés à part et regénérables.

Une entité ajoutée à la base n'entre pas d'elle-même dans l'archive, et son absence ne se voit pas : l'export réussit, l'archive paraît complète, et la perte n'apparaît qu'à la restauration. Un contrôle porté sur le contexte de persistance échoue donc dès qu'une table n'est ni sauvegardée ni écartée avec son motif — voir les profils Modbus pour la marche à suivre quand on en ajoute une.

À la restauration, les profils livrés que l'exploitant n'a pas modifiés sont réalignés sur la cartographie du code. Une archive les fige tels qu'ils étaient le jour de son écriture, adresses comprises : sans ce réalignement, une correction d'adressage venue depuis serait défaite et le poste interrogerait les anciennes adresses jusqu'au redémarrage suivant du service. Un profil livré modifié sur site garde ce qu'on en a fait, exactement comme au démarrage.


Documentation Modbus ​

Les adresses de registres, les codes de commande et la carte GlobalBits — quels bits de synthèse chaque centrale sert — des centrales standard font foi dans une source unique en code, dotnet/shared/Profiles/StandardPanelProfiles.cs, partagée par le backend et le simulateur ; le vocabulaire des états système vit à côté, dans dotnet/shared/Profiles/SystemFlagKeys.cs.

Ce qu'il faut retenir ​

Les tables d'échange INIS-E16 et AVISS documentent des adresses fil JBUS brutes : l'adresse logique est envoyée telle quelle, sans décalage d'adressage. Les deux centrales partagent le même cahier, écrit pour l'AVISS ; l'INIS-E16 s'en écarte bloc par bloc, et ces écarts sont relevés sur centrales réelles, non déduits. Elle apporte par ailleurs quatre tables de zones et deux synthèses générales qui lui sont propres — neutralisation, mode manuel seul, arrêt d'urgence, inhibition — que le profil AVISS laisse nulles, aucune lecture n'étant alors émise.

Un état système n'est pas identifié par son adresse mais par sa clé : deux centrales portent le même état à des bits différents, ou ne le portent pas. Une centrale dont le firmware ne sert que les bobines de synthèse de base reste connectée en mode dégradé au lieu d'être déclarée en panne : ses états de zone demeurent fiables, seules les synthèses d'exploitation deviennent indisponibles.

Où trouver le détail ​

BesoinDocument
Adresses de chaque table, divergences firmware, codes de commandedocs/project/MODBUS.md
Configurer une adresse, ajouter un type de centraleProfils Modbus
Ajouter un état supervisé, campagne de validation JBUSdocs/project/PLAN-ETATS-EXPLOITATION.md
Faiblesses de l'interface des centrales et parades — internedocs/project/COMPENSATIONS-MODBUS.md

Workflow et releases ​

  • main : branche de développement, CI (tests + build) à chaque push.
  • prod : branche de production, mise à jour par Pull Request uniquement, déclenche le CD (release GitHub).

Procédure de release ​

  1. Sur main : valider les tests, mettre à jour la version dans app.config.json et le CHANGELOG.md.
  2. Ouvrir une Pull Request main → prod, vérifier la CI.
  3. Au merge : le CD crée automatiquement une release GitHub en brouillon (tag vX.Y.Z + notes extraites du changelog). Il ne compile pas l'application.
  4. Compiler l'installateur localement : cd deployment && .\build-all.ps1.
  5. Attacher deployment/Installer/Superviseur-Setup-<version>.exe au brouillon de release, puis publier.

Le build de l'installateur (lourd) est volontairement réalisé en local, pas sur GitHub Actions.

Conventions ​

ObjetRègleVérifiable par
Message de commitUne seule ligne de sujet, Conventional Commits, en français. Types employés : fix, feat, docs, refactor, chore, test, style, ci, build, perfgit log --oneline
Corps de commitAbsent, sauf demande explicite. Le détail va au changeloggit log --format=%b
VersionAppVersion de app.config.json — source unique, estampillée sur les binaires par build-all.ps1Le CD y lit le tag et le nom de la release
Entrée de changelog## [X.Y.Z] - JJ-MM-AAAA, puis des sections ### Added, ### Changed, ### Fixed, ### Security, ### Removed, ### Tests, ### PerformanceLe CD extrait la première entrée jusqu'au --- suivant

Le format de date JJ-MM-AAAA et le séparateur --- en fin d'entrée sont exigés par l'expression régulière d'extraction du CD (cd.yml) : une entrée mal formée produit une release sans notes, sans erreur.


Intégration continue ​

Quatre workflows GitHub Actions, tous décrits dans .github/workflows/.

WorkflowDéclencheurCe qu'il faitArtefacts
ci.ymlpush et PR sur mainOnze jobs : frontend (build → tests → lint), backend (build → tests), desktop (build → tests), contrôle de build de la documentation, scan de vulnérabilités .NET et npm, SBOMsbom-cyclonedx (30 j)
docs.ymlpush sur main touchant docs/**, un README.md, CHANGELOG.md ou lui-même ; ou manuelTypeDoc → VitePress → DocFX, puis déploiement Cloudflare Pages (projet superviseur-docs, branche main)superviseur-documentation (7 j)
semgrep.ymlpush et PR sur main, lundi 03:00 UTC, ou manuelSemgrep OSS (p/default, p/security-audit, p/secrets) ; échoue sur les findings de sévérité ERRORsemgrep-sarif (14 j), seulement en cas d'échec
cd.ymlpush sur prodCrée une release GitHub en brouillon : tag v<AppVersion>, notes extraites du changelog. Ne compile rienAucun

Points qui surprennent :

ComportementRaison portée par le workflow
La CI ne compile jamais l'installateurBuild long et coûteux, réalisé en local
Les PR Dependabot n'exécutent qu'une partie des jobsLe préfixe de branche (dependabot/nuget/, dependabot/npm_and_yarn/) sert de discriminant ; un bump front ne relance pas les builds Windows
Backend-Build échoue si vue/src/config/generated/enums.ts diffèreLe job régénère le fichier et compare avec git diff --exit-code — régénérer par scripts/generate-ts-enums.ps1 et commiter
npm audit bloque sur les dépendances de production seulementLes dépendances de développement ne sont pas livrées ; l'audit complet reste informatif
Les tests backend tournent en ReleaseCertains types du backend sont sous #if DEBUG ; un test réflexif ne voit pas le même assembly qu'en local
La doc n'est pas reconstruite à chaque push de codeLa référence d'API ne se rafraîchit que sur workflow_dispatch ou sur un changement de docs/**
Les téléversements d'artefacts sont en continue-on-errorUn quota de stockage saturé ne doit pas faire échouer un job qui a abouti

Contraintes actives du dépôt ​

ContrainteEffet si elle est ignoréeOù
global.json épingle le SDK .NET sur 9.0.100Un SDK plus récent installé sans son runtime fait échouer toute commande dotnet sur « You must install or update .NET »global.json
appsettings.Crypto.{dev,prod}.json ne sont jamais versionnés ni affichésIls portent les clés revendeurs et le secret applicatif.gitignore
deployment/setup.iss est généré et non versionnéToute édition à la main est écrasée au build suivantgenerate-setup.ps1
vue/src/config/generated/enums.ts est généréUne édition à la main est perdue et fait rougir la CITsEnumGenerator
docs/site/api/ est généré par TypeDoc et ignoré par gitVide sur un dépôt fraîchement cloné, ce qui est normalvue/typedoc.json
cleanOutDir de VitePress reste à falseÀ true, la construction du portail efface dist-docs/backend/ produit par DocFXdocs/site/.vitepress/config.ts
DocFX passe après VitePressL'ordre inverse laisse la référence C# videgenerate-docs.ps1
Les guides VitePress incluent les sources par <!--@include: -->Éditer la page du portail au lieu de la source est sans effet durabledocs/site/guide/
Les scripts PowerShell sont écrits en UTF-8 avec BOMSans BOM, PowerShell 5.1 les lit en ANSI, corrompt les accents et casse le parsingscripts/, deployment/
Le frontend est publié dans le wwwroot du backend et dans celui du clientHors configuration Debug, la publication du backend déclenche npm run build et recopie vue/dist/ ; build-all.ps1 en dépose une seconde copie dans staging/client/wwwroot/. Un poste installé sans cette seconde copie affiche une fenêtre videbackend.csproj, build-all.ps1
Aucune URL /api ou /uploads relative dans le frontElles échouent sur poste installé, où le front est servi par un hôte virtuel distinct du backendvue/src/api/apiBase.ts, verrouillé par relative-api-calls.spec.ts
Une entité ajoutée à la base doit être sauvegardée ou écartée avec son motifSinon l'export réussit et la perte n'apparaît qu'à la restaurationBackupCoverageTests

Documentation Technique