Passer au contenu principal

Aperçu

L’idempotence garantit que l’exécution de la même opération plusieurs fois a le même effet que son exécution une seule fois. Agatabo utilise des clés d’idempotence pour empêcher les transactions financières en double causées par des problèmes réseau, des doubles-clics accidentels ou des relances système.
Fonctionnement : Chaque opération financière exige un en-tête x-idempotency-key unique. Si la même clé est utilisée deux fois, la deuxième requête est rejetée comme doublon.

Pourquoi l’Idempotence est Importante

Sans protection d’idempotence :
Avec l’idempotence d’Agatabo :

Fonctionnement

Contrainte de Base de Données

Le modèle JournalEntry a une contrainte unique :
Ce que cela signifie :
  • Dans une organisation, chaque idempotencyKey ne peut être utilisée qu’une seule fois
  • Toute tentative de créer une écriture comptable en double échoue avec une erreur de contrainte de base de données
  • La deuxième requête avec la même clé est rejetée automatiquement

Exigence API

Toutes les opérations de mutation exigent l’en-tête x-idempotency-key :
Opérations exigeant une clé d’idempotence :
  • Enregistrement de dépôts (POST /savings)
  • Enregistrement de retraits (DELETE /savings/{id})
  • Création de prêts (POST /loans)
  • Enregistrement de paiements de prêt (POST /loans/{id}/repay)
  • Enregistrement de dépenses (POST /expenses)
  • Création d’actifs (POST /assets)
  • Allocations de réserves (POST /reserve-allocations)
  • Libérations de réserves (POST /reserve-allocations/{id}/release)
  • Distributions de dividendes (POST /dividends/pools, POST /dividends/pools/{id}/distribute)
  • Clôture de période (POST /period-closing/close, POST /period-closing/undo)
Opérations n’exigeant PAS de clé d’idempotence :
  • Requêtes GET (lecture seule)
  • Génération de rapports
  • Consultation de données

Validation de Requête

Le backend valide la clé d’idempotence :
Clé manquante = erreur 400 Bad Request

Générer des Clés d’Idempotence

Responsabilité du frontend : Générer une clé unique pour chaque opération. Format recommandé :
Bonnes pratiques :
  • ✅ Utiliser UUID v4 (aléatoire cryptographiquement)
  • ✅ Inclure un timestamp pour faciliter le débogage
  • ✅ Stocker la clé dans l’état applicatif pendant la requête
  • ✅ Réutiliser la même clé pour les relances de la MÊME requête
  • ✅ Générer une nouvelle clé pour les nouvelles opérations
  • ❌ Ne jamais réutiliser des clés entre opérations différentes
  • ❌ Ne pas utiliser de numéros séquentiels (prévisibles)

Portée de l’Idempotence

Les clés sont portées à l’organisation :
Différentes organisations peuvent utiliser la même clé (la contrainte unique inclut organizationId) Dans la même organisation :

Détection des Doublons

Lorsqu’un doublon est détecté : Requête 1 (première fois) :
Requête 2 (doublon - même clé) :
Erreur de base de données (violation de contrainte unique) interceptée et retournée comme erreur API.

Scénarios Courants

Scénario 1 : Timeout Réseau

Situation :
  1. L’utilisateur soumet le formulaire de dépôt
  2. Timeout réseau (30 secondes, aucune réponse)
  3. Le frontend relance avec la même clé d’idempotence
Résultat :
Gestion frontend :

Scénario 2 : Double-Clic Accidentel

Situation :
  1. L’utilisateur double-clique sur le bouton “Enregistrer le Paiement”
  2. Deux requêtes sont envoyées rapidement
Implémentation frontend :
Même si les deux requêtes atteignent le backend :

Scénario 3 : Relance d’une Requête Échouée

Situation :
  1. La transaction échoue à cause d’une erreur de validation
  2. L’utilisateur corrige l’erreur et soumet à nouveau
Peut relancer avec la même clé si la transaction a échoué :
Point clé : La protection d’idempotence bloque uniquement les transactions réussies.

Scénario 4 : Nouvelle Transaction

Situation :
  1. L’utilisateur enregistre un dépôt avec succès
  2. Il veut enregistrer un autre dépôt
Une nouvelle clé est obligatoire :
Utiliser la même clé serait rejeté :

Gestion des Erreurs

Clé d’Idempotence Manquante

Requête sans clé :
Le frontend doit inclure une clé pour toutes les mutations.

Erreur de Clé en Double

Requête en double détectée :
Que faire :
  1. Vérifier si la transaction originale a réussi
  2. Si elle a réussi : ne pas relancer, afficher un message de succès
  3. Si elle a échoué : relancer avec la même clé
  4. Si vous créez une nouvelle transaction : générer une nouvelle clé

Exemple d’Implémentation Frontend

Gestion complète de l’idempotence :

Logique de Relance

Stratégie de relance sûre :

Bonnes Pratiques

Checklist d’implémentation de l’idempotence :Génération de clé :
  • ✅ Utiliser UUID v4 (crypto.randomUUID())
  • ✅ Générer la clé dans le frontend avant la requête
  • ✅ Stocker la clé dans l’état du composant pendant la requête
  • ✅ Inclure la clé dans tous les appels API de mutation
  • ✅ Journaliser les clés pour le débogage (ne pas les exposer aux utilisateurs)
Gestion des relances :
  • ✅ Réutiliser la même clé pour les timeouts réseau
  • ✅ Réutiliser la même clé pour les erreurs serveur 5xx
  • ✅ Générer une nouvelle clé pour les nouvelles opérations
  • ✅ Vérifier le statut de la transaction avant de relancer un doublon
  • ✅ Implémenter un backoff exponentiel pour les relances
Gestion des erreurs :
  • ✅ Détecter les erreurs de doublon (400/409 avec message “idempotency”)
  • ✅ Vérifier le statut de la transaction originale avant d’afficher une erreur
  • ✅ Afficher “Transaction déjà enregistrée” au lieu d’une erreur générique
  • ✅ Éviter la confusion utilisateur (ne pas dire “échec” si cela a réussi)
UI/UX :
  • ✅ Désactiver le bouton de soumission pendant la requête (empêcher le double-clic)
  • ✅ Afficher un indicateur de chargement pendant le traitement
  • ✅ Vider le formulaire seulement après confirmation du succès
  • ✅ Gérer les timeouts réseau proprement (relance automatique)
  • ✅ Fournir des messages d’erreur clairs
Tests :
  • ✅ Tester le rejet des clés en double
  • ✅ Tester la relance après timeout réseau
  • ✅ Tester les requêtes concurrentes avec la même clé
  • ✅ Tester l’unicité des clés entre opérations

Dépannage

Q : Erreur “idempotency-key header is required” R : Ajoutez l’en-tête x-idempotency-key à la requête :
Toutes les requêtes POST, PUT, DELETE pour les opérations financières exigent cet en-tête.
Q : Erreur “duplicate transaction” immédiatement R : La clé d’idempotence a déjà été utilisée. Soit :
  1. La transaction originale a réussi (vérifier l’historique des transactions)
  2. La clé d’une opération précédente est réutilisée (générer une nouvelle clé)
Solution :

Q : Besoin d’enregistrer des transactions identiques R : Utilisez des clés d’idempotence différentes :
L’idempotence empêche les requêtes en double, pas les transactions en double.
Q : La transaction a échoué mais je ne peux pas la soumettre à nouveau R : Si la transaction a échoué (non créée), vous pouvez relancer avec la même clé :

Q : Combien de temps les clés sont-elles valides ? R : Les clés d’idempotence sont permanentes. Une fois utilisées avec succès, elles ne peuvent pas être réutilisées dans cette organisation. Implication : N’utilisez pas de clés prévisibles (numéros séquentiels, dates seules).
Q : Puis-je utiliser la même clé dans différentes organisations ? R : Oui. La contrainte unique est (organizationId, idempotencyKey) :

Sujets Connexes

Enregistrement des Dépôts

API de dépôt avec idempotence

Création de Prêts

API de prêt avec idempotence

Clôture de Période

Clôture de période avec idempotence

Piste d'Audit

Suivre la prévention des doublons