Apparence
12. Modèle de données
👔 En clair
La liste des informations gérées par l'application (projets, modules, tests, étapes, campagnes, anomalies, preuves, CRIMs…) et leurs liens. Le diagramme ci-dessous en donne la vue d'ensemble ; les tableaux détaillés qui suivent sont techniques.
v2 — Convex. Le modèle est défini dans
packages/backend/convex/schema.ts(defineSchema) : des collections de documents typés (TypeScript + validateurs Zod partagés via@recette/validators), reliées par références indexées (v.id("table")) plutôt que par clés étrangères SQL. L'isolation multi-tenant passe par un champorganizationIdsur chaque document, filtré par la couche ABAC / RLS applicative. Environ 14 collections métier (héritées du périmètre v1 : PostgreSQL/Supabase, ~14 tables).
📌 Correspondances de typage v1 → v2 :
UUID/UUID FK→_idConvex /v.id("table")·JSONB→ objet imbriqué validé par Zod ·TEXT … CHECK→ union de littéraux (v.union(v.literal(...))) ·UNIQUE/ index SQL → index Convex (.index("by_...", [...])) · migrations SQL → composant migrations Convex.
12.1 Diagramme entité-relation (macro)
Le diagramme ci-dessous se lit sans connaissance technique : chaque bloc est une catégorie d'information gérée par l'application, chaque flèche un lien entre elles (« une campagne contient des tests », « un test contient des étapes »…).
Représentation conceptuelle. En Convex, chaque « table » est une collection de documents et chaque relation un champ
Id<...>résolu par index (voir les relationship helpersconvex-helpers).
En v2, l'identité et l'authentification (
organizations/profilesde la v1) sont portées par Better Auth (@convex-dev/better-auth) : l'utilisateur et sonorganizationIdviennent deauthComponent.getAuthUser(ctx), pas d'une table métier gérée à la main.
12.2 Dictionnaire des entités principales
Le dictionnaire ci-dessous liste, champ par champ, ce que l'application mémorise pour chaque type d'information. Il est utile si vous voulez vérifier qu'une donnée métier attendue est bien prévue (par exemple : « le nom du testeur est-il conservé ? »).
Il est rédigé en vocabulaire technique. Passez en mode Technique (en haut de page) pour le consulter.
tests (Flux / cas de test) — cœur du plan de test.
| Champ | Type (Convex) | Description métier |
|---|---|---|
_id | Id<"tests"> | Identifiant du document |
testCode | string | Code lisible (T1, T2…), unique par projet (index) |
nom | string | Nom du flux |
metier, fonctId, fonctNom, scId, scNom | string | Dénormalisations de la hiérarchie (synchronisées par triggers) |
scenarioId | Id<"scenarios"> | null | Scénario parent (optionnel) |
crims | string[] | Cache des codes CRIM (union des étapes) |
statut | union littérale | Cycle de vie : Draft / À rédiger / Validé / Obsolète |
isRefTest | boolean | true = référentiel maître ; false = snapshot/campagne-only |
campaignIdSnapshot | Id<"campaigns"> | null | null = maître ; sinon appartient à la campagne |
sourceRefId | Id<"tests"> | null | Ligne maître d'origine (traçabilité) |
position | number | Ordre d'affichage |
testeur, qualite | objet imbriqué | Blocs d'infos (validés par Zod) |
organizationId | string | Tenant — filtré par la couche ABAC |
etapes — étape d'un flux (définition + résultat).
| Champ | Type (Convex) | Description |
|---|---|---|
testId | Id<"tests"> | Flux parent |
campaignId | Id<"campaigns"> | null | null = maître ; sinon snapshot |
position | number | Ordre (unicité (testId, position) par index) |
nom, description, jeu, attendu, crimCode | string | Définition (copiée au snapshot) |
resultat | union littérale | OK / KO / Non testé — résultat, par campagne |
gravite, commentaire | string | Résultat |
evidenceFileId | Id<"evidence_files"> | null | Preuve d'étape |
anomalies — défaut sur une étape.
| Champ | Type (Convex) | Description |
|---|---|---|
etapeId | Id<"etapes"> | Étape (unique — 1 anomalie max, garanti par index) |
campaignId, testId | Id<...> | Scope + flux parent |
description | string | Obligatoire |
gravite | union littérale | Bloquant / Majeur / Gênant |
statut, assigneA, responsable, jiraLink, declarePar, dateCreation | — | Triage |
| dénormalisations (metier, codes/noms, crimCodes) | — | Liste sans jointures |
campaigns, crims, test_runs, evidence_files, modules, functionalities, scenarios, projects : mêmes entités qu'en v1, portées par des collections Convex typées. schema.ts (+ @recette/validators) est la source unique du modèle en v2 (le docs/db-schema.json de v1 n'a plus cours).
12.3 Dénormalisations & dette assumée
Certaines informations sont recopiées à plusieurs endroits pour accélérer l'affichage (le nom du module est stocké sur le flux, par exemple). En v1, ces copies étaient resynchronisées par un traitement fragile qui pouvait laisser des écarts. En v2, elles sont mises à jour de façon garantie — c'est un des gains directs du changement de socle.
En v1, ces points étaient une dette fragile ; en v2 ils deviennent des choix outillés :
testsporte des champs texte dupliqués depuis la hiérarchie → en v2, synchronisés atomiquement par triggers (convex-helpers/server/triggers) au lieu d'une boucle fire-and-forget.crimssurtests: cache de codes → recalculé par trigger à chaque changement d'étape.testeur,qualite,executant: objets imbriqués (validés par Zod) — normalisation vers des références utilisateur Better Auth possible via migration.campaign_tests(M2M campagne↔test) de la v1 : abandonnée (le flux snapshot utilisecampaignIdSnapshot) — non reprise en v2, voir Fonctionnalités inaccessibles.