Schéma de base de données pour plans et entitlements : mises à niveau et add-ons
Un schéma de base de données pour plans et entitlements qui gère upgrades, add-ons, essais et révocations sans règles codées en dur, via des tables claires et des vérifications temporelles.

Pourquoi les plans et les fonctionnalités deviennent vite compliqués
Sur une page tarifaire, les plans semblent simples : Basique, Pro, Entreprise. Le désordre commence au moment où vous transformez ces noms en règles d'accès réelles dans votre application.
Coder en dur les vérifications de fonctionnalités (comme if plan = Pro then allow X) fonctionne pour la première version. Puis le pricing change. Une fonctionnalité passe de Pro à Basique, un nouvel add-on apparaît, ou une vente inclut un bundle personnalisé. Soudain vous avez la même règle copiée dans les API, l'interface, les apps mobiles et les jobs en arrière-plan. Vous changez un endroit et en oubliez un autre. Les utilisateurs le remarquent.
Le second problème, c'est le temps. Les abonnements ne sont pas une étiquette statique ; ils changent en cours de période. Quelqu'un upgrade aujourd'hui, downgrade le mois prochain, met en pause ou annule avec du temps payé restant. Si votre base ne stocke que le « plan actuel », vous perdez la timeline et vous ne pouvez plus répondre à des questions basiques : à quoi avaient-ils accès mardi dernier ? Pourquoi le support a-t-il approuvé un remboursement ?
Les add-ons empirent les choses car ils traversent les plans. Un add-on peut débloquer des sièges supplémentaires, supprimer une limite ou activer une fonctionnalité spécifique. On peut l'acheter sur n'importe quel plan, le retirer ensuite ou le garder après une descente de gamme. Si la règle est incrustée dans le code, vous finirez avec une pile croissante de cas particuliers.
Voici les situations qui cassent habituellement les designs naïfs :
- Upgrade en cours de période : l'accès doit changer immédiatement, la facturation en prorata peut suivre d'autres règles.
- Downgrade planifié : l'accès peut rester « supérieur » jusqu'à la fin de la période payée.
- Grandfathering : d'anciens clients conservent une fonctionnalité que les nouveaux n'obtiennent pas.
- Offres personnalisées : un compte obtient la Fonction A mais pas la Fonction B, alors qu'ils partagent le même nom de plan.
- Besoins d'audit : support, finance ou conformité demande « qu'est-ce qui était activé et quand ? »
L'objectif est simple : un modèle de contrôle d'accès flexible qui suit l'évolution du pricing, sans réécrire la logique métier à chaque fois. Vous voulez un seul endroit pour demander « peuvent-ils faire ceci ? » et une trace en base qui explique la réponse.
À la fin de cet article, vous aurez un motif de schéma que vous pouvez copier : plans et add-ons deviennent des entrées, et les entitlements deviennent la source unique de vérité pour l'accès aux fonctionnalités. La même approche convient aussi aux constructeurs no-code comme AppMaster, car vous pouvez garder les règles dans des données et les interroger de manière cohérente depuis votre backend, web et mobile.
Termes clés : plan, add-on, entitlement et accès
Beaucoup de problèmes d'abonnement commencent par un problème de vocabulaire. Si chacun utilise le même mot pour des choses différentes, votre schéma se transforme en ensemble de cas particuliers.
Séparez clairement ces termes dans un schéma de plans et d'entitlements :
- Plan : le bundle par défaut quand quelqu'un s'abonne (par exemple Basique ou Pro). Un plan fixe généralement les limites de base et les fonctionnalités incluses.
- Add-on : un achat optionnel qui modifie la baseline (par exemple « sièges supplémentaires » ou « reporting avancé »). Les add-ons doivent pouvoir être attachés et retirés sans changer le plan.
- Entitlement : le « ce qu'ils ont maintenant » final, calculé après combinaison plan + add-ons + overrides. C'est ce que votre app doit interroger.
- Permission (ou capacité) : une action précise qu'une personne peut effectuer (par exemple « exporter des données » ou « gérer la facturation »). Les permissions dépendent souvent du rôle plus que des entitlements.
- Accès : le résultat réel quand l'app applique les règles (un écran affiche/masque une fonctionnalité, un appel API est autorisé ou bloqué, une limite est appliquée).
Les feature flags sont proches mais différentes. Un feature flag est généralement un interrupteur produit que vous contrôlez (déploiements progressifs, expérimentations, désactivation pendant un incident). Un entitlement est un accès spécifique au client basé sur ce qu'il paie ou sur ce que vous lui avez accordé. Utilisez des flags pour modifier le comportement pour des groupes sans toucher à la facturation. Utilisez des entitlements quand l'accès doit correspondre à un abonnement, une facture ou un contrat.
La portée (scope) est une autre source de confusion. Gardez ces idées claires :
- Utilisateur : une personne. Utile pour les rôles (admin vs membre) et les limites personnelles.
- Compte (customer) : l'entité payante. Utile pour les infos de facturation et la propriété de l'abonnement.
- Espace de travail (workspace/projet/équipe) : là où le travail se fait. Beaucoup de produits appliquent des entitlements ici (sièges, stockage, modules activés).
Le temps compte car l'accès change. Modélisez-le directement :
- Début et fin : un entitlement peut être actif seulement dans une fenêtre (essai, promo, contrat annuel).
- Changement planifié : les upgrades peuvent commencer maintenant ; les downgrades commencent souvent au renouvellement suivant.
- Grace et annulation : vous pouvez autoriser un accès limité après un paiement échoué, mais seulement jusqu'à une date de fin claire.
Exemple : une société est en Pro, ajoute « Reporting avancé » en milieu de mois, puis programme une descente vers Basique au cycle suivant. Le plan change plus tard, l'add-on démarre maintenant, et la couche d'entitlement reste l'endroit unique pour demander : « Cet workspace peut-il utiliser les rapports avancés aujourd'hui ? »
Un schéma de base simple pour plans et fonctionnalités
Un bon schéma de base pour plans et entitlements commence petit : séparez ce que vous vendez (plans et add-ons) de ce que les gens peuvent faire (fonctionnalités). Si vous gardez ces deux idées nettes, les upgrades et les nouveaux add-ons deviennent des changements de données, pas des réécritures.
Voici un ensemble de tables pratiques qui fonctionne pour la plupart des produits par abonnement :
- products : la chose vendable (plan de base, plan équipe, add-on sièges supplémentaires, add-on support prioritaire).
- plans : optionnel, si vous voulez que les plans soient un type spécial de produit avec des champs spécifiques (intervalle de facturation, ordre d'affichage public). Beaucoup d'équipes stockent les plans dans
productset utilisent une colonneproduct_type. - features : le catalogue de capacités (accès API, max projets, export, SSO, crédits SMS).
- product_features (ou
plan_featuressi vous séparez plans) : table de jointure indiquant quelles fonctionnalités sont fournies par quel produit, généralement avec une valeur.
La jointure est là où réside la plupart du pouvoir. Les fonctionnalités ne sont pas souvent juste activées/désactivées. Un plan peut inclure max_projects = 10, tandis qu'un add-on peut ajouter +5. Donc product_features devrait prendre en charge au moins :
feature_value(nombre, texte, JSON ou colonnes séparées)value_type(booléen, entier, enum, json)grant_mode(remplacer vs ajouter), afin qu'un add-on puisse « ajouter 5 sièges » au lieu d'écraser la limite de base
Modélisez les add-ons comme des produits aussi. La seule différence est la manière d'achat. Un produit plan de base est « un à la fois », tandis qu'un add-on peut permettre une quantité. Mais les deux mappent aux fonctionnalités de la même façon. Cela évite des cas particuliers du type « si add-on X alors activer la fonctionnalité Y » dispersés dans votre code.
Les fonctionnalités doivent être des données, pas des constantes codées. Si vous codez en dur les vérifications des fonctionnalités dans plusieurs services, vous finirez par livrer des divergences (le web dit oui, le mobile dit non, le backend diffère). Quand les fonctionnalités vivent en base, l'app peut poser une question cohérente et vous pouvez déployer des changements en éditant des lignes.
Le nommage compte plus qu'on ne le croit. Utilisez des identifiants stables qui ne changent jamais, même si le nom marketing évolue :
feature_keycommemax_projects,sso,priority_supportproduct_codecommeplan_starter_monthly,addon_extra_seats
Gardez les libellés d'affichage séparés (feature_name, product_name). Si vous utilisez l'Data Designer d'AppMaster avec PostgreSQL, traiter ces clés comme champs uniques paye immédiatement : vous pouvez régénérer en sécurité tout en conservant l'intégration et les rapports stables.
La couche entitlements : un seul endroit pour demander « peuvent-ils ? »
La plupart des systèmes d'abonnement partent en vrille quand « ce qu'ils ont acheté » est stocké à un endroit, mais « ce qu'ils peuvent faire » est calculé dans cinq chemins différents. La solution est une couche d'entitlements : une table unique (ou une vue) qui représente l'accès effectif pour un sujet à un instant donné.
Si vous visez un schéma de plans et d'entitlements qui survit aux upgrades, downgrades, essais et concessions ponctuelles, cette couche est celle qui rend tout prévisible.
Une table d'entitlements pratique
Considérez chaque ligne comme une revendication : « ce sujet a accès à cette fonctionnalité avec cette valeur, de ce temps à ce temps, depuis cette source. » Une forme courante ressemble à :
- subject_type (par ex. "account", "user", "org") et subject_id
- feature_id
- value (la valeur effective pour cette fonctionnalité)
- source (d'où ça vient : "direct", "plan", "addon", "default")
- starts_at et ends_at (ends_at nullable pour un accès continu)
Vous pouvez implémenter value de plusieurs façons : une seule colonne texte/JSON plus un value_type, ou des colonnes séparées comme value_bool, value_int, value_text. Gardez-le simple et facile à interroger.
Types de valeur qui couvrent la plupart des produits
Les fonctionnalités ne sont pas toujours true/false. Ces types de valeur couvrent généralement les besoins réels de facturation et de contrôle d'accès :
- Booléen : activé/désactivé (
can_export= true) - Nombre quota : une limite (
seats= 10,api_calls= 100000) - Niveau (tier) : un rang (
support_tier= 2) - Chaîne : un mode ou une variante (
data_retention= "90_days")
Priorité : comment résoudre les conflits
Les conflits sont normaux. Un utilisateur peut être sur un plan qui permet 5 sièges, acheter un add-on pour 10 sièges supplémentaires, et aussi recevoir une attribution manuelle du support.
Définissez une règle claire et appliquez-la partout :
- L'attribution directe (direct grant) écrase le plan
- Puis les add-ons
- Puis les valeurs par défaut
Une approche simple consiste à stocker toutes les lignes candidates (dérivées du plan, des add-ons, direct) et calculer un « gagnant » final par subject_id + feature_id en triant selon la priorité de la source, puis par le starts_at le plus récent.
Voici un scénario concret : un client downgrade son plan aujourd'hui, mais il a déjà payé pour un add-on qui dure jusqu'à la fin du mois. Avec starts_at/ends_at sur les entitlements, la descente prend effet immédiatement pour les fonctionnalités basées sur le plan, tandis que l'add-on reste actif jusqu'à son ends_at. Votre app peut répondre « peuvent-ils ? » avec une seule requête au lieu d'une logique ad hoc.
Abonnements, items et accès borné dans le temps
Votre catalogue (plans, add-ons, features) est le « quoi ». Les abonnements sont le « qui a quoi, et quand ». Si vous gardez ces éléments séparés, les upgrades et annulations cessent d'être effrayants.
Un motif pratique : un abonnement par compte, et plusieurs items d'abonnement sous celui-ci (un pour le plan de base, plus zéro ou plusieurs add-ons). Dans un schéma de plans et d'entitlements, cela vous donne un endroit propre pour enregistrer les changements dans le temps sans réécrire les règles d'accès.
Tables de base pour modéliser la timeline d'achat
Vous pouvez rester simple avec deux tables faciles à interroger :
- subscriptions : id, account_id, status (active, trialing, canceled, past_due), started_at, current_period_start, current_period_end, canceled_at (nullable)
- subscription_items : id, subscription_id, item_type (plan, addon), plan_id/addon_id, quantity, started_at, ends_at (nullable), source (stripe, manual, promo)
Un détail courant : stocker chaque item avec ses propres dates. Ainsi vous pouvez accorder un add-on pour seulement 30 jours, ou laisser un plan courir jusqu'à la fin d'une période payée même si le client annule le renouvellement.
Gardez la proratisation et la facturation hors de la logique d'accès
La proratisation, les factures et les relances de paiement sont des problèmes de facturation. L'accès aux fonctionnalités est un problème d'entitlements. N'essayez pas de « calculer l'accès » depuis les lignes de facture.
Laissez plutôt les événements de facturation mettre à jour les enregistrements d'abonnement (par exemple, prolonger current_period_end, créer une nouvelle ligne subscription_item, ou définir ends_at). Votre app répond alors aux questions d'accès à partir de la timeline d'abonnement (et ensuite, depuis la couche d'entitlements), pas depuis les calculs de facturation.
Changements planifiés sans surprises
Les upgrades et downgrades prennent souvent effet à un moment précis :
- Ajoutez
pending_plan_idetchange_atsur subscriptions pour un changement de plan programmé simple. - Ou utilisez une table
subscription_changes(subscription_id, effective_at, from_plan_id, to_plan_id, reason) si vous avez besoin d'historique et de plusieurs changements futurs.
Cela évite d'incruster des règles comme « les downgrades arrivent à la fin de la période » dans des parties aléatoires de votre code. Le calendrier devient des données.
Où se placent les essais (trials)
Les essais sont juste des accès limités dans le temps avec une source différente. Deux options propres :
- Traiter l'essai comme un statut d'abonnement (trialing) avec trial_start/trial_end.
- Ou créer des items/entitlements de trial avec started_at/ends_at et source = trial.
Si vous construisez ceci dans AppMaster, ces tables se mappent proprement au Data Designer en PostgreSQL, et les dates permettent de requêter simplement « qu'est-ce qui est actif maintenant » sans cas particuliers.
Étape par étape : implémenter le motif
Un bon schéma commence par une promesse : la logique fonctionnelle vit dans les données, pas éparpillée dans les chemins de code. Votre app doit poser une question : « quels sont les entitlements effectifs maintenant ? » et obtenir une réponse claire.
1) Définir des fonctionnalités avec des clés stables
Créez une table feature avec une clé stable et lisible que vous ne renommerez jamais (même si le libellé UI change). De bons identifiants ressemblent à export_csv, api_calls_per_month ou seats.
Ajoutez un type pour que le système sache comment traiter la valeur : booléen (on/off) vs numérique (limites/quotas). Gardez ça simple et cohérent.
2) Mapper plans et add-ons vers des entitlements
Vous avez besoin de deux sources de vérité : ce qu'un plan inclut, et ce que chaque add-on accorde.
Une séquence simple et pratique :
- Mettez toutes les fonctionnalités dans une table
featureavec des clés stables et un type de valeur. - Créez
planetplan_entitlementoù chaque ligne accorde une valeur de fonctionnalité (par exempleseats = 5,export_csv = true). - Créez
addonetaddon_entitlementqui accordent des valeurs supplémentaires (par exempleseats + 10,api_calls_per_month + 50000, oupriority_support = true). - Décidez comment combiner les valeurs : les booléens utilisent souvent OR, les limites numériques utilisent souvent MAX (le plus élevé gagne), et les quantités de sièges utilisent souvent SUM.
- Enregistrez quand les entitlements commencent et se terminent pour que les upgrades, annulations et proratas ne cassent pas les vérifications d'accès.
Si vous construisez ceci dans AppMaster, vous pouvez modéliser ces tables dans le Data Designer (PostgreSQL) et conserver les règles de combinaison comme une petite table de « policy » ou un enum utilisé par votre logique métier (Business Process).
3) Produire les « entitlements effectifs »
Deux options : calculer à la lecture (interroger et fusionner à chaque fois) ou générer un snapshot mis en cache quand quelque chose change (changement de plan, achat d'add-on, renouvellement, annulation). Pour la plupart des applications, les snapshots sont plus simples à raisonner et plus rapides en charge.
Une approche courante est une table account_entitlement qui stocke le résultat final par fonctionnalité, plus valid_from et valid_to.
4) Faire appliquer l'accès avec un seul contrôle
Ne dispersez pas les règles sur les écrans, endpoints et jobs. Mettez une fonction unique dans le code qui lit les entitlements effectifs et décide.
can(account_id, feature_key, needed_value=1):
ent = get_effective_entitlement(account_id, feature_key, now)
if ent.type == \"bool\": return ent.value == true
if ent.type == \"number\": return ent.value \u003e= needed_value
Une fois que tout appelle can(...), les upgrades et add-ons deviennent des mises à jour de données, pas une réécriture.
Scénario d'exemple : upgrade + add-on sans surprises
Une équipe support de 6 personnes est sur le plan Starter. Starter inclut 3 sièges agents et 1000 SMS par mois. En milieu de mois, ils passent à 6 agents et veulent un pack SMS supplémentaire de 5000. Vous voulez que cela fonctionne sans code spécial du type « si plan = Pro alors… ».
Jour 1 : ils commencent sur Starter
Vous créez un subscription pour le compte avec une période de facturation (par exemple 1 Janv à 31 Janv). Puis vous ajoutez un subscription_item pour le plan.
Au checkout (ou via un job nocturne), vous écrivez des grants d'entitlement pour cette période :
entitlement_grant:agent_seats, valeur3, début1 Janv, fin31 Janventitlement_grant:sms_messages, valeur1000, début1 Janv, fin31 Janv
Votre app ne demande jamais « quel plan ont-ils ? » Elle demande « quel est leur entitlement effectif maintenant ? » et obtient seats = 3, SMS = 1000.
Jour 15 : upgrade vers Pro, ajoute le pack SMS le même jour
Le 15 Janv ils upgrade en Pro (inclut 10 sièges agents et 2000 SMS). Vous ne modifiez pas les grants anciens. Vous ajoutez de nouveaux enregistrements :
- Fermez l'ancien item de plan : mettez
subscription_item(Starter) end à15 Janv - Créez un nouvel item de plan :
subscription_item(Pro) start15 Janv, end31 Janv - Ajoutez un nouvel item add-on :
subscription_item(SMS Pack 5000) start15 Janv, end31 Janv
Puis les grants pour la même période sont ajoutés :
entitlement_grant:agent_seats, valeur10, start15 Janv, end31 Janventitlement_grant:sms_messages, valeur2000, start15 Janv, end31 Janventitlement_grant:sms_messages, valeur5000, start15 Janv, end31 Janv
Ce qui se passe immédiatement le 15 Janv :
- Sièges : le nombre effectif de sièges devient 10 (règle : "prendre le max pour les sièges"). Ils peuvent ajouter 3 agents supplémentaires ce jour-là.
- SMS : le quota effectif devient 7000 pour le reste de la période (règle : "somme additive" pour les packs de messages).
Aucun usage existant n'a besoin d'être « déplacé ». Votre table d'usage continue de compter les messages envoyés ; la vérification d'entitlement compare simplement l'usage de la période avec la limite effective actuelle.
Jour 25 : schedule d'une descente, accès conservé jusqu'à la fin de période
Le 25 Janv ils programment une descente vers Starter effective le 1er Fév. Vous ne touchez pas aux grants de Janv. Vous créez des items futurs (ou grants futurs) pour la période suivante :
subscription_item(Starter) start1 Fév, end28 Fév- Aucun item SMS Pack commençant le 1 Fév
Résultat : ils conservent les sièges Pro et le pack SMS jusqu'au 31 Janv. Le 1er Fév, leurs sièges effectifs tombent à 3 et les SMS repassent aux limites Starter pour la nouvelle période. C'est simple à raisonner et se mappe proprement à un workflow no-code dans AppMaster : changer des dates crée de nouvelles lignes, et la requête d'entitlement reste la même.
Erreurs courantes et pièges
La plupart des bugs d'abonnement ne sont pas des bugs de facturation. Ce sont des bugs d'accès causés par une logique éparpillée. La manière la plus rapide de casser un schéma est de répondre à « peuvent-ils ? » à cinq endroits différents.
Un échec classique est de coder des règles dans l'UI, l'API et les jobs en arrière-plan séparément. L'UI cache un bouton, l'API oublie de bloquer l'endpoint, et un job nocturne continue de tourner parce qu'il vérifie autre chose. Vous vous retrouvez avec des rapports « ça marche parfois » difficiles à reproduire.
Un autre piège est d'utiliser des checks sur plan_id au lieu de vérifications par fonctionnalité. Ça semble simple au départ (Plan A peut exporter, Plan B non), mais cela s'effondre dès qu'un add-on, un client « grandfathered », un essai gratuit ou une exception enterprise apparaissent. Si vous dites jamais « if plan is Pro then allow… », vous construisez un labyrinthe à maintenir pour toujours.
Cas limites de temps et d'annulation
L'accès se « coince » aussi quand vous stockez seulement un booléen comme has_export = true sans jamais attacher de dates. Annulations, remboursements, rétrofacturations et downgrades en cours de période ont tous besoin de bornes temporelles. Sans starts_at et ends_at, vous accordez par erreur un accès permanent, ou vous le retirez trop tôt.
Une règle simple pour éviter ça :
- Chaque grant d'entitlement doit avoir une source (plan, add-on, override manuel) et une plage temporelle.
- Chaque décision d'accès doit vérifier « now entre start et end » (avec des règles claires pour les end nulls).
- Les jobs en arrière-plan doivent re-vérifier les entitlements au moment de l'exécution, et non supposer l'état d'hier.
Ne mélangez pas facturation et accès
Les équipes se mettent aussi en difficulté en mélangeant enregistrements de facturation et règles d'accès dans la même table. La facturation a besoin de factures, taxes, prorata, identifiants fournisseurs et états de retry. L'accès a besoin de clés de fonctionnalité claires et de fenêtres temporelles. Quand tout est emmêlé, une migration de facturation devient une panne produit.
Enfin, beaucoup de systèmes sautent l'audit trail. Quand un utilisateur demande « pourquoi puis-je exporter ? », vous devez pouvoir répondre : « Activé par l'Add-on X du 2026-01-01 au 2026-02-01 » ou « Accordé manuellement par le support, ticket 1842. » Sans ça, le support et l'ingénierie devinent.
Si vous construisez ceci dans AppMaster, conservez les champs d'audit dans votre modèle Data Designer et faites de la vérification « peuvent-ils ? » un Business Process unique utilisé par le web, le mobile et les flows planifiés.
Checklist rapide avant la mise en production
Avant de déployer votre schéma de plans et d'entitlements, faites une dernière passe avec des questions réelles, pas de la théorie. L'objectif est que l'accès soit explicable, testable et facile à changer.
Questions de réalité
Prenez un utilisateur et une fonctionnalité, puis essayez d'expliquer le résultat comme au support ou à la finance. Si vous ne pouvez répondre que « ils sont sur Pro » (ou pire, « le code le dit »), vous sentirez la douleur la première fois qu'un client upgrade en cours de période ou obtient une offre ponctuelle.
Utilisez cette checklist rapide :
- Pouvez-vous répondre « pourquoi cet utilisateur a cet accès ? » uniquement à partir des données (subscription items, add-ons, overrides et fenêtres temporelles), sans lire le code applicatif ?
- Toutes les vérifications d'accès se basent-elles sur des clés de fonctionnalité stables (comme
feature.export_csv) plutôt que sur des noms de plan (comme « Starter » ou « Business ») ? Les noms de plan changent ; les feature keys ne devraient pas. - Les entitlements ont-ils des débuts et fins clairs, y compris essais, périodes de grâce et annulations planifiées ? Si le temps manque, les downgrades deviennent des disputes.
- Pouvez-vous accorder ou retirer l'accès pour un seul client via un enregistrement d'override, sans dévier votre logique ? C'est ainsi que vous gérez « donnez-leur 10 sièges supplémentaires ce mois-ci » sans code spécifique.
- Pouvez-vous tester un upgrade et un downgrade avec quelques lignes d'exemple et obtenir des résultats prédictibles ? Si vous avez besoin d'un script complexe pour simuler cela, votre modèle est trop implicite.
Un test pratique : créez trois utilisateurs (nouveau, upgrade en milieu de mois, annulé) et un add-on (par ex. « sièges supplémentaires » ou « rapports avancés »). Exécutez votre requête d'accès pour chacun. Si les résultats sont évidents et explicables, vous êtes prêt.
Si vous utilisez un outil comme AppMaster, gardez la même règle : faites d'une seule requête (ou d'un seul Business Process) la responsabilité de « peuvent-ils ? » afin que chaque écran web et mobile utilise la même réponse.
Prochaines étapes : faciliter la maintenance des upgrades
La meilleure façon de garder les upgrades sous contrôle est de commencer plus petit que prévu. Choisissez une poignée de fonctionnalités qui ont réellement de la valeur (5-10 suffisent) et construisez une unique requête ou fonction d'entitlement qui répond à une seule question : « Cet account peut-il faire X maintenant ? » Si vous ne pouvez pas répondre à cela en un seul endroit, les upgrades resteront toujours risqués.
Une fois ce contrôle en place, traitez les chemins d'upgrade comme un comportement produit, pas seulement comme du billing. Le moyen le plus rapide de détecter les cas limites étranges est d'écrire un petit ensemble de tests d'accès basés sur des mouvements clients réels.
Voici des étapes pratiques qui paient rapidement :
- Définissez un catalogue minimal de fonctionnalités et mappez chaque plan à un ensemble clair d'entitlements.
- Ajoutez les add-ons comme des « items » séparés qui accordent ou étendent des entitlements, au lieu de les intégrer dans les règles de plan.
- Écrivez 5-10 tests d'accès pour les parcours courants (upgrade en cours de période, downgrade au renouvellement, add-on ajouté puis retiré, essai vers payant, période de grâce).
- Faites des changements de prix uniquement via les données : mettez à jour les lignes de plan, les mappings de fonctionnalités et les grants d'entitlement, pas le code.
- Prenez l'habitude : chaque nouveau plan ou add-on doit être accompagné d'au moins un test qui prouve que l'accès se comporte comme prévu.
Si vous utilisez un backend no-code, vous pouvez toujours modéliser proprement ce motif. Dans AppMaster, le Data Designer convient bien pour bâtir les tables de base (plans, features, subscriptions, subscription items, entitlements). Puis le Business Process Editor peut contenir le flux décisionnel d'accès (charger les entitlements actifs, appliquer les fenêtres temporelles, retourner allow/deny) pour éviter d'écrire des vérifications dispersées à la main dans les endpoints.
Le bénéfice apparaît au prochain changement de tarif. Au lieu de réécrire des règles, vous éditez des données : une fonctionnalité passe de « Pro » à un add-on, la durée d'un entitlement change, ou un plan legacy conserve ses anciens grants. Votre logique d'accès reste stable, et les upgrades deviennent une mise à jour contrôlée, pas un sprint de développement.
Si vous voulez valider rapidement votre schéma, essayez de modéliser de bout en bout un upgrade plus un add-on, puis exécutez ces tests d'accès avant d'ajouter quoi que ce soit d'autre.


