Flow — Paiement marchand par carte physique
Le consumer paie un marchand en tapant les 6 derniers chiffres du card_number imprimé sur la carte physique du marchand (8 caractères au total, préfixés par MERCHANT_CARD_PREFIX).
Sequence diagram
Trust boundaries traversées
| Étape | Crossing | Contrôle |
|---|---|---|
| 3 | App consumer → Orchestrator | JWT + guards |
| 5 | Préfixage card_number | Variable d’environnement MERCHANT_CARD_PREFIX (default 63) |
| 6 | Lookup carte | UNIQUE PARTIAL sur card active par POS |
| 12 | Risk preflight | scope risk:evaluate |
| 18 | Ledger écriture | metadata.posId persisté |
Spécificités carte marchand
- 6 chiffres saisis par l’utilisateur (UX optimisée pour comptoir et feature phones).
- Préfixe
MERCHANT_CARD_PREFIX(env, default63) ajouté côté serveur pour reconstruire lecard_number8 caractères complet (cf. ADR-0005). - Carte = POS :
cards.pos_idest UNIQUE PARTIAL → identification précise du point de vente qui encaisse. - Brute-force protection : à rate-limiter côté API (cf. known-gaps).
- Legacy :
merchants.merchant_code6 chiffres est déprécié mais encore lu en ILIKE pour rétro-compatibilité.
Pré-conditions
- Merchant KYB validé, au moins un POS actif.
- Carte physique active, liée à un POS (UNIQUE PARTIAL).
- Consumer KYC validé, solde suffisant.
Post-conditions
| Entity | État |
|---|---|
| Wallet consumer | - (montant + frais) |
| Wallet merchant | + montant |
| Wallet commissions Nex | + frais |
intents | status completed, metadata.posId = POS de la carte |
| Audit trail | trace card_number (suffixe seulement masqué dans les logs publics) |
Acceptance criteria (Gherkin)
gherkin
Scenario: Paiement carte marchand valide
Given une carte active 63123456 liée au POS-X du merchant M
And un consumer avec 50 000 XAF de solde
When le consumer tape "123456" + montant 8 000 XAF
Then le serveur préfixe en "63123456" et résout POS-X
And le risk preflight renvoie "approved"
When le consumer confirme avec son PIN
Then le wallet M reçoit 8 000 XAF
And l'intent persiste metadata.posId = POS-X
Scenario: Carte désactivée
Given une carte avec statut "inactive"
When un consumer tente un paiement avec son suffixe
Then le lookup échoue
And l'intent n'est pas créé
Scenario: Brute-force sur les 6 chiffres
Given un attaquant qui teste plusieurs combinaisons à la suite
When le seuil de rate limit est dépassé
Then les tentatives suivantes sont rejetées
And un événement de sécurité est journalisé