Aller au contenu
Grégory BresolinMe contacter
Tous les projets

PrixGagnant

Calculateur qui dit sur quelle plateforme de revente on encaisse le plus, frais déduits — site statique, calcul dans le navigateur, aucun backend ni traqueur.

Année
2026
Cadre
Projet personnel
Statut
livré
Stack
Astro, TypeScript, Tailwind CSS, Vitest

Voir le projet en ligne →

Contexte

Le site répond à une question : où vendre un objet pour toucher le plus ? On saisit un prix, et on voit ce qu’on encaisse réellement sur Vinted, eBay, leboncoin et Rakuten une fois tous les frais déduits — ligne par ligne, avec le délai de versement et l’effort que chaque canal demande. Le mode inverse répond à la question posée dans l’autre sens : pour toucher tel montant, voilà le prix à afficher.

J’ai passé une partie de mes douze ans à mon compte sur des comparateurs de prix. Celui-ci ne compare pas des prix : il compare ce qu’il reste au vendeur, et c’est un problème d’une autre nature — les grilles tarifaires sont publiques, mais chacune a sa propre façon de compter.

Le raisonnement produit tient en une phrase : un article qui explique les frais Vinted se fait absorber par les résumés générés par les moteurs de recherche, un calculateur non — le moteur n’a pas les chiffres de l’utilisateur, il ne peut pas répondre à sa place. Tout le reste en découle : chaque page porte une grille réelle et un calcul qui fonctionne, jamais du texte autour d’un mot-clé.

Contraintes

Le site n’a qu’un argument : l’exactitude. Aucun tarif inventé, aucune extrapolation : chaque plateforme porte un drapeau verified et la date de son dernier contrôle, et une grille non vérifiée n’apparaît pas dans le build de production — ni page, ni ligne dans le comparateur. La conséquence est assumée : tant qu’aucune grille n’est vérifiée, le build sort un site sans comparateur.

Le domaine a vingt ans. Je l’ai acheté en 2006, un an avant de me mettre à mon compte, et il a porté mon site de codes promos. Un domaine avec ce passé est surveillé : pas de blog, pas de page produite par variation de mot-clé, pas de scraping. Les anciennes URLs encore indexées répondent 410 Gone, et surtout pas une redirection vers l’accueil — rediriger en masse d’anciennes URLs vers la racine est le signal même de l’abus de domaine expiré, et le fait que celui-ci n’ait jamais changé de main ne change rien à ce qu’en voit un moteur.

La maintenance doit tenir en deux heures par an, le temps de relever les grilles quand elles bougent — une à deux fois l’an. D’où un site entièrement statique, et toute la connaissance métier dans un fichier par plateforme : mettre à jour un tarif, c’est éditer ce fichier, jamais du code. Si le moteur de calcul doit être touché pour changer un pourcentage, l’architecture est ratée.

Décisions d’architecture

Le mode inverse résout par dichotomie, pas par algèbre

objectif / (1 - taux) est faux dès qu’un seuil est franchi — un palier, un plancher, un plafond — et le résultat reste plausible, donc l’erreur ne se voit pas. Le mode inverse fait donc de la dichotomie sur la fonction de calcul directe : une seule implémentation du métier, qu’on interroge dans les deux sens. Un test verrouille l’aller-retour prix → net → prix, qui doit retomber au centime sur les quatre plateformes.

Ce qui a compliqué l’affaire : Rakuten facture une commission fixe en escalier — 0,05 € jusqu’à 5 €, 0,10 € jusqu’à 10 €, et ainsi de suite. Un escalier rend le net non monotone : à 5,00 € pile la commission est de 0,05 €, à 5,01 € elle passe à 0,10 € et le net redescend. Le bon prix devient une solution isolée, que la dichotomie saute : le mode inverse renvoyait 5,07 € — un prix qui atteint bien l’objectif, mais qui n’est pas le meilleur. Les seuils étant connus d’avance, ils sont énumérés et testés explicitement après la dichotomie.

Deux dimensions qu’on confond une fois sur deux

L’erreur la plus intéressante du projet était dans le modèle, pas dans le code. Qui paie les frais de port et sur quoi la commission est prélevée sont deux dimensions indépendantes : le port peut être payé par l’acheteur — donc ne rien coûter au vendeur — et malgré tout entrer dans l’assiette de la commission. C’est le cas d’eBay, dont la page officielle dit noir sur blanc que le montant retenu inclut les frais d’expédition.

La première version ajoutait mécaniquement le port à l’assiette dès que la plateforme calculait sur le total payé. C’est juste quand le port est facturé en plus, et faux en livraison offerte : l’acheteur ne paie alors que le prix affiché, port déjà compris dedans, et l’ajouter le comptait deux fois. Sur un objet à 70 € avec 6 € d’étiquette, eBay sortait à 55,73 € au lieu de 56,36 €. Trois tests verrouillent les deux situations, et le fait qu’à charge égale les deux façons de vendre donnent le même net.

Ce qu’on ne sait pas s’affiche à côté du résultat

Rakuten reverse au vendeur une participation aux frais d’envoi dont le montant dépend du produit et du mode de livraison, et qu’il ne publie pas. Impossible à modéliser sans inventer. Deux mauvaises réponses se présentaient : retirer le port du calcul surestime le net, le passer sous silence donne un chiffre présenté comme exact alors qu’il ne l’est pas. Le port est donc déduit en entier — l’hypothèse prudente — et la réserve s’affiche à côté du résultat, pas reléguée en note de bas de page.

Même règle quand une grille ne tranche pas qui paie le port : le calcul retient le vendeur. Surestimer ce qu’on va toucher, c’est tromper l’utilisateur ; sous-estimer ne fait que lui réserver une bonne surprise.

Arbitrages

  • Aucun backend, aucune base, aucun compte. Le calcul se fait entièrement dans le navigateur. On y gagne un hébergement au coût marginal nul, aucune donnée personnelle à protéger et rien à maintenir en ligne ; on y perd toute mesure fine des usages — le seul signal disponible est le trafic.
  • Quatre plateformes, pas une de plus. Le périmètre n’est pas un objectif de couverture : c’est le plus petit produit capable de dire si l’idée tient. L’architecture rend l’ajout d’une cinquième trivial — un fichier de configuration, aucune ligne de code métier — précisément pour qu’elle attende un signal d’usage plutôt que d’être ajoutée à l’aveugle.
  • L’accueil n’est pas la porte d’entrée du référencement. Ce sont les quatre pages plateforme, chacune sur une requête précise. Demander à l’accueil de se positionner sur les mêmes requêtes la ferait concourir contre ses propres pages, alors qu’elle est la plus autoritaire du site.
  • Déploiement en FTPS, et non en SSH — l’arbitrage inverse de celui retenu pour ce site-ci. o2switch limite le SSH à cinq IP en liste blanche, ce qu’un runner GitHub qui change d’adresse à chaque exécution ne peut satisfaire sans un jeton cPanel, lequel ouvre tout l’hébergement. Un compte FTP cloisonné au seul dossier du site est de moindre privilège : divulgué, il ne donne accès à rien d’autre. La fusion vers main met en ligne, après tests, typage et contrôles du build.

Résultat

En production depuis le 20 août 2026, construit en une semaine. Huit pages, 71 tests sur le moteur de calcul et sur les grilles, environ 4 300 lignes hors tests.

100 en performance, en accessibilité, en bonnes pratiques et en référencement au Lighthouse mobile, mesuré sur l’URL de production. Deux réserves, pour que ce score ne serve pas d’alibi : ce sont des mesures de laboratoire, et les données de terrain ne remonteront qu’avec du trafic ; un automate ne contrôle qu’environ un tiers des critères d’accessibilité, et le contraste des bordures de contrôle — un point encore ouvert sur les onglets inactifs — n’en fait pas partie.

Le premier écran pèse 133 Ko, dont 117 de polices : le reste — HTML, CSS, JavaScript du calculateur et favicon — tient en 16 Ko compressés, pour huit requêtes et aucun appel à un tiers.

Reste un contrôle, et c’est le plus important : confronter une grille à une vraie facture de vente. Les quatre ont été vérifiées sur les pages officielles des plateformes, mais une page de tarification ne dit pas tout ce qu’une facture révèle.