L'accès à un module dépend de l'abonnement de l'organisation. Ce contrôle s'appelle le gating, et il est appliqué côté serveur.
Comment ça marche¶
Chaque route protégée porte l'attribut [RequireModule("<clé>")]. À chaque appel, le service
résout les droits (entitlements) de l'organisation auprès de Billing :
- Organisation autorisée → la requête passe.
- Non autorisée → 403 Forbidden.
GET /api/forms (module "forms")
└─ tenant abonné Business+ → 200
└─ tenant Starter → 403
Clés de module¶
Le gating utilise une clé de module stable, par exemple : appointments, loyalty,
forms, rh, docs, slides, knowledge, careers, ia, send, mail… La
disponibilité de chaque clé selon le palier est décrite dans l'espace Pricing.
Résolution et cache des droits¶
Pour éviter un appel à Billing à chaque requête, les droits sont mis en cache :
- Cache mémoire court (~15 s) dans chaque service ;
- sinon, clé Redis partagée
billing:entitlements:{tenantId}(TTL 5 min) publiée par Billing ; - sinon, appel HTTP à Billing (qui repeuple le cache).
Billing invalide la clé Redis à chaque changement d'abonnement (essai, upgrade, add-on, webhook Stripe). Un changement de plan se propage donc à toute la suite en ≤ 15 s.
Côté interface (rappel)¶
Le front masque ce à quoi l'utilisateur n'a pas droit (barre latérale, pages, boutons
« Mettre à niveau »). Ce n'est pas une sécurité : c'est l'API qui fait autorité avec son
403. Ne vous reposez jamais sur le masquage client.
Add-ons¶
Un module peut être activé en add-on, hors des inclusions du palier. Un add-on actif rend le module disponible quel que soit le palier. Voir Pricing → Add-ons.
Cas particulier : routes internes et publiques¶
- Les routes internes (
/internal/*) et publiques anonymes ne portent pas de tenant connecté ;[RequireModule]y est neutre. Elles ont leur propre protection (secret M2M, slug public, clé API). Voir Ponts M2M et Conventions REST.