Une demande est marquée « approuvée » et un email a été envoyé. Pourtant, personne ne peut expliquer quelle version a été examinée, si l’acteur avait encore l’autorité nécessaire ou si une nouvelle tentative a créé un doublon. La valeur d’un champ ne suffit pas à établir la validité d’une décision.

Définir l’invariant métier

L’opération exécutée doit correspondre à la version effectivement autorisée. Une modification du montant ne doit pas hériter silencieusement de l’approbation précédente. Les droits dépendent du rôle mais aussi du périmètre : un responsable d’un service ne doit pas approuver les demandes d’un autre. L’institution doit décider si une correction entraîne un amendement, une nouvelle approbation ou une annulation.

Vérifier version et autorité dans la transaction

Le client transmet la version attendue et une clé stable de commande. L’identité vient du contexte authentifié côté serveur. Une transaction vérifie l’état faisant autorité, applique la transition conditionnelle, enregistre l’audit et conserve le résultat de la commande. Une contrainte d’unicité ou un verrouillage adapté protège les tentatives concurrentes ; une simple recherche préalable de la clé ne supprime pas la course.

Commande : approuver(id_demande, version_attendue, clé)
Vérifier l’acteur, le périmètre et la transition
Protéger la clé de commande contre la concurrence
Vérifier l’état et la version attendus
Enregistrer décision, audit et résultat ; valider
Reprise identique : retourner le résultat enregistré

Ce pseudocode n’est pas une réalisation complète. Il faut définir le périmètre des clés, comparer les charges utiles, traiter leur expiration et choisir une stratégie de concurrence. Les niveaux d’isolation PostgreSQL n’offrent pas tous les mêmes garanties. Le comportement doit être testé avec deux sessions concurrentes.

Séparer décision et notification

L’échec d’un email ne doit pas annuler une décision déjà validée. La transaction peut enregistrer une intention de notification, traitée ensuite par un worker. Le modèle transactional outbox traite cette frontière de double écriture. Des livraisons répétées restent possibles : le consommateur doit les reconnaître. La validité de l’approbation et l’envoi de l’email sont deux faits différents.

Traiter une réponse perdue

Une coupure après validation peut laisser le client dans l’incertitude. Réutiliser la même clé permet de rapprocher la nouvelle tentative du résultat déjà enregistré. Une nouvelle clé risque de créer une nouvelle opération. L’interface doit distinguer brouillon non transmis, demande acceptée et résultat encore inconnu.

Les vérifications utiles

  • Deux approbations concurrentes sur la même version n’exécutent pas deux transitions.
  • Une réponse perdue suivie d’une reprise conserve le résultat initial.
  • Une clé réutilisée avec un contenu différent est refusée.
  • Une demande modifiée impose une nouvelle revue de la version actuelle.
  • Un worker arrêté peut reprendre les notifications après redémarrage.

Le métier définit l’autorité. L’architecture la traduit en règles d’état, de concurrence et de reprise. La réalisation doit démontrer ces règles. C’est cette continuité qui rend la décision défendable.

Références techniques