Une même référence est vendue sous deux marques, dans trois pays et à quatre catégories de clients. L’équipe duplique la fiche pour changer un titre, puis copie le tarif pour ajouter une remise locale. Six mois plus tard, une correction réglementaire est appliquée sur cinq copies sur six, un client voit le prix d’une autre entité et personne ne sait quelle fiche désactiver.
Le problème ne vient pas du nombre de catalogues. Il vient du mélange entre l’objet vendu, sa présentation, son éligibilité et le prix proposé dans un contexte. Lorsque ces concepts partagent une table ou un fichier, chaque différence locale entraîne une duplication. Le système perd alors la capacité d’expliquer ce qui est commun, ce qui varie et pourquoi.
Le vrai enjeu n’est pas de construire une fiche universelle contenant cent options, ni une copie complète par organisation. Le socle sépare produit, offre, publication, catalogue, tarif et règle ; il leur donne un périmètre, une version et une source. La résolution d’un prix devient une décision traçable, pas une succession de conditions cachées.
Dans un projet de développement web sur mesure, cette modélisation protège l’expérience, l’intégration et le run. Ce guide propose une architecture progressive pour mutualiser le cœur sans gommer les marques, contrats, pays et organisations qui donnent réellement un sens différent aux données.
Séparer produit, offre, catalogue et publication
Le produit décrit ce qui existe
Le produit porte l’identité stable, les caractéristiques intrinsèques et les relations techniques. Une référence, une composition, un format ou une compatibilité ne dépend pas directement du canal. Une variante physique possède sa propre identité lorsqu’elle change stock, logistique ou conformité. Un simple texte marketing ne justifie pas une nouvelle référence.
L’offre décrit ce qui est proposé
L’offre relie un produit à un vendeur, un canal, une zone, une période et des conditions. Elle peut être activée sans dupliquer les attributs du produit. Une publication porte le contenu exposé : titre, médias, ordre, libellé et référencement. Un catalogue regroupe des offres selon une intention commerciale ou contractuelle.
Cette séparation évite de faire du catalogue un second référentiel produit. Elle permet qu’une correction de poids se propage partout, tandis qu’un titre de marque reste local. Le modèle Product et Offer de Schema.org illustre aussi la distinction entre l’objet et la proposition commerciale, sans imposer l’architecture interne.
Modéliser organisations et périmètres
Le pays ne suffit pas à représenter le contexte. Une société légale facture, une unité commerciale négocie, une marque publie et un entrepôt prépare. Ces rôles peuvent se recouper ou diverger. Le modèle nomme organisation, relation et responsabilité au lieu de stocker un unique country_id sur toutes les lignes.
Chaque offre et chaque règle possède un périmètre explicite : organisation, canal, segment, contrat, zone et période. Les dimensions inutiles ne sont pas ajoutées « au cas où ». Elles apparaissent lorsqu’un dossier réel exige une décision distincte. Une relation de partage permet à plusieurs entités d’utiliser le même produit sans leur donner le droit de modifier sa définition.
Séparer capacité et portée
Le rôle indique qui peut créer une offre ou valider un tarif ; le périmètre indique pour quelles organisations et marques. Un responsable local peut proposer une variation, tandis qu’un propriétaire groupe valide un attribut commun. Les exports, API et tâches asynchrones transportent ce contexte, pas seulement l’interface.
Distinguer prix, tarif et condition commerciale
Un montant stocké n’explique pas nécessairement un prix. Le tarif est un ensemble de valeurs ou règles applicables à un périmètre et une période. La condition commerciale peut dépendre du client, de la quantité, du contrat, du canal ou d’un palier. Le prix final résulte d’une résolution, avec devise, unité, taxes, arrondi et provenance.
Le système conserve les composants nécessaires à l’explication : prix de base, remise, surcharge, conversion, taxe et total. Il évite d’enregistrer seulement le résultat si celui-ci doit être audité ou recalculé. À l’inverse, une commande conserve le prix accepté et la version des règles ; elle ne recalcule pas l’historique à chaque changement de catalogue.
Par exemple, si un contrat client possède un prix valide à la date d’engagement, alors il prévaut sur le tarif de segment. En revanche, une promotion exclusive ne se cumule pas avec une remise locale. Le moteur doit appliquer ces arbitrages explicites plutôt que l’ordre de création des lignes.
Les règles ont une priorité explicite. Un contrat client peut remplacer le tarif de segment ; une promotion peut s’ajouter ou être exclusive. L’algorithme ne dépend pas de l’ordre arbitraire des lignes. Une ambiguïté produit un conflit visible plutôt qu’un montant choisi au hasard.
Encadrer héritage et variantes locales
L’héritage réduit la répétition : une organisation reçoit la valeur groupe tant qu’elle ne définit pas de remplacement. Mais il doit être visible. L’écran montre valeur effective, source, niveau hérité et date. Une personne peut retirer la surcharge locale pour revenir au groupe sans recopier la valeur actuelle.
Les champs ne suivent pas tous le même régime. Un attribut réglementaire peut exiger une validation par pays. Un texte marketing peut varier par marque. Un identifiant logistique peut être propre à l’entrepôt. Une matrice attribue pour chaque donnée le niveau propriétaire, les niveaux lecteurs et les remplacements autorisés.
Contre-intuitivement, rendre chaque champ configurable fragilise le produit. Les combinaisons explosent, les tests deviennent incomplets et le support finit par programmer dans l’interface. Les invariants restent dans le domaine ; seules les variations possédées, bornées et réversibles deviennent des options.
Versionner dates d’effet et chevauchements
Un catalogue, une offre et un tarif possèdent début, fin et statut. La publication peut être préparée avant sa date. Les fenêtres utilisent un fuseau décidé et une convention claire sur les bornes. Une règle prévue pour le 1er avril ne remplace pas immédiatement la valeur du 31 mars dans les caches.
Le système détecte les chevauchements incompatibles. Deux tarifs de même priorité ne doivent pas couvrir le même produit, segment et période sans règle de résolution. Les contraintes applicatives sont complétées, lorsque le modèle le permet, par des contraintes de base. La documentation PostgreSQL sur les contraintes rappelle leur rôle pour protéger l’intégrité indépendamment de l’interface.
Une commande conserve un instantané opposable : identifiants, montants, devise, règles et version. Elle peut aussi pointer vers les sources pour l’explication. Rejouer le moteur avec les règles actuelles ne constitue pas une preuve du prix accepté hier.
Attribuer une source à chaque donnée
L’ERP peut posséder références comptables et coût ; le PIM, les attributs enrichis ; le moteur commercial, les offres et règles ; le CMS, certains contenus. La matrice descend au niveau de la donnée. Dire « le PIM est maître du produit » reste insuffisant lorsque le statut de vente dépend de l’ERP et la traduction d’une équipe locale.
Une copie locale porte identifiant source, version et fraîcheur. Une correction revient au propriétaire par une commande ou un workflow. L’application ne modifie pas une projection parce que son écran permet d’éditer. Les conflits de source entrent dans une file qualifiée avec la décision attendue.
Éviter le référentiel par export
Un fichier partagé peut servir de transition, mais il reçoit schéma, version, propriétaire et date de sortie. S’il devient le seul endroit où les exceptions sont corrigées, le socle n’est plus la source opérationnelle. Les importations sont idempotentes et rendent les rejets visibles.
Stabiliser identifiants et correspondances
Le produit possède un identifiant interne stable. Les codes ERP, fournisseur, marque ou canal vivent dans des namespaces distincts avec période de validité. Un code affiché n’est pas supposé unique partout. Cette discipline permet à deux organisations d’utiliser le même numéro local sans fusion accidentelle.
Les standards GS1 aident lorsque le métier échange des identifiants globaux, mais ils doivent être appliqués selon leurs règles. Le GTIN présenté par GS1 identifie les articles de commerce ; il ne remplace pas automatiquement l’identifiant d’une offre, d’un contrat ou d’une publication. Le modèle conserve ces objets distincts.
Une fusion ou un remplacement garde les anciens identifiants résolvables. Les commandes historiques pointent vers l’objet utilisé à l’époque. Supprimer un doublon sans redirection peut rendre messages tardifs, documents et rapprochements impossibles à expliquer.
Cas concret : deux marques et trois pays
Cas hypothétique : un fabricant vend la même machine sous deux marques en France, Belgique et Suisse. Les caractéristiques techniques sont communes. Les brochures, garanties et accessoires visibles varient par marque. Les devises, taxes, tarifs et contrats diffèrent par pays et client. L’ancien système duplique six fiches et douze listes de prix.
La cible crée un produit technique, deux publications de marque, des offres par organisation vendeuse et des tarifs datés. Le contrat client porte une condition qui remplace le tarif de segment. La Suisse utilise un contenu réglementaire propre sans copier les attributs mécaniques. Chaque valeur effective indique son niveau et sa version.
Lors d’un changement de puissance, la donnée technique est modifiée une fois et republiée vers les six contextes. Une brochure locale reste bloquée jusqu’à validation. Un prix suisse futur peut être préparé sans affecter les commandes actuelles. Si deux règles commerciales se chevauchent, la publication échoue avant qu’un client ne voie un montant arbitraire.
Le pilote couvre cinquante produits, une marque et deux segments. Les seuils locaux portent sur conflits non résolus, prix sans provenance, temps d’explication et corrections manuelles. Toute erreur de périmètre interrompt l’extension ; la tolérance n’est pas déduite d’un benchmark générique.
Concevoir un back-office qui explique la règle
L’écran ne montre pas seulement un formulaire. Il affiche contexte actif, valeur héritée, surcharge, période, statut et impact. Avant une modification de masse, l’utilisateur prévisualise les produits, offres et organisations touchés. Une validation sépare proposition et publication pour les prix ou données sensibles.
Les erreurs sont actionnables : chevauchement de période, mapping absent, devise incompatible ou droit insuffisant. La personne peut corriger la cause sans ouvrir les journaux techniques. Les opérations de masse produisent un rapport avec succès, rejets et possibilité de reprise bornée.
Le support dispose d’une vue de résolution : pour un client, un produit et une date, elle explique catalogue choisi, offre, règles appliquées et prix final. Le coût caché diminue lorsque cette explication ne nécessite plus trois experts et un export.
Publier des contrats et projections fiables
Les consommateurs reçoivent des événements nommés : produit modifié, offre activée, tarif publié. Ils ne dépendent pas de tables internes. Le contrat inclut identifiants, périmètre, version et date d’effet. Les messages sont idempotents ; une publication répétée ne crée pas une seconde offre.
Une projection par canal sert rapidement les données résolues. Elle conserve sa version et peut être reconstruite. Au moment de la commande, le système revalide les éléments sensibles ou fige le prix selon le contrat. Le cache ne devient pas une autorité silencieuse.
La réconciliation compare objets sources, projections et offres exposées. Elle identifie absents, doublons, conflits de période et mauvais périmètres. Le monitoring relie l’écart à une organisation et à une décision commerciale, pas seulement à un job technique.
Faire vivre les projections en production
Dans le backend PHP et Symfony, une API expose produits, offres et tarifs sans révéler les tables. Doctrine applique contraintes et migrations ; un worker publie les projections et invalide le cache. Les tests d’intégration couvrent dates, priorités, devises et droits, tandis que la CI bloque un déploiement qui introduit un chevauchement non résolu.
L’instrumentation suit entrée, sortie, dépendance et version dans l’observabilité. La journalisation explique chaque calcul sans copier de secrets commerciaux. Le runbook attribue les responsabilités de reprise, le seuil de suspension et la réconciliation ; le rollback retire une publication future sans modifier les commandes déjà acceptées.
Pour qui ce socle devient-il nécessaire ?
Produit, commerce, finance, responsables de catalogue, données, intégration et support participent. Le produit protège les concepts. Le commerce possède les conditions. La finance valide devise, taxes et écritures. Les équipes locales portent les variations. La technique garantit contraintes, publication et reprise.
Pour une boutique mono-entité avec un tarif simple, cette architecture peut être réduite. Dès que plusieurs marques, contrats, canaux ou organisations combinent leurs règles, expliciter les objets évite une dette rapide. Le nombre de produits n’est pas le seul déclencheur ; le nombre de contextes et de décisions compte davantage.
Erreurs fréquentes qui dupliquent le modèle
Copier le produit pour changer le contenu
La copie sépare les corrections techniques et crée des identités concurrentes. Utilisez une publication de marque ou de canal lorsque l’objet physique reste le même.
Stocker seulement le prix final
Sans composants ni version, le support ne peut expliquer un montant. Conservez la décision acceptée et les références nécessaires à son audit.
Empiler des options sans propriétaire
Chaque paramètre ajoute des combinaisons à tester. Une variation sans responsable, date d’effet et retrait prévu devient une règle permanente par accident.
Décider le niveau de mutualisation
Bloc de décision. Mutualisez le produit lorsque son identité et ses attributs ont le même sens. Spécialisez la publication lorsque le contenu ou la visibilité varie. Créez une offre distincte lorsque vendeur, disponibilité ou conditions diffèrent. Isolez un tarif lorsque sa formule, sa devise ou son contrat possède un cycle de vie propre.
Différez la généralisation si l’équipe ne sait pas distinguer produit et offre, si les règles de priorité ne sont pas décidées ou si un prix ne peut pas être expliqué. Refusez une copie d’instance uniquement destinée à tenir une date sans plan de convergence. Priorisez identité, périmètre et dates avant le confort du back-office.
- Mutualiser les faits stables et réellement partagés.
- Versionner les décisions commerciales et leur période.
- Rendre l’héritage visible plutôt que copier sa valeur.
- Isoler une capacité seulement si son propriétaire et son run sont distincts.
Plan d’action sur huit semaines
Semaines 1 et 2 : cartographier les décisions
Choisissez vingt produits et cinq commandes qui couvrent marques, pays, contrats et périodes. Reconstituez produit, offre, publication, prix et règle. Nommez propriétaires, identifiants et sources. Les ambiguïtés deviennent un backlog de décisions, pas des colonnes génériques.
Semaines 3 à 5 : construire le noyau et migrer
Créez les concepts, contraintes et mappings. Migrez un périmètre par lots idempotents avec balance. Le nouveau moteur résout les prix en parallèle sans les exposer. Les équipes comparent valeurs, provenance et conflits avec les commandes historiques.
Semaines 6 à 8 : publier et éprouver
Ouvrez une organisation et un canal. Provoquez chevauchement, mapping absent, règle future et reprise d’import. Le support explique le prix depuis l’identifiant de commande. Le rollback ferme les nouvelles publications sans effacer celles déjà acceptées. Étendez après un cycle représentatif.
Le bilan rapproche prix calculés, commandes figées, conflits, interventions manuelles et temps d’explication. D’abord, l’équipe ferme les erreurs de périmètre ; ensuite, elle réduit les règles sans provenance ; puis elle ajoute une organisation. Toute option sans propriétaire est différée ou supprimée avant la tranche suivante.
Les entrées, sorties et dépendances de chaque publication sont jointes au contrat avec les responsabilités. L’instrumentation vérifie le seuil de conflits avant activation ; le monitoring suit les projections ; le rollback retire le tarif fautif sans recalculer les commandes, tandis que le runbook guide la réconciliation.
- Séparer les concepts depuis des commandes réelles.
- Fermer périmètres, priorités, versions et sources.
- Comparer la résolution cible à l’historique.
- Ouvrir progressivement avec réconciliation et support.
Guides complémentaires pour les règles locales
Traiter devises et taxes
Le guide des devises, taxes et règles locales approfondit arrondis, dates et responsabilités financières.
Encadrer les variations
La modélisation des variations locales aide à choisir configuration, politique ou module sans casser le cœur partagé.
- Expliquer la valeur effective depuis son niveau d’héritage.
- Conserver la version de prix avec la commande acceptée.
- Refuser les chevauchements sans règle de priorité métier.
Conclusion : expliquer chaque différence
Un socle multi-catalogue robuste ne réduit pas toutes les données à une fiche. Il donne une identité et un cycle de vie à chaque fait, contenu, offre et décision commerciale.
La priorité est de séparer produit, publication, offre et tarif, puis de fermer périmètres, versions et sources. L’héritage devient utile lorsqu’il reste visible et réversible.
Le meilleur test tient dans une commande : l’équipe doit expliquer pourquoi ce produit était visible, quelle règle a produit ce prix et quelle organisation l’a engagé à cette date.
Dawap peut accompagner la conception de ce modèle, sa migration et ses outils dans une stratégie de développement web sur mesure. Le résultat est un socle qui accepte les différences réelles sans les transformer en copies incontrôlables.