Aller au contenu

Projections persistées

Status: CURRENT

Rôle

Les projections persistées sont des représentations dérivées, optimisées pour la lecture et destinées aux consommateurs de CMonChoix Platform.

Elles ne constituent jamais une nouvelle vérité métier. Leur contenu doit pouvoir être reconstruit à partir d'un état amont autoritatif et d'un Builder déterministe.

Position dans l'architecture

Domain Core / Vertical Modules
          ↓
   vérité métier résolue
          ↓
  Projection Builder
          ↓
    Write Service
          ↓
 projection persistée
          ↓
Read Services / Frontend / API

Le Builder décide quelles lignes ou quels DTOs dérivés doivent exister. Le Write Service effectue la persistance contrôlée. Le consommateur lit ensuite la projection sans reconstruire la logique métier.

Cette séparation décrit la cible normative. Lorsqu’une implémentation CURRENT combine encore calcul de projection et persistance dans une classe technique, cet écart doit être déclaré comme dette transitoire et non présenté comme le modèle à reproduire.

Pourquoi persister une projection ?

La persistance d'une projection permet :

  • des lectures rapides et stables ;
  • un contrat découplé du Pipeline ;
  • un Frontend simple ;
  • des audits reproductibles ;
  • une reconstruction contrôlée ;
  • plusieurs consommateurs partageant la même représentation.

Elle ne justifie jamais de dupliquer la logique métier dans SQL ou dans le Frontend.

Source de vérité

Une projection doit avoir une source amont clairement identifiée.

Selon la famille, cette source peut inclure :

  • des résultats du Domain Core ;
  • une Canonical Identity ;
  • des offres normalisées ;
  • des Product Models ;
  • des données enrichies validées ;
  • des contrats de projection neutres.

La projection elle-même ne devient pas la source de départ d'une nouvelle décision métier simplement parce qu'elle est persistée.

Familles de projection documentées

La documentation CMonChoix décrit notamment :

  • Product Projection ;
  • Offer Projection ;
  • Navigation Projection ;
  • Homepage Projection ;
  • Canonical Product Projection persistée dans ccx_canonical_products_v1 ;
  • projections Product Models, Variants, Specifications et Gallery ;
  • projections Catalog et autres read models spécialisés.

La disponibilité concrète d'une famille dans le Runtime doit être vérifiée dans le code et les bootstraps actuels avant toute commande opérationnelle.

Canonical Product Projection CURRENT

ccx_canonical_products_v1 est une projection globale de lecture dérivée de ccx_offers_norm_v2 et regroupée par product_identity_key.

Elle sert notamment à fournir un slug produit stable et un résumé agrégé directement consommable par les lectures catalogue.

Invariant de couverture :

identités non vides de ccx_offers_norm_v2
⊆ identités de ccx_canonical_products_v1

Le contrôle ccx health projections rend cet invariant observable via missing_canonical_product_identity.

Le rebuild CURRENT est :

  • global ;
  • protégé par un lock applicatif ;
  • transactionnel sur InnoDB ;
  • fail-closed si la lecture source échoue ;
  • basé sur DELETE + réécriture dans la transaction, pas sur TRUNCATE ;
  • rollbacké si un insert ou le commit échoue.

La commande opérateur certifiée est documentée dans ../cli/rebuild-projections.md.

Cycle de refresh

Après l’upsert de ccx_offers_norm_v2, la finalisation d’un sync appelle ccx_sync_refresh_product_projections($feed). Ce chemin rafraîchit d’abord la projection canonique, puis les projections Product Models des verticales concernées.

Un replay d’offre en mode apply rafraîchit également la projection canonique après le commit de la modification d’offre.

Le frontend ne doit donc pas compenser une ligne canonical absente par une nouvelle règle métier. Une couverture incomplète est un défaut de projection à diagnostiquer et reconstruire.

Frontière CURRENT

La projection canonical suit désormais explicitement la chaîne :

WpdbCanonicalProductOfferReader
        ↓
CanonicalProductProjectionBuilder
        ↓
CanonicalProductProjectionRebuildService
        ↓
CanonicalProductProjectionWriter
        ↓
WpdbCanonicalProductProjectionWriter

Le Reader Infrastructure ne possède aucune agrégation métier. Le Builder Application construit les lignes canonical de manière déterministe et testable sans base ni WordPress. Le Rebuild Service orchestre la lecture et la transaction via des Contracts. Le Writer Infrastructure possède uniquement les opérations techniques de persistance.

Pour des offres à prix égal, la sélection de l’offre gagnante ne dépend jamais de l’URL de tracking. Le départage technique est explicite et reproductible : source_feed, puis merchant_id, puis offer_key, puis offer_id en ultime secours.

Écriture des projections

La persistance doit passer par le Write Service dédié lorsqu'il existe.

La famille actuellement documentée comprend notamment :

  • CCX_OfferProjectionWriteService ;
  • CCX_ProductModelProjectionWriteService ;
  • CCX_ProductVariantProjectionWriteService ;
  • CCX_ProductSpecificationProjectionWriteService ;
  • CCX_ProductGalleryProjectionWriteService.

Pour une reconstruction complète Product Models, l'ordre canonique documenté est :

Product Models
    ↓
Variants
    ↓
Specifications
    ↓
Gallery

La Canonical Product Projection précède cette chaîne lorsque les offres normalisées ont changé.

Avant de lancer une opération réelle, vérifier que les classes et leurs bootstraps sont effectivement chargés dans le contexte visé.

Reconstruction

Une projection est reconstruisible, mais cela ne signifie pas qu'elle peut être détruite sans précaution.

Procédure sûre :

  1. identifier la projection et son périmètre ;
  2. vérifier l'état amont ;
  3. exécuter un audit read-only ;
  4. simuler ou dry-run lorsque disponible ;
  5. reconstruire avec le Builder / orchestrateur prévu ;
  6. persister via la frontière d’écriture prévue ;
  7. relire la projection ;
  8. comparer les KPI, invariants et échantillons avant/après.

Une reconstruction globale ne doit pas être préférée à une reconstruction ciblée sans justification. La projection canonical constitue actuellement une exception d’implémentation : son refresh CURRENT est global et cette limite de scalabilité est documentée comme dette.

Projection et Frontend

Le Frontend consomme une projection ; il ne doit pas :

  • recalculer une identité ;
  • choisir une vérité produit ;
  • fusionner des offres ;
  • recalculer des remises ;
  • reconstruire un arbre métier ;
  • corriger une projection pendant le rendu.

Les shims de compatibilité WordPress peuvent adapter la forme du payload, mais ils ne doivent pas recréer la logique métier.

Données incomplètes

Une projection doit rendre l'absence ou l'incertitude explicite.

Les statuts unknown, ambiguous et conflict, lorsqu'ils appartiennent au contrat amont, ne doivent pas être transformés silencieusement en valeur supposée correcte pour faciliter l'affichage.

Un consommateur peut choisir une présentation différente, mais ne doit pas inventer une donnée métier manquante.

Déterminisme

À état amont, version de règle et configuration identiques, une projection doit produire le même résultat logique.

Pour préserver cette propriété :

  • trier explicitement les collections ;
  • éviter les dépendances à l'ordre implicite SQL ;
  • versionner les règles influençant la forme ;
  • rendre les filtres explicites ;
  • ne pas dépendre d'un cache non identifié.

Diagnostic d'une projection incorrecte

Quand une projection semble fausse :

  1. la donnée amont est-elle déjà incorrecte ?
  2. le Builder a-t-il reçu les bonnes entrées ?
  3. le Builder produit-il le bon résultat en mémoire ?
  4. le Rebuild Service et le Writer ont-ils persisté toutes les lignes attendues ?
  5. la projection lue appartient-elle au bon run ou périmètre ?
  6. le consommateur applique-t-il un shim ou filtre supplémentaire ?
  7. une ancienne reconstruction destructive a-t-elle contaminé l'état ?

Pour ccx_canonical_products_v1, vérifier en plus la couverture offers_norm → canonical avant d’enquêter sur le renderer.

Cette séquence évite de modifier le Frontend pour masquer une erreur de projection, ou de modifier la projection pour masquer une erreur du Domain Core.

Media Quality

Media Quality reste audit-first.

Une projection historique déjà altérée par une ancienne mutation destructive, par exemple un nettoyage de image_norm, ne constitue pas une baseline fiable. Il faut d'abord régénérer l'état dérivé depuis une source saine, puis relancer l'audit ou la comparaison.

Pièges fréquents

Éditer directement une ligne de projection

Le prochain rebuild écrasera la correction et la cause restera présente.

Utiliser la projection comme vérité métier

Cela crée une boucle de dépendance et empêche la reconstruction fiable.

Mettre la logique de projection dans le writer

Le Write Service doit persister une décision déjà construite, pas décider du contenu métier.

Corriger dans le Frontend

Une correction d'affichage peut masquer une anomalie sans corriger la projection pour les autres consommateurs.

Tests attendus

Une projection importante doit être couverte par :

  • tests du Builder ;
  • tests de déterminisme ;
  • tests sur données manquantes et incertaines ;
  • tests du Write Service / store ;
  • tests d'idempotence ou de remplacement scoped ;
  • tests de contrat consommateur ;
  • test de reconstruction sur une fixture représentative ;
  • tests de rollback sur les étapes destructives ;
  • health check de couverture lorsqu’une source et une projection doivent converger.

Invariants

  1. Une projection est dérivée.
  2. Elle est reconstruisible.
  3. Elle ne décide pas de la vérité métier.
  4. Le Builder et le Write Service restent séparés comme cible normative.
  5. Le Frontend ne recalcule pas le métier.
  6. L'incertitude reste visible.
  7. Une reconstruction est vérifiée après écriture.
  8. Une projection contaminée n'est pas utilisée comme baseline fiable.
  9. Une identité source attendue dans une projection de couverture ne doit pas disparaître silencieusement.

Voir aussi