Développeurs

Concepts transverses

Gating par module

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 :

  1. Cache mémoire court (~15 s) dans chaque service ;
  2. sinon, clé Redis partagée billing:entitlements:{tenantId} (TTL 5 min) publiée par Billing ;
  3. 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.

#api