Le système de boutique en ligne existe parce qu’un vendeur local qui tient sa boutique dans un fil de discussion finit par perdre une commande. Ce qui remplace le fil est volontairement sans éclat : un catalogue avec recherche et filtres, une fiche produit qui montre le stock avant le geste, un panier qui n’est jamais ambigu sur la boutique à laquelle il appartient, et une commande qui traverse cinq états nommés avec notification à chaque transition.
La fiche produit : variantes, stock et remise, avant le clic
Chaque produit porte des photos, une description, un stock et un prix qui peut être remisé — prix soldé à côté du prix barré, avec un badge de pourcentage, pour que l’ampleur de la remise soit lisible plutôt que sous-entendue. Une rupture de stock est dessinée par-dessus la photo, pas découverte au paiement. Règle générale de l’app : ce qui change ce que fait un geste doit être visible avant le geste.
Les variantes sont engendrées à partir d’attributs plutôt que saisies une à une. Le vendeur déclare les axes — taille, couleur, ce sur quoi le produit varie réellement — et les combinaisons deviennent des variantes portant chacune son stock. Cela évite l’erreur classique : trois fiches distinctes pour la même chemise, impossibles à agréger dans un rapport, avec un compteur de stock juste pour l’une des trois.
Le panier appartient à une seule boutique
Ajouter un article d’un autre vendeur demande confirmation avant de vider le panier, plutôt que de construire discrètement un panier réparti sur quatre commerces. C’est un refus de conception : un panier multi-boutiques suppose un paiement unique, un calcul de livraison unique et un responsable unique quand quelque chose n’arrive pas — trois choses inexistantes quand les vendeurs sont quatre commerces indépendants.
Une boutique par panier, volontairement. Changer de boutique propose de vider le panier. Un panier couvrant plusieurs vendeurs exigerait un paiement unique pour être honnête, et il n’y a pas ici de paiement à l’échelle de la place de marché : chaque commande lie un acheteur à un seul commerce.
Les frais de livraison ne sont pas un champ envoyé par l’app. Ils sont lus dans la fiche de la boutique, sur le serveur, au moment de la commande, et ne s’appliquent qu’à la livraison.
Paiement : livraison ou retrait, et des frais que le client ne fixe pas
Le paiement pose les questions dont une commande a besoin : livraison ou retrait, nom, téléphone, adresse, note et mode de règlement. Choisir le retrait supprime les frais au lieu d’afficher zéro, car ces deux états veulent dire des choses différentes. Les adresses viennent d’un carnet avec adresse par défaut — un seul carnet, partagé avec le profil, parce qu’une adresse de profil et une adresse de livraison sont le même fait et que le stocker deux fois garantit que les deux copies finiront par diverger.
Les frais eux-mêmes sont côté serveur : place_shop_order lit businesses.delivery_fee dans la base et ignore la valeur soumise par le client, exactement comme le service à table calcule chaque ligne. Ce n’est pas une option désactivable dans les réglages, c’est l’endroit d’où vient le nombre.
Cinq états de commande, un suivi, les deux parties notifiées
Une commande passe par en attente, confirmée, en préparation, expédiée et livrée, avec annulée et refusée comme branches terminales. L’acheteur voit une barre de progression plutôt qu’un mot d’état isolé, donc « en préparation » se lit comme une position dans une suite, avec quelque chose après. Un numéro de suivi est attaché à l’étape d’expédition, avec un transporteur choisi dans une liste tenue par l’administration qui porte un modèle d’URL de suivi : le numéro saisi par la boutique devient donc un lien que l’acheteur peut ouvrir. Une boutique ne peut pas attacher un numéro sans nommer de transporteur, car un numéro dont on ignore l’émetteur ne pourra jamais devenir un lien. Il reste visible pour l’acheteur ensuite.
Les deux fins portent un motif. Le client qui annule doit dire pourquoi, la boutique qui refuse aussi, et le motif voyage avec la commande au lieu d’être un message qui défile dans une conversation. Chaque transition notifie les deux parties, parce qu’un parcours de commande sans notifications laisse les boutiques rater des commandes et les acheteurs deviner.
- en attente — passée, la boutique doit répondre
- confirmée — acceptée, la boutique s’engage
- en préparation — en cours de préparation
- expédiée — partie, avec un numéro de suivi
- livrée — close, et l’acheteur devient éligible à l’avis
Le côté vendeur : caisse, commandes en ligne et stock
Un commerce de détail obtient trois tuiles : une caisse pour la vente au comptoir, une console de commandes en ligne pour tout ce qui est passé par l’app, et produits et stock avec alertes de seuil bas. Le tableau de bord porte des pastilles rafraîchies toutes les quelques secondes, donc une nouvelle commande s’annonce au lieu d’attendre qu’on la découvre. Vendre en boutique et vendre par l’app écrivent dans le même registre.
Comme les deux canaux atterrissent au même endroit, les rapports couvrent tout le commerce et pas seulement la part en ligne : chiffre d’affaires, nombre de commandes, panier moyen, répartition espèces / PromptPay / autre, cinq meilleures ventes, histogramme du chiffre d’affaires sur sept jours, et périodes aujourd’hui, 7 jours, 30 jours ou tout. Les reçus se réimpriment, et un reçu ou un texte de facture partageable se génère depuis la même écriture. La liste de clients se construit sur ce registre elle aussi — avec notes et étiquettes par client, historique d’achats, points de fidélité accumulés à un taux fixé par le commerce dans sa propre devise, contre une vente minimale et une récompense configurables.
L’accès du personnel passe par une matrice de permissions avec préréglages de rôles et dérogations individuelles, pour qu’un vendeur puisse recevoir les produits et les commandes sans la paie ni les rapports. La même matrice existe en base sous la forme has_capability(business_id, capability), qui développe les préréglages côté serveur pour les politiques de sécurité au niveau des lignes : le serveur ne croit jamais le client sur parole quant au rôle de quelqu’un.
Deux registres voisins partagent la même logique d’inventaire. Ce qu’un commerce possède sans le vendre — outils, machines, mobilier — vit dans le registre des actifs, et ce qu’il prête contre caution passe par les locations.
Les avis produit, réservés à ceux qui ont acheté
Les avis produits sont distincts de l’avis sur le commerce, et tous deux sont filtrés de la même façon : seul un client dont la plateforme peut prouver la transaction peut en écrire un. L’éligibilité est une vue en base, et l’achat est l’un des types qualifiants, aux côtés du repas sur place, de la livraison, du séjour et du recours à une prestation. Tous les autres voient une carte verrouillée expliquant pourquoi il n’y a pas de bouton d’écriture, plutôt qu’un bouton qui échoue.
La note en étoiles n’est pas un nombre stocké que quelqu’un modifie. Un déclencheur en base la recalcule à partir des lignes d’avis — le mécanisme que détaille la page confiance et sécurité —, donc la note de la carte du commerce et les avis de la page ne peuvent pas diverger. Un acheteur peut modifier son dernier avis, le supprimer, ou en ajouter un nouveau lors d’un achat suivant pendant que l’ancien reste ; le commerce peut répondre publiquement.