Versionnement et migrations des formulaires
Depuis 0.1.13, QForm Builder possède un format de persistance canonique et versionné. Il permet de faire évoluer indépendamment :
- l’enveloppe du document ;
- le schéma FormKit/Quasar ;
- le thème sérialisé.
Le moteur reste compatible avec les tableaux de schéma et les anciens états d’autosauvegarde non versionnés.
Versions courantes
import {
QFORM_BUILDER_DOCUMENT_VERSION,
QFORM_BUILDER_SCHEMA_VERSION,
QFORM_BUILDER_THEME_VERSION,
} from '@vevedh/qform-builder-layer/migrations'Les valeurs de 0.1.13 sont :
QFORM_BUILDER_DOCUMENT_VERSION = 1
QFORM_BUILDER_SCHEMA_VERSION = 1
QFORM_BUILDER_THEME_VERSION = 2La version du thème est indépendante du schéma. Le passage du thème 1 au thème 2 ajoute les groupes background, effects, motion et icons introduits par le Theme Builder avancé.
Document canonique
{
"format": "qform-builder",
"documentVersion": 1,
"schemaVersion": 1,
"themeVersion": 2,
"exportedAt": "2026-06-27T15:00:00.000Z",
"schema": [],
"values": {},
"settings": {
"formName": "Formulaire",
"preview": {
"width": 640,
"isFullWidth": false
},
"previewMode": "editing",
"columns": "default",
"theme": {}
},
"metadata": {
"source": "form-builder"
}
}Le document complet est désormais le mode d’export recommandé. Le mode Schéma uniquement reste disponible pour les intégrations historiques.
API pure
import {
createQFormBuilderDocument,
migrateQFormBuilderDocument,
parseQFormBuilderDocument,
stringifyQFormBuilderDocument,
} from '@vevedh/qform-builder-layer/migrations'
const document = createQFormBuilderDocument({
schema,
values,
settings,
}, {
metadata: {
name: 'Formulaire support',
source: 'nfz-forms',
},
})
const json = stringifyQFormBuilderDocument(document)
const result = parseQFormBuilderDocument(json)
console.log(result.sourceKind)
console.log(result.migrations)
console.log(result.warnings)migrateQFormBuilderDocument() accepte :
- un tableau de schéma historique ;
- une enveloppe
{ schema: [...] }; - un ancien état
{ schema, values, settings, savedAt }; - un document canonique versionné.
Le résultat indique précisément ce que la source contenait :
result.included.values
result.included.settingsCette information évite qu’un ancien export contenant seulement le schéma efface les valeurs ou le thème courants.
API du composant
const builder = ref<FormBuilderPublicApi | null>(null)
const document = builder.value?.exportDocument({
metadata: { source: 'admin-ui' },
})
builder.value?.importDocument(document)
builder.value?.importDocument(json) // les chaînes JSON sont aussi acceptéesOptions d’import :
builder.value?.importDocument(legacySchema, {
applyValues: false,
applySettings: false,
})Par défaut :
- le schéma est toujours appliqué ;
- les valeurs ne sont appliquées que si la source en contenait ;
- les réglages et le thème ne sont appliqués que si la source en contenait.
Événements :
<FormBuilder
@document-import="auditImport"
@document-export="auditExport"
/>document-import expose la source, les versions, les migrations exécutées, les avertissements et les groupes réellement appliqués.
Registre de migrations
import {
qFormBuilderMigrationRegistry,
resolveQFormBuilderMigrationPath,
} from '@vevedh/qform-builder-layer/migrations'
const themePath = resolveQFormBuilderMigrationPath('theme', 1)Chaque entrée possède un identifiant stable, un périmètre, une version source, une version cible et une description. resolveQFormBuilderMigrationPath() résout un chemin contigu et déterministe, puis échoue si une étape manque ou forme un cycle. Une version future non prise en charge est rejetée explicitement ; elle n’est jamais interprétée comme une ancienne version.
Autosauvegarde
L’autosauvegarde écrit désormais le document canonique. La lecture reste compatible avec l’ancien format non versionné. Une clé localStorage existante est donc migrée à la prochaine sauvegarde sans migration destructive préalable.
Sécurité
Le moteur :
- réutilise
sanitizeQFormBuilderSchema(); - rejette les clés
__proto__,prototypeetconstructor; - refuse les fonctions, symboles, nombres non finis et prototypes personnalisés ;
- borne la profondeur, le nombre de valeurs, les chaînes et la taille JSON ;
- filtre les réglages et métadonnées sur un contrat fermé ;
- normalise les thèmes et icônes avec les allowlists existantes ;
- refuse les versions futures plutôt que de les rétrograder silencieusement.
Les valeurs du document doivent rester JSON. Les objets navigateur File, Blob et FileList ne sont pas intégrés au fichier .qform.json : téléversez les binaires séparément, puis persistez uniquement un identifiant ou des métadonnées validées. Si une valeur non sérialisable atteint l’autosauvegarde, le snapshot local précédent est conservé et l’événement error reçoit le code AUTOSAVE_SERIALIZATION_FAILED.
Le backend reste responsable de l’authentification, du RBAC, des quotas, du contrôle de concurrence et de la validation serveur avant persistance.
Politique pour les futures migrations
Toute modification persistée doit :
- incrémenter uniquement la version du périmètre concerné ;
- ajouter une migration pure et déterministe au registre ;
- préserver l’objet source ;
- documenter les valeurs par défaut et pertes éventuelles ;
- ajouter un test runtime, un scénario navigateur et une note de migration FR/EN ;
- rejeter les versions futures inconnues.