Contexte
Tigmi vend de l’artisanat et de la décoration d’intérieur : tapis noués, poterie tournée, laiton ciselé, luminaires, cuir, textile de maison.
Ce catalogue pose un problème que les produits de série n’ont pas. Chaque pièce est unique, ou presque. Un tapis noué existe en un exemplaire, ses dimensions ne se déclinent pas en tailles, et une rupture de stock n’est pas un réapprovisionnement : c’est une disparition.
Le problème
Trois langues, dont une qui retourne la page. La clientèle lit le français, l’anglais ou l’arabe. Traduire ne suffit pas : l’arabe s’écrit de droite à gauche, ce qui inverse la mise en page entière, pas seulement le texte.
Le prix n’est pas une donnée, c’est un calcul. Il se déduit du produit, d’une promotion éventuelle, d’un port qui dépend de la zone, d’un seuil de gratuité et d’un régime de TVA. Chacune de ces règles est simple ; c’est leur combinaison qui produit les erreurs de facturation — et, si l’on n’y prend garde, les fraudes.
Renommer un produit ne doit pas coûter son référencement. Sur une boutique, les intitulés bougent. Si l’adresse change sans filet, la page repart de zéro dans les moteurs.
Ce que nous avons fait
Le prix facturé est toujours recalculé côté serveur. La requête ne transporte que des choix — adresse, transporteur, moyen de paiement. Le prix, la remise, le port et la taxe viennent d’un seul service. Un test vérifie qu’un montant injecté dans le formulaire est purement et simplement ignoré.
C’est la garantie la moins visible d’une boutique en ligne, et la seule qui empêche qu’on s’y serve.
Les adresses sont traduites, pas préfixées. Les slugs vivent dans une table indexée en unique sur la langue et le slug : une URL se résout en une requête indexée, ce qu’un slug rangé dans une colonne JSON ne permet pas. Les anciens slugs continuent de répondre et renvoient une redirection permanente vers le slug courant. Les slugs arabes gardent leurs caractères d’origine plutôt que d’être translittérés en alphabet latin.
Dix entités partagent deux écrans d’administration. Catégories, ateliers, articles, rubriques, pages, FAQ, carrousel, témoignages, transporteurs et zones passent par un CRUD générique : une déclaration décrit colonnes et champs, la validation multilingue et les slugs en découlent. Moins de code à maintenir, et surtout un comportement identique partout — ce qui évite qu’une entité se comporte différemment des neuf autres pour de mauvaises raisons.
Les rappels de paiement sont vérifiés puis journalisés sous contrainte d’unicité. Un webhook rejoué par le prestataire — cela arrive — ne produit ni double encaissement ni double événement.
Sous franchise en base de TVA, le taux est à zéro et aucune ligne de taxe n’apparaît : les prix sont annoncés nets, comme la loi l’exige. Un taux non nul réactive le calcul sans rien changer d’autre.
Le résultat
Une boutique complète en trois langues, du catalogue au suivi de commande.
Le référencement est en place dès la première mise en ligne : adresses traduites, redirections permanentes sur les anciens slugs, données structurées et équivalences de langue déclarées. Ce sont des choses qu’on ajoute rarement après coup sans tout reprendre.
Un mot sur le cache, parce que le choix est contre-intuitif. Il ne contient jamais de modèle Eloquent, seulement des identifiants et des scalaires : un modèle sérialisé ne se relit pas de façon fiable depuis un cache partagé, et l’on s’en aperçoit en production, six mois plus tard, sur une erreur incompréhensible. Les listes sont réhydratées en une requête indexée.