Verrouillage optimiste pour outils admin : empêcher les écrasements silencieux
Apprenez le verrouillage optimiste pour les outils admin avec colonnes de version et vérifications updated_at, plus des modèles UI simples pour gérer les conflits d’édition sans écrasements silencieux.

Le problème : des écrasements silencieux quand plusieurs personnes éditent
Un « écrasement silencieux » survient lorsque deux personnes ouvrent le même enregistrement, font des modifications, et que la dernière personne à cliquer sur Sauvegarder l’emporte. Les modifications de la première disparaissent sans avertissement et souvent sans moyen simple de les récupérer.
Dans un panneau d’administration fréquenté, cela peut arriver toute la journée sans que personne ne le remarque. Les gens gardent plusieurs onglets ouverts, naviguent entre des tickets, puis reviennent à un formulaire resté ouvert pendant 20 minutes. Quand ils sauvegardent enfin, ils n’ont pas la dernière version du registre. Ils l’écrasent.
Ce problème apparaît davantage dans les outils back-office que dans les applications publiques parce que le travail est collaboratif et centré sur des enregistrements. Les équipes internes modifient les mêmes clients, commandes, produits et demandes à plusieurs reprises, souvent en courtes sessions. Les applications publiques sont plus souvent « un utilisateur modifie ses propres données », alors que les outils d’administration sont « plusieurs utilisateurs modifient des éléments partagés ».
Les conséquences sont rarement dramatiques immédiatement, mais s’accumulent rapidement :
- Un prix produit revient à une ancienne valeur juste après une mise à jour promotionnelle.
- La note interne d’un agent de support disparaît, de sorte que l’agent suivant refait les mêmes vérifications.
- Le statut d’une commande recule (par exemple « Expédiée » redevient « Emballée »), déclenchant un suivi inapproprié.
- Le numéro de téléphone ou l’adresse d’un client est remplacé par des informations obsolètes.
Les écrasements silencieux sont pénibles parce que tout le monde pense que le système a bien enregistré. Il n’y a pas de moment clair « quelque chose a mal tourné », juste de la confusion plus tard quand les rapports semblent incorrects ou quand un collègue demande : « Qui a modifié ça ? »
Les conflits de ce type sont normaux. Ils indiquent que l’outil est partagé et utile, pas que votre équipe a mal agi. L’objectif n’est pas d’empêcher deux personnes d’éditer, mais de détecter si l’enregistrement a changé pendant qu’une personne l’éditait, puis de gérer ce cas en toute sécurité.
Si vous construisez un outil interne dans une plateforme no-code comme AppMaster, il vaut la peine de planifier cela tôt. Les outils d’administration tendent à croître rapidement, et une fois que les équipes en dépendent, perdre des données « parfois » devient une source constante de méfiance.
Le verrouillage optimiste en clair
Quand deux personnes ouvrent le même enregistrement et cliquent toutes les deux sur Sauvegarder, vous avez une concurrence. Chacune a commencé à partir d’un instantané ancien, mais une seule peut être « la plus récente » quand les sauvegardes arrivent.
Sans protection, la dernière sauvegarde gagne. C’est comme ça que naissent les écrasements silencieux : la deuxième sauvegarde remplace discrètement la première.
Le verrouillage optimiste est une règle simple : « J’enregistre mes modifications seulement si l’enregistrement est resté dans le même état que lorsque j’ai commencé à éditer. » Si l’enregistrement a changé entre-temps, la sauvegarde est rejetée et l’utilisateur voit un conflit.
C’est différent du verrouillage pessimiste, qui revient à « j’édite, donc personne d’autre ne peut le faire ». Le verrouillage pessimiste implique généralement des verrous durs, des timeouts et des blocages. Ça peut être utile dans des cas rares (par exemple déplacer de l’argent entre comptes), mais c’est souvent frustrant dans des outils d’administration très actifs où de petites modifications se font toute la journée.
Le verrouillage optimiste est en général le meilleur choix par défaut parce qu’il laisse le travail circuler. Les gens peuvent éditer en parallèle, et le système n’intervient qu’en cas de vraie collision.
Il convient surtout lorsque :
- Les conflits sont possibles mais pas constants.
- Les modifications sont rapides (quelques champs, formulaire court).
- Bloquer les autres ralentirait l’équipe.
- Vous pouvez afficher un message clair « quelqu’un a mis à jour ceci ».
- Votre API peut vérifier une version (ou un horodatage) à chaque mise à jour.
Ce qu’il empêche, c’est le problème de « l’écrasement silencieux ». Au lieu de perdre des données, vous obtenez un arrêt net : « Cet enregistrement a changé depuis que vous l’avez ouvert. »
Ce qu’il ne peut pas faire est important aussi. Il n’empêchera pas deux personnes de prendre des décisions différentes (mais valides) en se basant sur la même information ancienne, et il ne fusionnera pas automatiquement les modifications pour vous. Et si vous sautez la vérification côté serveur, vous n’avez rien résolu.
Limites courantes à garder en tête :
- Il ne résout pas automatiquement les conflits (il faut choisir une action).
- Il n’aide pas si des utilisateurs éditent hors ligne puis synchronisent sans vérification.
- Il ne corrige pas de permissions incorrectes (quelqu’un peut toujours modifier ce qu’il ne devrait pas).
- Il ne détectera pas les conflits si vous ne faites la vérification que côté client.
En pratique, le verrouillage optimiste est juste une valeur supplémentaire envoyée avec l’édition, plus une règle côté serveur « n’écris que si ça correspond ». Si vous créez un panneau d’administration dans AppMaster, cette vérification vit généralement dans la logique métier là où les mises à jour sont exécutées.
Deux approches courantes : colonne de version vs updated_at
Pour détecter qu’un enregistrement a changé pendant qu’un utilisateur l’éditait, on choisit généralement l’un de ces deux signaux : un numéro de version ou un horodatage updated_at.
Approche 1 : colonne version (entier incrémental)
Ajoutez un champ version (généralement un entier). Quand vous chargez le formulaire d’édition, vous chargez aussi la version courante. Quand vous sauvegardez, vous renvoyez cette même valeur.
La mise à jour ne réussit que si la version stockée correspond toujours à celle que l’utilisateur avait au départ. Si elle correspond, vous mettez à jour l’enregistrement et incrémentez version de 1. Si elle ne correspond pas, vous renvoyez un conflit au lieu d’écraser.
C’est facile à comprendre : la version 12 signifie « c’est la 12ᵉ modification ». Cela évite aussi les problèmes liés au temps.
Approche 2 : updated_at (comparaison d’horodatage)
La plupart des tables ont déjà un champ updated_at. L’idée est la même : lire updated_at à l’ouverture du formulaire, puis l’inclure à la sauvegarde. Le serveur n’actualise que si updated_at est inchangé.
Ça peut bien fonctionner, mais les horodatages ont des pièges. Les bases de données n’ont pas toutes la même précision. Certaines arrondissent à la seconde, ce qui peut rater des modifications rapides. Si plusieurs systèmes écrivent dans la même base, la dérive d’horloge et les fuseaux horaires peuvent aussi créer des cas ambigus.
Résumé simple :
- Colonne de version : comportement le plus clair, portable entre bases, pas de problèmes d’horloge.
updated_at: souvent « gratuit » parce qu’il existe déjà, mais la précision et la gestion des horloges peuvent poser problème.
Pour la plupart des équipes, une colonne de version est le meilleur signal principal. Elle est explicite, prévisible et facile à référencer dans les logs et tickets support.
Si vous utilisez AppMaster, cela signifie généralement d’ajouter un champ entier version dans le Data Designer et de s’assurer que votre logique de mise à jour le vérifie avant d’enregistrer. Vous pouvez garder updated_at pour l’audit, mais laissez le numéro de version décider si une édition est sûre à appliquer.
Que stocker et quoi envoyer à chaque modification
Le verrouillage optimiste ne fonctionne que si chaque modification transporte un marqueur « vu en dernier » du moment où l’utilisateur a ouvert le formulaire. Ce marqueur peut être un numéro version ou un horodatage updated_at. Sans lui, le serveur ne peut pas savoir si l’enregistrement a changé pendant que l’utilisateur tapait.
Sur l’enregistrement lui-même, conservez vos champs métier habituels, plus un champ de concurrence contrôlé par le serveur. L’ensemble minimal ressemble à ceci :
id(identifiant stable)- champs métier (nom, statut, prix, notes, etc.)
version(entier incrémenté à chaque mise à jour réussie) ouupdated_at(horodatage écrit par le serveur)
Quand l’écran d’édition se charge, le formulaire doit stocker la valeur « vue en dernier » de ce champ de concurrence. Les utilisateurs ne doivent pas l’éditer, gardez-le en champ caché ou dans l’état du formulaire. Exemple : l’API renvoie version: 12, et le formulaire conserve 12 jusqu’à la sauvegarde.
Quand l’utilisateur clique sur Sauvegarder, envoyez deux choses : les changements et le marqueur « vu en dernier ». La forme la plus simple consiste à l’inclure dans le corps de la requête de mise à jour, comme id, champs modifiés et expected_version (ou expected_updated_at). Si vous construisez l’UI dans AppMaster, traitez cela comme n’importe quelle autre valeur liée : chargez-la avec l’enregistrement, ne la modifiez pas et soumettez-la avec la mise à jour.
Côté serveur, la mise à jour doit être conditionnelle. N’écrivez que si le marqueur attendu correspond à la valeur actuelle en base. Ne tentez pas de « fusionner » silencieusement.
Une réponse de conflit doit être claire et facile à gérer dans l’UI. Une réponse pratique inclut :
- le statut HTTP
409 Conflict - un message court comme « Cet enregistrement a été mis à jour par quelqu’un d’autre. »
- la valeur courante côté serveur (
current_versionoucurrent_updated_at) - optionnellement, l’enregistrement courant (pour que l’UI montre ce qui a changé)
Exemple : Sam ouvre un client à la version 12. Priya sauvegarde une modification, le passant à la version 13. Sam clique plus tard sur Sauvegarder avec expected_version: 12. Le serveur renvoie 409 avec l’enregistrement courant en version 13. L’UI peut alors inviter Sam à consulter les valeurs récentes au lieu d’écraser l’édition de Priya.
Étapes pas à pas : implémenter le verrouillage optimiste de bout en bout
Le verrouillage optimiste se résume souvent à une règle : chaque modification doit prouver qu’elle est basée sur la dernière version enregistrée du registre.
1) Ajouter un champ de concurrence
Choisissez un champ qui change à chaque écriture.
Un version entier dédié est le plus simple à comprendre. Commencez à 1 et incrémentez à chaque mise à jour. Si vous avez déjà un updated_at fiable qui change toujours, vous pouvez l’utiliser, mais assurez-vous qu’il s’actualise à chaque écriture (y compris les jobs en arrière-plan).
2) Envoyer cette valeur au client lors de la lecture
Quand l’UI ouvre un écran d’édition, incluez la version (ou updated_at) courante dans la réponse. Stockez-la dans l’état du formulaire comme valeur cachée.
Considérez-la comme un reçu qui dit : « j’édite ce que j’ai lu en dernier ».
3) Exiger la valeur à la mise à jour
À la sauvegarde, le client renvoie les champs modifiés plus le marqueur de concurrence « vu en dernier ».
Côté serveur, faites la mise à jour de manière conditionnelle. En SQL, c’est :
UPDATE tickets
SET status = $1,
version = version + 1
WHERE id = $2
AND version = $3;
Si la mise à jour affecte 1 ligne, la sauvegarde a réussi. Si elle affecte 0 ligne, quelqu’un d’autre a déjà modifié l’enregistrement.
4) Retourner la nouvelle valeur après succès
Après une sauvegarde réussie, renvoyez l’enregistrement mis à jour avec la nouvelle version (ou updated_at). Le client doit remplacer l’état du formulaire par ce que le serveur renvoie. Cela empêche les « double sauvegardes » avec une ancienne version.
5) Considérer les conflits comme une issue normale
Quand la mise à jour conditionnelle échoue, renvoyez une réponse de conflit claire (souvent HTTP 409) qui inclut :
- l’enregistrement courant tel qu’il est maintenant
- les changements tentés par le client (ou assez d’infos pour les reconstruire)
- les champs qui diffèrent (si vous pouvez le calculer)
Dans AppMaster, cela se traduit bien par un champ modèle PostgreSQL dans le Data Designer, un endpoint de lecture qui retourne la version, et un Business Process qui effectue la mise à jour conditionnelle et se sépare ensuite en branche succès ou conflit.
Modèles d’UI qui gèrent les conflits sans agacer les utilisateurs
Le verrouillage optimiste ne fait que la moitié du travail. L’autre moitié, c’est ce que voit la personne quand sa sauvegarde est rejetée parce que quelqu’un d’autre a changé l’enregistrement.
Une bonne UI de conflit poursuit deux objectifs : empêcher les écrasements silencieux et aider l’utilisateur à terminer sa tâche rapidement. Bien fait, cela ressemble à une protection utile, pas à un obstacle.
Modèle 1 : boîte de dialogue bloquante simple (le plus rapide)
Utilisez-le quand les modifications sont courtes et que les utilisateurs peuvent réappliquer facilement leurs changements après rechargement.
Gardez le message court et précis : « Cet enregistrement a changé pendant que vous l’éditiez. Rechargez pour voir la version la plus récente. » Puis proposez deux actions claires :
- Recharger et continuer (primaire)
- Copier mes modifications (optionnel mais utile)
« Copier mes modifications » peut placer les valeurs non sauvegardées dans le presse-papiers ou les préserver dans le formulaire après le rechargement, pour éviter à l’utilisateur de tout retaper.
Cela fonctionne bien pour des mises à jour d’un seul champ, des bascules, des changements de statut ou de petites notes. C’est aussi le plus simple à implémenter dans la plupart des outils, y compris des écrans AppMaster.
Modèle 2 : « Revoir les modifications » (idéal pour les enregistrements importants)
Utilisez-le quand l’enregistrement est critique (tarification, permissions, paiements) ou que le formulaire est long. Au lieu d’une erreur sans suite, envoyez l’utilisateur vers un écran de conflit qui compare :
- « Vos modifications » (ce que l’utilisateur a tenté d’enregistrer)
- « Valeurs actuelles » (dernières en base)
- « Ce qui a changé depuis que vous avez ouvert » (champs en conflit)
Restez concentré. Ne montrez pas tous les champs si seulement trois sont en conflit.
Pour chaque champ en conflit, offrez des choix simples :
- Garder le mien
- Prendre le leur
- Fusionner (utile uniquement quand cela a du sens, par exemple pour des tags ou des notes)
Après résolution, sauvegardez de nouveau avec la valeur de version la plus récente. Pour du texte long, affichez un petit diff (ajout/suppression) pour aider l’utilisateur à trancher rapidement.
Quand autoriser un écrasement forcé (et qui peut le faire)
Parfois un écrasement forcé est nécessaire, mais il doit rester rare et contrôlé. Si vous l’ajoutez, rendez-le délibéré : exigez une courte raison, loggez qui l’a fait et limitez-le à des rôles comme administrateurs ou superviseurs.
Pour les utilisateurs réguliers, par défaut « Revoir les modifications ». L’écrasement forcé se défend mieux quand l’utilisateur est propriétaire de l’enregistrement, que le risque est faible, ou que le système corrige des données sous supervision.
Scénario exemple : deux collègues éditent le même enregistrement
Deux agents support, Maya et Jordan, travaillent dans le même outil d’administration. Ils ouvrent tous les deux le profil d’un client pour mettre à jour le statut et ajouter des notes après des appels séparés.
Chronologie (avec verrouillage optimiste activé en utilisant soit un champ version, soit une vérification updated_at) :
- 10:02 - Maya ouvre le client #4821. Le formulaire charge Statut = "Needs follow-up", Notes = "Called yesterday" et Version = 7.
- 10:03 - Jordan ouvre le même client. Il voit les mêmes données, aussi Version = 7.
- 10:05 - Maya change Statut en "Resolved" et ajoute une note : "Issue fixed, confirmed by customer." Elle clique sur Sauvegarder.
- 10:05 - Le serveur met à jour l’enregistrement, incrémente Version à 8 (ou met à jour
updated_at) et stocke une entrée d’audit : qui a changé quoi et quand. - 10:09 - Jordan tape une autre note : "Customer asked for a receipt" et clique sur Sauvegarder.
Sans vérification de concurrence, la sauvegarde de Jordan pourrait écraser silencieusement le statut et la note de Maya, selon la manière dont la mise à jour est construite. Avec le verrouillage optimiste, le serveur rejette la mise à jour de Jordan car il tente de sauvegarder avec Version = 7 alors que l’enregistrement est déjà à Version = 8.
Jordan voit un message de conflit clair. L’UI montre ce qui s’est passé et lui propose une action sûre :
- Recharger l’enregistrement le plus récent (abandonner mes modifications)
- Appliquer mes modifications par-dessus la version la plus récente (recommandé quand c’est possible)
- Revoir les différences (afficher « Les miennes » vs « La plus récente ») et choisir ce qu’on garde
Un écran simple peut afficher :
- « Ce client a été mis à jour par Maya à 10:05 »
- Les champs qui ont changé (Statut et Notes)
- Un aperçu de la note non sauvegardée de Jordan, pour qu’il puisse la copier ou la réappliquer
Jordan choisit « Revoir les différences », conserve le Statut de Maya = "Resolved" et ajoute sa note aux notes existantes. Il sauvegarde à nouveau, cette fois avec Version = 8, et la mise à jour réussit (maintenant Version = 9).
État final : pas de perte de données, pas de devinettes sur qui a écrasé qui, et une piste d’audit propre qui montre la modification de statut de Maya et les deux notes comme éditions distinctes et traçables. Dans un outil construit avec AppMaster, cela se traduit par un contrôle unique à la mise à jour plus une petite boîte de résolution de conflit dans l’UI.
Erreurs fréquentes qui causent encore des pertes de données
La plupart des bugs liés au « verrouillage optimiste » ne viennent pas de l’idée elle‑même. Ils surviennent lors du passage d’informations entre l’UI, l’API et la base de données. Si une couche oublie les règles, vous pouvez toujours obtenir des écrasements silencieux.
Une erreur classique est de récupérer la version (ou l’horodatage) quand l’écran d’édition se charge, mais de ne pas la renvoyer à la sauvegarde. Cela arrive souvent quand un formulaire est réutilisé entre pages et que le champ caché est perdu, ou quand un client API n’envoie que les « champs modifiés ».
Un autre piège courant est de faire des vérifications uniquement dans le navigateur. L’utilisateur peut voir un avertissement, mais si le serveur accepte quand même la mise à jour, un autre client (ou une nouvelle tentative) peut écraser les données. Le serveur doit être le gardien final.
Les patterns qui causent le plus de pertes :
- Absence du jeton de concurrence dans la requête de sauvegarde (
version,updated_at, ou ETag), le serveur n’a rien à comparer. - Accepter des mises à jour sans condition atomique, par exemple mettre à jour uniquement par
idau lieu de « id + version ». - Utiliser
updated_atavec une faible précision (par exemple des secondes). Deux modifications dans la même seconde peuvent paraître identiques. - Remplacer de gros champs (notes, descriptions) ou des tableaux entiers (tags, lignes) sans montrer ce qui a changé.
- Traiter tout conflit comme un « réessayer », ce qui peut réappliquer des valeurs obsolètes sur des données plus récentes.
Un exemple concret : deux leads support ouvrent le même dossier client. L’un ajoute une longue note interne, l’autre change le statut et sauvegarde. Si votre sauvegarde remplace la charge utile entière, le changement de statut risque d’effacer la note.
Quand un conflit survient, les équipes perdent encore des données si la réponse API est trop maigre. Ne renvoyez pas seulement « 409 Conflict ». Renvoyez assez pour qu’un humain puisse réparer :
- La version courante côté serveur (ou
updated_at) - Les dernières valeurs du serveur pour les champs concernés
- Une liste claire des champs qui diffèrent (même des simples noms)
- Qui a changé et quand (si vous le suivez)
Si vous implémentez cela dans AppMaster, appliquez la même discipline : conservez la version dans l’état de l’UI, renvoyez-la avec la mise à jour, et faites la vérification dans la logique backend avant d’écrire dans PostgreSQL.
Vérifications rapides avant le déploiement
Avant de déployer, faites un passage rapide sur les modes de défaillance qui créent « ça a bien sauvegardé » tout en écrasant silencieusement le travail des autres.
Contrôles données et API
Assurez-vous que l’enregistrement transporte un jeton de concurrence de bout en bout. Ce jeton peut être version (entier) ou updated_at (horodatage), mais il doit être traité comme faisant partie de l’enregistrement, pas comme métadonnée optionnelle.
- Les lectures incluent le jeton (et l’UI le stocke dans l’état du formulaire, pas seulement à l’affichage).
- Chaque mise à jour renvoie le jeton vu en dernier, et le serveur le vérifie avant d’écrire.
- En cas de succès, le serveur retourne le nouveau jeton pour que l’UI reste synchronisée.
- Les éditions en masse et les modifications en ligne suivent la même règle, pas de raccourci spécial.
- Les jobs en arrière-plan qui modifient les mêmes lignes vérifient aussi le jeton (sinon ils créeront des conflits apparemment aléatoires).
Si vous utilisez AppMaster, vérifiez que le champ existe (version ou updated_at) dans le Data Designer, et que votre Business Process de mise à jour le compare avant d’exécuter l’écriture.
Contrôles UI
Un conflit n’est « sûr » que si l’étape suivante est évidente.
Quand le serveur rejette une mise à jour, affichez un message clair : « Cet enregistrement a changé depuis que vous l’avez ouvert. » Puis proposez une action sûre d’abord : recharger les dernières données. Si possible, ajoutez un chemin « recharger et réappliquer » qui conserve les entrées non sauvegardées et les réapplique sur l’enregistrement rafraîchi, pour qu’une petite correction ne devienne pas une séance de retapage.
Si votre équipe en a vraiment besoin, ajoutez une option « forcer la sauvegarde » contrôlée. Restreignez-la par rôle, demandez une confirmation et journalisez qui a forcé et ce qui a été changé. Cela garde les urgences possibles sans faire de la perte de données la règle.
Prochaines étapes : ajouter le verrouillage à un workflow puis étendre
Commencez petit. Choisissez un écran d’administration où les utilisateurs se gênent souvent, et ajoutez le verrouillage optimiste là en premier. Les zones à forte collision sont généralement les tickets, commandes, tarifications et inventaires. Si vous rendez les conflits sûrs sur un écran occupé, vous verrez rapidement le modèle à répéter ailleurs.
Choisissez votre comportement par défaut pour les conflits dès le départ, car il façonne la logique backend et l’UI :
- Bloquer-et-recharger : arrêter la sauvegarde, recharger l’enregistrement le plus récent et demander à l’utilisateur de réappliquer sa modification.
- Revoir-et-fusionner : afficher « vos modifications » vs « dernières modifications » et laisser l’utilisateur décider.
Bloquer-et-recharger est plus rapide à construire et marche bien pour des modifications courtes (statuts, assignation, petites notes). Revoir-et-fusionner vaut le coup pour des enregistrements longs ou à fort enjeu (tableaux de tarification, modifications multi-champs de commande).
Puis implémentez et testez un flux complet avant d’étendre :
- Choisissez un écran et listez les champs les plus modifiés.
- Ajoutez une valeur de version (ou
updated_at) au payload du formulaire et exigez-la à la sauvegarde. - Faites la mise à jour conditionnelle en base (n’écrire que si la version correspond).
- Concevez le message de conflit et l’action suivante (recharger, copier mon texte, ouvrir une vue de comparaison).
- Testez avec deux navigateurs : sauvegardez dans l’onglet A, puis essayez de sauvegarder des données obsolètes dans l’onglet B.
Ajoutez des logs légers pour les conflits. Même un simple événement « conflit survenu » avec le type d’enregistrement, le nom de l’écran et le rôle de l’utilisateur aide à repérer les points chauds.
Si vous construisez des outils d’administration avec AppMaster (appmaster.io), les éléments principaux se mappent proprement : modélisez un champ version dans le Data Designer, imposez des mises à jour conditionnelles dans les Business Processes, et ajoutez une petite boîte de résolution de conflit dans le constructeur d’UI. Une fois le premier workflow stable, répétez la même approche écran par écran et gardez l’UI de conflit cohérente pour que les utilisateurs l’apprennent une fois et lui fassent confiance partout.
FAQ
Un écrasement silencieux survient lorsque deux personnes modifient le même enregistrement depuis des onglets ou sessions différents, et que la dernière sauvegarde remplace les modifications précédentes sans avertissement. Le problème est que les deux utilisateurs voient une « sauvegarde réussie », donc les modifications manquantes ne sont remarquées que plus tard.
Le verrouillage optimiste signifie que l’application n’enregistre vos modifications que si l’enregistrement n’a pas changé depuis que vous l’avez ouvert. Si quelqu’un d’autre a sauvegardé avant vous, votre sauvegarde est rejetée par un conflit afin que vous puissiez consulter les dernières données au lieu de les écraser.
Le verrouillage pessimiste empêche les autres d’éditer pendant que vous travaillez, ce qui crée souvent des attentes, des expirations et des « qui a verrouillé ça ? » dans les équipes. Le verrouillage optimiste convient généralement mieux aux panneaux d’administration parce que les gens peuvent travailler en parallèle et n’interviennent que lorsqu’un vrai conflit arrive.
Une colonne de version est en général l’option la plus simple et la plus prévisible car elle évite les problèmes de précision et d’horloge. Un updated_at peut fonctionner, mais il peut rater des éditions rapides si le timestamp a une faible précision ou s’il est géré de manière incohérente entre systèmes.
Il faut un jeton de concurrence contrôlé par le serveur sur l’enregistrement, typiquement version (entier) ou updated_at (horodatage). Le client doit le lire à l’ouverture du formulaire, le garder inchangé pendant l’édition et le renvoyer à la sauvegarde comme valeur « attendue ».
Parce que le client ne peut pas être considéré comme fiable pour protéger des données partagées. Le serveur doit appliquer une mise à jour conditionnelle du type « update where id = X and version = Y », sinon un autre client, une nouvelle tentative ou un job en arrière-plan peut quand même écraser les modifications silencieusement.
Par défaut, afficher un message bloquant qui indique que l’enregistrement a changé et proposer une action sûre : recharger la version la plus récente. Si l’utilisateur a saisi beaucoup de texte, conservez son entrée non sauvegardée pour qu’il puisse la réappliquer après le rechargement au lieu de tout retaper.
Retournez une réponse de conflit claire (souvent 409) avec suffisamment de contexte pour récupérer : la version actuelle côté serveur et les valeurs récentes. Si possible, indiquez qui a modifié et quand, pour que l’utilisateur comprenne pourquoi sa sauvegarde a été rejetée et ce qui a changé.
Surveillez l’absence du jeton lors de la sauvegarde, les mises à jour qui ne filtrent que par id au lieu de id + version, et les contrôles d’horodatage à faible précision. Également, remplacer des champs volumineux (notes, tableaux) sans montrer ce qui a changé augmente le risque d’effacer le travail de quelqu’un d’autre.
Dans AppMaster, ajoutez un champ version dans le Data Designer et incluez-le dans l’enregistrement lu par le formulaire. Ensuite, faites une mise à jour conditionnelle dans le Business Process afin que l’écriture ne réussisse que si la version attendue correspond, et gérez la branche de conflit dans l’UI avec un flux de rechargement/revue.


