Yayaw
Documentation

Produits de facturation

Modèle de catalogue produit et workflow de gestion admin.

Modèle de catalogue

Les produits de facturation sont stockés dans billing_products avec des métadonnées non secrètes :

  • clé produit

  • type (subscription ou one_time)

  • slug de plan

  • intervalle (monthly/yearly le cas échéant)

  • slug de droit optionnel

  • Stripe price ID, géré en interne après synchronisation

  • métadonnées Stripe Product/Price en miroir

  • indicateur actif

  • ordre de tri

Les admins gèrent les prix produit dans Yayaw. Lorsqu'un montant produit est enregistré, Yayaw crée ou met à jour le Stripe Product correspondant, crée un nouveau Stripe Price lorsque le montant, la devise ou l'intervalle change, archive le Price précédent pour les nouveaux checkouts et stocke le Stripe price ID résultant ainsi que les métadonnées Product/Price en miroir. Les secrets Stripe restent dans les variables d'environnement.

Products & Services est la source de vérité pour les noms, prix, types, intervalles, état de synchronisation Stripe et disponibilité checkout des produits de facturation. Les modèles de données CMS ne doivent pas dupliquer ces champs commerciaux.

Les coupons Stripe et codes promotionnels sont répliqués dans :

  • billing_stripe_coupons

  • billing_stripe_promotion_codes

Stripe reste la source de vérité pour les remises ; Yayaw les réplique pour les variables CMS et l'inspection MCP.

Workflow admin

Utilisez les pages admin du tableau de bord :

Capacités V1 actuelles :

  • basculer l'état actif d'un produit

  • modifier le montant et la devise du produit

  • créer et répliquer le Stripe Product/Price via l'API Stripe

  • modifier l'ordre de tri

  • conserver des clés produit stables

Les réglages de facturation couvrent actuellement :

  • jours de période de grâce

  • réglages du dépôt GitHub pour l'accès au code

Les limites de fonctionnalités des plans vivent dans billing_plans et sont lues par les services de facturation à l'exécution. Les quotas média et les limites de sièges doivent être modifiés via le modèle de plan de facturation à l'exécution, pas codés en dur dans les cartes produit.

L'écran du catalogue de facturation

/dashboard/admin/billing-products (« Produits & services », permission de route billing-product:manage) affiche l'écran dashboard.admin.billing-catalog. Le catalogue appartient à la plateforme : c'est donc un écran global, une seule copie pour toute la plateforme, que seuls les Super Admins personnalisent (voir Dashboard). Son écran par défaut montre :

  • cinq chiffres, des décomptes uniquement, puisque les prix sont dans plusieurs devises et ne sont jamais additionnés : les produits, ceux en vente, les abonnements, les produits en paiement unique, et Synchronisation à vérifier (les produits dont la synchronisation Stripe a échoué, est en attente ou n'a pas de prix, la file de travail du même nom de la table) ;

  • Plans : la limite de sièges, la taille maximale d'un fichier et le quota de stockage de chaque plan de facturation, affichés à qui détient billing-plan:read globalement et modifiés par qui détient billing-plan:manage globalement ;

  • les produits dans une table en pleine page de la source system:billing-products, dans l'ordre du catalogue, 20 par page.

Les chiffres et la table listent tous les produits à qui détient billing-product:list globalement, quelle que soit l'organisation active, et une permission d'organisation ne les ouvre jamais. Qui détient aussi billing-product:manage globalement (les Super Admins) modifie un produit depuis sa ligne : un clic ouvre le formulaire avec son prix et sa devise, s'il est en vente et son ordre d'affichage ; la clé produit est en lecture seule. Le serveur vérifie de nouveau chaque modification (billing-product:update, globalement) et synchronise un nouveau prix avec Stripe avant de l'enregistrer.

La table garde les colonnes de la liste (nom, plan, type de produit, périodicité, prix, devise, sync Stripe et en vente affichés ; clé produit, ordre d'affichage, Price ID Stripe et produit Stripe à un clic), ses vues enregistrées et ses favoris (billing-products), et ses files de travail après la vue propre à l'écran : En vente, Hors vente et Synchronisation à vérifier. Les prix s'affichent dans leur devise. Elle propose les modes Tableau, Liste, un Kanban par statut de synchronisation Stripe, dont on ne peut pas déplacer les cartes (un produit se modifie par son formulaire), et des graphiques qui comptent les produits.

L'écran ne lit jamais le texte d'un échec de synchronisation Stripe (seulement s'il y en a un, pour le statut de synchronisation), l'ID de produit Stripe ni aucun secret Stripe, qui reste dans les variables d'environnement. Le Price ID Stripe s'affiche : il désigne un prix dans Stripe et n'accorde rien.

  • Recherche : elle ne lit que du texte : le nom, la clé produit, le plan, le type, la périodicité, le Price ID et le nom du produit Stripe, la devise et le statut de synchronisation, jamais un booléen, un ordre d'affichage ou un prix.

  • Pagination : au plus 100 produits par page (10, 20 ou 50 proposés).

  • Ordre : l'ordre du catalogue par défaut (ordre d'affichage, puis identifiant) ; les noms se trient comme on les lit (« Pro 2 » avant « Pro 10 »), dans la base.

  • Prix : ils ne sont jamais additionnés, moyennés ou comparés, ni dans un chiffre, ni dans un graphique, ni en pied de table.

  • Paramètres d'URL : les paramètres de la table sont indexés par sa source (system:billing-products-…), et view=<id> ouvre une vue enregistrée ou une file de travail.

  • Plans : quand le serveur refuse les limites d'un plan, l'éditeur du plan dit pourquoi.

Un assistant qui prépare un brouillon de cet écran ne lit que les colonnes de la source, jamais l'identifiant d'une ligne ni si la personne peut la modifier ; les assistants listent et modifient les produits avec les outils ci-dessous.

Contenu Produit CMS

Le seed crée un modèle de données global billing-product-content avec une entrée par produit du catalogue de facturation. Chaque entrée est liée par le champ verrouillé catalog_product_key et ne doit contenir que des ajouts éditoriaux: badge, résumé, puces de fonctionnalités, libellé CTA ou état mis en avant.

Utilisez ce modèle pour compléter les variables de catalogue dans les pages ou sections. Utilisez {billing.product.<productKey>.*} et {billing.price.<productKey>.*} pour les noms de produits, prix, Stripe Price IDs et disponibilité checkout.

Workflow d'organisation

Utilisez la page de facturation d'organisation :

  • /dashboard/organization/billing

  • /dashboard/organization/plans

Capacités V1 actuelles :

  • /billing se concentre sur le résumé du plan actif et l'activité interne

  • /plans se concentre sur la sélection de plan et les actions de checkout

  • lancer un checkout d'abonnement

  • lancer un checkout de paiement unique (pro_lifetime)

  • ouvrir le portail de facturation Stripe

  • voir les raisons de désactivation du checkout avant de cliquer sur les actions

L'action du portail de facturation est désactivée jusqu'à ce que l'organisation possède un client Stripe enregistré. Cela évite un échec de portail confus avant que le premier checkout réussi ne crée le client dans Stripe.

Notes opérationnelles

  • Si un produit n'a pas de Stripe price ID synchronisé, un Stripe Price/Product en miroir actif ou comporte une erreur de synchronisation, le checkout est désactivé pour ce produit.

  • Les sessions Stripe Checkout d'abonnement et de paiement unique autorisent les codes promotionnels Stripe.

  • Le seed crée uniquement les lignes de produits manquantes et n'écrase pas les changements de catalogue gérés par opérateur.

  • Les clés produit sont des contrats stables. Ajoutez une nouvelle clé produit pour une nouvelle offre commerciale plutôt que de réutiliser une clé existante avec une sémantique différente.

  • Les Stripe Price IDs sont immuables pour le montant/la devise/l'intervalle. Les changements de montant créent un nouveau Price actif et archivent l'ancien Price pour les nouveaux checkouts.

  • Les données de remise sont répliquées depuis Stripe uniquement pour les usages en lecture. Créez et gouvernez les coupons/codes promotionnels dans Stripe.

  • Le checkout à vie en paiement unique accorde pro_lifetime et crée un grant durable d'accès au code indexé par session de checkout Stripe.

  • Le checkout d'abonnement crée un grant durable d'accès au code indexé par Stripe subscription ID, puis rafraîchit ou révoque ce grant sur les événements d'abonnement.

Workflow MCP

Les outils du plan de contrôle (control plane) exposent le catalogue et le miroir des remises Stripe :

  • yayaw_billing_products_list

  • yayaw_billing_product_update

  • yayaw_stripe_discounts_list

  • yayaw_stripe_discounts_sync

Les écritures nécessitent control-plane:admin, l'autorisation Yayaw billing-product:update et un reason.

Validation

Vérifications utiles après des changements du catalogue de facturation :

bun test src/lib/server/services/billing/billing-products.test.ts
bun test src/lib/server/services/billing/stripe-catalog-sync.test.ts
bun test src/lib/server/services/billing/billing-organization-view.test.ts
bun run test