Architecture

Les choix techniques


Chaque technologie justifiée par une contrainte de votre métier.

Pourquoi Go et PostgreSQL

Go produit un binaire unique, sans machine virtuelle ni dépendances système : le déploiement et la mise à jour se réduisent à remplacer un fichier. Sa gestion de la concurrence est sûre par construction, ce qui compte quand plusieurs guichets écrivent simultanément.

PostgreSQL apporte ce dont un système comptable ne peut pas se passer : des transactions ACID réelles, des contraintes différées vérifiées au COMMIT, le cloisonnement par ligne (Row-Level Security) directement dans la base, et une restauration à un instant précis (PITR).

Redis ne sert que de chemin rapide : idempotence, verrous de caisse, limitation de débit. PostgreSQL reste la source de vérité — si Redis tombe, le système ralentit, il ne ment pas.

Nous utilisons pgx et sqlc plutôt qu'un ORM. Sur du code financier, nous voulons voir le SQL exécuté, pas le deviner.

L'argent ne se stocke pas en virgule flottante

C'est le détail qui distingue un système comptable d'un logiciel de gestion.

  • Les montants sont des entiers 64 bits en unités mineures. Jamais float64, jamais REAL en base.
  • Les taux sont en NUMERIC(10,6).
  • XAF et XOF n'ont pas de décimale — l'unité mineure est le franc. Mais les taux de commission produisent des fractions.
  • Tout calcul de commission génère donc un reste d'arrondi, écrituré explicitement sur un compte dédié. Sans cela, la balance dérive d'un franc par opération, et trois mois plus tard personne ne sait d'où vient l'écart.
  • Aucune écriture ne mélange deux devises : une conversion XAF ↔ XOF est deux écritures liées par un compte de position de change.

Le cycle de vie d'une opération

Cycle de vie d'une requête

0.48s mesuré / 2.0s budget

  1. Guichet 3Gclé d'idempotence UUID+320ms
  2. TraefikTLS 1.3 · routage+90ms
  3. IdempotenceRedis · rejeu sans effet+8ms
  4. RBAC + règlesrôle · agence · plafonds+25ms
  5. Écriture ledgerACID · balance = 0+35ms
  6. Scelléaudit chaîné≈ 0.48s

Le plafond de 2 s est un test bloquant de notre chaîne de livraison — pas une intention. Notez l'étape 3 : un retry après coupure rejoue la même clé et ne crée rien.

L'étape 3 est la plus importante et la moins visible : sur un réseau instable, c'est elle qui garantit qu'un caissier qui réessaie après une coupure ne crée pas une seconde opération.

Le mode dégradé est un cas nominal

Le réseau tombera. L'architecture le considère comme normal, pas comme une exception :

  • Le guichet est une PWA avec file locale ; les opérations de caisse et de saisie restent possibles hors-ligne.
  • Chaque opération porte un UUID généré côté client, qui sert de clé d'idempotence. À la reconnexion, le serveur déduplique nativement — pas de résolution de conflit exotique, pas de CRDT.
  • Restent interdites hors-ligne : toute opération exigeant une validation partenaire temps réel, et tout dépassement du plafond de float local.

Ce que nous n'utilisons pas

ÉcartéPourquoi
Kafka / bus de messagesSurdimensionné ; une brique d'infrastructure de plus à exploiter
Micro-servicesCoût d'exploitation sans contrepartie à cette volumétrie
Elasticsearchpg_trgm suffit pour le filtrage flou des listes de sanctions
Kubernetes au démarrageDocker sur un serveur ; on migre le jour où la charge le justifie