# Décisions architecturales 0.2.0-dev.3 Les décisions sont ajoutées au fil des checkpoints. Les modèles existants sont privilégiés avant toute nouvelle table. ## D-005 — Centre de configuration permanent et setup progressif **CONTEXTE** : le setup initial ne doit pas devenir une page jetable ; une GMAO utile doit accepter une configuration partielle et expliciter les actions restantes. **OPTIONS ÉTUDIÉES** : checklist statique de fin d'installation ; tableau calculé et permanent avec liens d'action. **CHOIX** : créer/faire évoluer un Centre de configuration permanent, organisé par domaines (Essentiel, Maintenance, Patrimoine, Entreprises, Compteurs, Cartographie technique, Intégrations), avec états calculés et intégrations facultatives non bloquantes. **JUSTIFICATION** : rendre la configuration progressive observable et exploitable sans SQL ni connaissance de l'architecture. **CONSÉQUENCES** : chaque contrôle doit avoir une règle de calcul et une destination UI ; Pronote, ENT, Outlook, Yeastar, IA, compteurs, logements et cartographie restent facultatifs. **DATE/COMMIT** : 2026-08-23 / préparation checkpoint B. ## D-006 — RoomType structurel, RoomProfile séparé à étudier **CONTEXTE** : `RoomType` classe actuellement les locaux et est utilisé par Pronote et les écrans de patrimoine, mais ne porte aucun catalogue d'équipements, de quantités ou d'ouvrages. **OPTIONS ÉTUDIÉES** : enrichir `RoomType` ; créer un `RoomProfile` distinct relié à `RoomType` ; stocker des JSON dans `RoomType`. **CHOIX** : `RoomProfile` séparé, avec `RoomProfileItem` et `RoomSurface` normalisés. `RoomType` reste structurel et n'est pas modifié. **JUSTIFICATION** : éviter de casser les usages de classification/enseignement et permettre plusieurs profils de proposition pour un même type structurel. **CONSÉQUENCES** : migrations `k6f7a8b9c0d1` et `l7a8b9c0d1e2` ajoutées ; association de profil nullable ; aucune création automatique d'équipement sans validation utilisateur. **DATE/COMMIT** : 2026-08-23 / implémentation checkpoint B en cours. ## D-007 — Origine d’une proposition de profil **CONTEXTE** : une réapplication d’un RoomProfile doit ajouter uniquement le delta sans rechercher les équipements par nom. **OPTIONS ÉTUDIÉES** : comparaison fragile nom/catégorie ; table de liaison ; identifiant nullable sur Equipment. **CHOIX** : ajouter `Equipment.room_profile_item_id`, nullable, indexé et relié à `RoomProfileItem`. Les équipements historiques sans origine restent valides. **JUSTIFICATION** : l’identifiant de proposition est stable, compatible avec les noms en doublon et permet une idempotence explicite sans mutation silencieuse. **CONSÉQUENCES** : migration non destructive `m8b9c0d1e2f3`; le service commun renseigne l’origine lors de l’application d’un profil. **DATE/COMMIT** : 2026-08-23 / checkpoint B. ## D-008 — Centre de configuration sans faux état d’erreur **CONTEXTE** : le lot d’un équipement est facultatif et les modèles de contrats exposent des colonnes ORM dont certaines propriétés métier ne sont pas directement filtrables. **CHOIX** : afficher un équipement sans lot comme information facultative ; filtrer les contrats via `Contract.__table__.c` pour éviter les erreurs de rendu du Centre. **JUSTIFICATION** : une configuration progressive ne doit pas bloquer l’inventaire ni produire une page de synthèse cassée. **CONSÉQUENCES** : les liens du nouveau menu pointent vers Centre, profils, bulk et horaires ; les intégrations avancées restent facultatives. **DATE/COMMIT** : 2026-08-23 / validation B. ## D-000 — Checkpoints indépendants **CONTEXTE** : le chantier couvre plusieurs domaines avec migrations et risques différents. **OPTIONS ÉTUDIÉES** : un gros développement continu ; checkpoints commitables. **CHOIX** : checkpoints A à E, chacun documenté, testé et versionné. **JUSTIFICATION** : reprise fiable, absence de régression masquée, dépôt source de vérité. **CONSÉQUENCES** : aucun checkpoint suivant ne démarre avant validation du précédent. **DATE/COMMIT** : 2026-08-23 / initialisation. ## D-001 — Service de création Equipment **CONTEXTE** : les routes fiche avancée et wizard construisaient des objets différents et le wizard retrouvait ensuite des équipements par nom. **OPTIONS ÉTUDIÉES** : conserver les routes indépendantes ; centraliser la construction dans un service. **CHOIX** : `core.services.equipment_creation.create_equipment`, lot et catégorie facultatifs, retour de l'instance persistée. **JUSTIFICATION** : évite les collisions de noms et garantit la même gestion de quantité, parent, localisation et génération préventive. **CONSÉQUENCES** : les anciens parcours sont progressivement migrés ; les relations techniques restent hors `parent_id`. **DATE/COMMIT** : 2026-08-23 / checkpoint A en cours. ## D-009 — Rattachement explicite des compteurs **CONTEXTE** : les compteurs historiques étaient obligatoirement rattachés à `Equipment`, alors que l'exploitation nécessite aussi des compteurs de bâtiment, zone, local et logement. **OPTIONS ÉTUDIÉES** : cible polymorphe `scope_type/scope_id` ; FK nullable distinctes ; création d'un faux équipement pour chaque compteur patrimoine. **CHOIX** : conserver `equipment_id` nullable et ajouter `building_id`, `zone_id`, `room_id` et `housing_unit_id`, avec une contrainte SQL imposant exactement un rattachement principal. `Room` est supporté directement. **JUSTIFICATION** : les FK garantissent l'intégrité référentielle MariaDB, rendent les requêtes explicites et évitent le faux équipement. Le polymorphisme aurait supprimé les FK natives et complexifié les jointures. **CONSÉQUENCES** : l'index historique des compteurs Equipment reste valide ; les listes ne font plus de `join(Equipment)` obligatoire ; migration non destructive `n9c0d1e2f3g4`. ## D-010 — Hiérarchie, relevés audités et remplacement **CHOIX** : `Meter.parent_id` porte une hiérarchie indépendante d'`Equipment.parent_id`, avec plusieurs racines possibles et validation des cycles. `MeterReading` reste une mesure physique dans l'unité native. `record_meter_reading` est le service unique ; une baisse exige un reset explicite et justifié. Une correction met à jour la mesure tout en conservant ancienne valeur, nouvelle valeur, auteur, date et justification dans `MeterReadingCorrection`. Un remplacement crée une nouvelle identité reliée par `replaces_meter_id` et clôt l'ancien compteur. **PHOTOS** : une photo facultative est stockée sur le relevé (`photo_filename`, `photo_path`) en réutilisant les extensions et la racine d'upload existantes ; aucune association artificielle à `EquipmentDocument`. **HORS C1** : échéances, consommations, coefficients gaz, alertes, coûts, contrats et quotas restent respectivement C2, C3 et C4. **DATE/COMMIT** : 2026-08-23 / checkpoint C1. ## D-003 — Catégorie et lot facultatifs **CONTEXTE** : un inventaire peut être saisi avant que le référentiel de maintenance soit complet. **OPTIONS ÉTUDIÉES** : bloquer toute création sans lot ; accepter un équipement incomplet et le compléter plus tard. **CHOIX** : la création reste valide sans lot (et sans catégorie dans les parcours wizard) ; un lot fourni est validé et peut déclencher la génération préventive. **JUSTIFICATION** : respecter le principe de configuration progressive sans fabriquer de maintenance implicite. **CONSÉQUENCES** : l'interface doit pouvoir signaler ultérieurement « Lot non renseigné » ; les relations techniques restent indépendantes. **DATE/COMMIT** : 2026-08-23 / checkpoint A. ## D-004 — Versionnement du checkpoint A **CONTEXTE** : le chantier interdit `0.1.0-dev.13` et demande des versions correspondant à des checkpoints réellement validés. **CHOIX** : le checkpoint A validé passe de `0.1.0-dev.12` à `0.2.0-dev.1` ; B, C, D et E restent séparés. **JUSTIFICATION** : la création Equipment est consolidée et testée sans nouvelle régression ; les erreurs restantes sont exactement la baseline historique. **CONSÉQUENCES** : Docker doit être reconstruit avec la nouvelle version ; aucune migration n'est ajoutée au checkpoint A. **DATE/COMMIT** : 2026-08-23 / version commit. ## D-002 — Durée d'intervention inconnue **CONTEXTE** : `Intervention.effective_estimated_duration` retournait silencieusement 60 minutes. **CHOIX** : retourner 0 si aucune estimation ou moyenne historique n'existe ; DayPlanner affiche alors une tâche sans durée à renseigner. **JUSTIFICATION** : ne pas présenter une estimation arbitraire comme une contrainte métier. **CONSÉQUENCES** : les statistiques historiques restent inchangées ; les workflows doivent renseigner les interventions planifiables. **DATE/COMMIT** : 2026-08-23 / checkpoint A en cours.