Skip to content

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

ts
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 :

txt
QFORM_BUILDER_DOCUMENT_VERSION = 1
QFORM_BUILDER_SCHEMA_VERSION = 1
QFORM_BUILDER_THEME_VERSION = 2

La 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

json
{
  "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

ts
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 :

ts
result.included.values
result.included.settings

Cette information évite qu’un ancien export contenant seulement le schéma efface les valeurs ou le thème courants.

API du composant

ts
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ées

Options d’import :

ts
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 :

vue
<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

ts
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__, prototype et constructor ;
  • 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 :

  1. incrémenter uniquement la version du périmètre concerné ;
  2. ajouter une migration pure et déterministe au registre ;
  3. préserver l’objet source ;
  4. documenter les valeurs par défaut et pertes éventuelles ;
  5. ajouter un test runtime, un scénario navigateur et une note de migration FR/EN ;
  6. rejeter les versions futures inconnues.

QForm Builder — layer Nuxt 4, Quasar et FormKit pour formulaires dynamiques.