Apparence
8. Concept central : Référentiel & Snapshots de campagne
Ce mécanisme est le cœur métier de l'application. Le comprendre est indispensable.
⚠️ Mise à jour du 19/07/2026 — ce modèle n'est plus reconduit à l'identique en v2. La page ci-dessous décrit fidèlement l'existant v1. Pour la v2, le couple « référentiel + snapshot intégral » est remplacé par un modèle hybride : association pour la structure, gel ciblé des champs de définition au moment de la première saisie de résultat → voir 🆕 A3bis — modèle hybride. La conséquence pratique : le périmètre d'une campagne devient ajustable en cours de route, et l'historique reste figé au niveau du résultat, plus au niveau de l'arbre entier.
Deux périmètres coexistent
| Périmètre | Nature | Modifiable ? | Discriminant (v2, Convex) |
|---|---|---|---|
| Référentiel maître | Modèle réutilisable du plan de test | Définitions oui (admin/consultant) ; résultats : non | campaignId / campaignIdSnapshot = null |
| Snapshot de campagne | Copie figée appartenant à une campagne | Résultats : oui, uniquement si campagne active | campaignIdSnapshot = Id<"campaigns"> |
Chaque copie garde un lien vers l'élément d'origine dont elle est issue — c'est ce qui permet de retrouver, pour un test exécuté dans une campagne, quel élément du plan de test il reproduit.
Ce lien est le champ sourceRefId, résolu par relationship helper.
Activation d'une campagne = photographie figée
À la première activation d'une campagne :
- La campagne devient la campagne active ; toute autre campagne active du même projet est automatiquement désactivée — il ne peut y en avoir qu'une (comportement v1 ; l'évolution A12 autorise plusieurs campagnes actives en parallèle).
- L'intégralité du plan de test est recopiée dans la campagne : modules → fonctionnalités → scénarios → flux → étapes.
- Les définitions d'étapes (intitulé, description, jeu de données, résultat attendu, CRIM) sont copiées ; les résultats partent à zéro (« Non testé »).
- La recopie n'a lieu qu'une fois. Réactiver une campagne plus tard ne recopie jamais : les résultats déjà saisis sont préservés.
Mutation campaigns.activate. (1) isActive = true, unicité par index Convex + garde dans la mutation, en remplacement de l'index partiel SQL de v1. (2) copie en profondeur vers des documents scopés à la campagne. (4) champ snapshotCreatedAt → garde d'idempotence (RG-14).
Règle d'exécution
- Les résultats et anomalies ne sont saisissables que dans la campagne active.
- Le plan de test de référence et les campagnes désactivées sont en lecture seule pour les résultats.
Garde assertCampaignActive, appliquée dans les mutations etapes / anomalies. C'est une règle d'état, portée par la couche ABAC, pas par l'UI.
⚠️ Point d'attention : ce modèle recopie tout le plan de test à chaque campagne. Passé quelques campagnes, la même information existe en dizaines de milliers d'exemplaires, et certains libellés recopiés doivent être resynchronisés — ce qui, en v1, était une source d'incohérences. La pertinence même du modèle est ce qui a conduit à la décision A3bis — voir aussi Q5.
Champs dénormalisés concernés : metier, fonctId, scId, fonctNom, scNom sur tests. En v1, propagation fire-and-forget (dette D5) ; en v2, synchronisation atomique par triggers convex-helpers.