Le brief
Un torréfacteur vend six références sur les marchés et veut ouvrir la vente en ligne. Il a déjà regardé les plateformes du marché : entre l'abonnement mensuel, la commission sur chaque vente et le thème à personnaliser, il paierait plusieurs centaines d'euros par an pour vendre une centaine de sacs.
- Contrainte : pas d'abonnement, pas de commission au-delà de celle du paiement.
- Besoin réel : six produits, une variante (la mouture), et un paiement fiable.
- Non-besoin : comptes clients, codes promo, gestion multi-entrepôts.
Un site statique couvre tout ça. Reste le paiement — et c'est là que la plupart des boutiques « faites main » se trompent.
Le piège : un prix qui vient du navigateur
La tentation, sur un site sans serveur, est de laisser le panier calculer le total et de l'envoyer au paiement. Le problème : tout ce qui vient du navigateur est modifiable par le visiteur. Une console ouverte, deux lignes tapées, et le sac à 19 € part à 1 €.
// le navigateur annonce le prix
payer({
article: "Éthiopie 250 g",
prix: panier.total, // ← modifiable
quantite: 3
});
// le navigateur annonce
// seulement quoi et combien
payer({
lignes: [
{ ref: "ETH-250", qte: 3 }
]
});
// le prix est lu côté serveur
La fonction serveur détient sa propre table de prix. Elle ne lit jamais le montant envoyé par la page : elle reçoit une référence et une quantité, puis calcule elle-même. Un panier trafiqué ne change rien au montant débité.
L'architecture, en trois temps
Le navigateur
Affiche le catalogue, tient le panier en mémoire locale. Aucune donnée n'est envoyée tant que le visiteur ne paie pas.
La fonction serveur
Reçoit des références, applique ses prix, crée la session de paiement. La clé secrète n'existe que là.
Stripe
Héberge la page de paiement. Aucune donnée bancaire ne transite par le site ni n'y est stockée.
Une seule fonction, une centaine de lignes. Le reste du site est statique : il se déploie sur n'importe quel hébergement, y compris gratuit.
Les garde-fous
Écrire la fonction ne suffisait pas : il fallait la rendre difficile à détourner.
- Refus des clés de production. La fonction s'arrête si la clé Stripe n'est pas une clé de test — une démonstration publique ne doit jamais encaisser réellement.
- Adresse de retour restreinte. Après paiement, la redirection n'est acceptée que vers le site lui-même : impossible de détourner le tunnel vers un domaine tiers.
- Références vérifiées. Une référence inconnue fait échouer la demande, plutôt que de créer une ligne à prix nul.
- Quantités bornées. Douze articles par ligne, vingt lignes par commande — de quoi éviter les commandes absurdes.
Enregistrer la commande : pourquoi pas sur la page de remerciement
Le réflexe serait d'enregistrer la commande à l'arrivée sur la page de remerciement. C'est une erreur : cette page dépend du visiteur. Il peut fermer l'onglet juste après avoir payé, perdre le réseau — ou à l'inverse ouvrir l'adresse à la main sans avoir rien acheté.
Seul Stripe sait si l'argent est arrivé. Il l'annonce à une seconde fonction, qui écrit la commande en base.
Ce que cette fonction refuse
- Une signature absente ou fausse. Chaque message de Stripe est signé ; la fonction recalcule la signature et compare — en temps constant, pour que la durée du calcul ne renseigne pas un attaquant.
- Un message vieux de plus de cinq minutes, afin qu'un message intercepté ne puisse pas être rejoué plus tard.
- Un doublon. Stripe réessaie tant qu'il n'a pas de réponse : la commande est identifiée par sa session, et une seconde tentative n'écrit pas une seconde ligne.
Dernier détail, et il compte : le détail des articles n'est pas lu dans le message reçu. La fonction le redemande à Stripe. Le montant enregistré est celui qui a réellement été encaissé, pas celui qu'on nous annonce.
Côté base, la table n'est lisible par personne : aucune règle d'accès n'est ouverte aux visiteurs, et seule la clé de service — côté serveur — peut y écrire.
Puis le courriel de confirmation
Une fois la commande écrite, la même fonction envoie au client le récapitulatif de sa commande. Écrire depuis le serveur de paiement plutôt que depuis le navigateur a la même justification que ci-dessus : un client qui ferme l'onglet reçoit quand même son courriel.
Reste un piège propre à l'envoi : Stripe réessaie les messages restés sans réponse. Une confirmation en double est presque aussi gênante qu'une confirmation absente. L'heure de l'envoi est donc conservée à côté de la commande — le courriel n'est retenté que s'il n'est jamais parti. Et si le service d'envoi refuse le message, la fonction répond en erreur après avoir enregistré la commande : Stripe rappelle, la commande n'est pas dupliquée, le courriel finit par partir.
Le message dit en clair qu'il s'agit d'une démonstration, que rien ne sera expédié et qu'aucune somme n'a été débitée. Écrire à quelqu'un au nom d'une marque fictive sans le préciser ne serait pas acceptable.
Les choix d'interface
- Pas de compte à créer. Un achat de café ne justifie pas un mot de passe. Le panier vit dans le navigateur, le courriel est demandé au moment du paiement.
- La mouture choisie sur la fiche produit, pas après coup : c'est la question que le client se pose devant le sac, pas devant son panier.
- Pas de photographie. Les sachets sont des aplats colorés — un vrai projet utiliserait les photos du torréfacteur, mais la démonstration porte sur la mécanique, pas sur la direction artistique.
- Accessible au clavier, comme le reste du site : lien d'évitement, anneaux de focus visibles, quantités modifiables sans souris.
Ce que la démonstration ne fait pas
Autant le dire, ces limites sont assumées — elles marquent la frontière entre une démonstration et une boutique en production :
- Pas de stock, pas de frais de port calculés, pas de TVA paramétrée.
- Pas de suivi d'expédition après la confirmation, ni de retour marchandise — ce sont des branchements, pas des difficultés.
- Le panier vit dans le navigateur : effacer ses données de navigation le vide.
Chacune se lève en une à deux journées de travail. Ce sont des décisions de périmètre, pas des impasses techniques.
Ce que ce projet démontre
- Le paiement en ligne n'impose pas une plateforme. Six produits et une variante tiennent dans un site statique, sans abonnement mensuel.
- La sécurité tient à un principe, pas à un outil : ne jamais faire confiance à ce que le navigateur annonce.
- Le coût se déplace au bon endroit : l'hébergement est gratuit, la seule commission est celle du paiement.