Contrôle d'accès — Feature Flags
Cascade de features App/Network/Customer, activation conditionnelle et intégration dans les guards.
Contrôle d'accès — Feature Flags
Ce chapitre couvre la cascade de features et leur utilisation concrète. Lisez Modèle de droits et Guards & Hooks en premier.
Modèle de cascade
Une feature est le résultat de trois activations indépendantes. Si une seule est false, la feature est indisponible pour l'utilisateur :
Chargement du diagramme…
Conséquence pratique : un Partner peut activer une feature globalement au niveau App, mais un Customer spécifique peut la désactiver pour ses utilisateurs. Ce mécanisme permet une granularité fine sans code custom.
Features standard de la plateforme
| Feature | Description |
|---|---|
invitations | Flux d'invitations utilisateur (envoi email, acceptation, provisioning) |
antivirus | Scan antivirus des fichiers uploadés (ClamAV via ws-mod-antivirus) |
hds | Fonctionnalités Healthcare Data Security (ws-mod-hds) |
ai-translation | Traduction automatique IA (consomme des crédits) |
export | Export Stellar + WORM archiving |
audit | Consultation des logs d'audit |
billing | Module de facturation et gestion des crédits |
Utilisation côté frontend
Vérification simple
typescriptimport { useAppRights } from "@/hooks/use-app-rights"; function InvitationsSection() { const { hasFeature } = useAppRights(); if (!hasFeature("invitations")) { return null; // Masquer complètement la section } return <InvitationsList />; }
Combinaison feature + droit
tsx// Toujours vérifier la feature AVANT le droit <Protected feature="invitations" right="invitations.create"> <InviteUserButton /> </Protected>
Ordre recommandé : vérifier la feature en premier. Si la feature est désactivée, inutile de tester les droits — l'API retournera
403 Feature désactivéede toute façon.
Activation via l'API
Pour activer ou désactiver une feature sur un Customer :
httpPATCH /api/config/customers/{customerWid}/features/{featureName} Authorization: Bearer <wakaToken> Content-Type: application/json { "isEnabled": true }
Pour consulter les features actives d'un Customer :
httpGET /api/config/customers/{customerWid}/features Authorization: Bearer <wakaToken>
Réponse :
json{ "data": [ { "name": "invitations", "isEnabled": true }, { "name": "antivirus", "isEnabled": false }, { "name": "hds", "isEnabled": true } ] }
Activation au niveau App
Les features disponibles pour une App sont définies par le Partner :
httpGET /api/config/apps/{appWid}/features Authorization: Bearer <wakaToken>
Un Partner peut désactiver une feature au niveau App pour tous ses Customers en une seule opération :
httpPATCH /api/config/apps/{appWid}/features/{featureName} Authorization: Bearer <wakaToken> Content-Type: application/json { "isEnabled": false }
Guard backend NestJS — RequireFeature
Si votre Wakapp expose des endpoints qui nécessitent une feature active :
typescript// decorators/require-feature.decorator.ts import { SetMetadata } from "@nestjs/common"; export const REQUIRED_FEATURE_KEY = "requiredFeature"; export const RequireFeature = (feature: string) => SetMetadata(REQUIRED_FEATURE_KEY, feature);
typescript// guards/feature.guard.ts import { Injectable, CanActivate, ExecutionContext, ForbiddenException } from "@nestjs/common"; import { Reflector } from "@nestjs/core"; @Injectable() export class FeatureGuard implements CanActivate { constructor(private reflector: Reflector) {} canActivate(context: ExecutionContext): boolean { const requiredFeature = this.reflector.getAllAndOverride<string>( REQUIRED_FEATURE_KEY, [context.getHandler(), context.getClass()] ); if (!requiredFeature) return true; const request = context.switchToHttp().getRequest(); const enrichedPayload = request.enrichedPayload; // mis à jour par AuthMiddleware const features: string[] = enrichedPayload?.features ?? []; if (!features.includes(requiredFeature)) { throw new ForbiddenException( `La fonctionnalité ${requiredFeature} n'est pas activée pour ce customer` ); } return true; } }
Usage :
typescript@Controller("invitations") @UseGuards(FeatureGuard, AppRightGuard) export class InvitationsController { @Post() @RequireFeature("invitations") @RequireAppRight("invitations.create") async createInvitation(@Body() dto: CreateInvitationDto) { // ... } }
Bonnes pratiques
- Vérifier la feature avant d'afficher l'UI : ne pas attendre le
403de l'API pour masquer un bouton. - Pas de feature par défaut : si une feature est absente de
me.features, considérez-la désactivée. - Logging : loggez les tentatives d'accès à des features désactivées pour identifier les bugs d'UI.
Pièges classiques
- Feature absente ≠ erreur : si
featuresest un tableau vide, ce n'est pas un bug — l'utilisateur n'a simplement aucune feature activée. - Ne pas confondre feature et AppRight : une feature active ne garantit pas le droit — il faut les deux.
- Cache features : les features font partie du payload
/me, elles sont donc en cache. Une activation côté admin ne sera visible qu'après le prochain appel/me.
Aller plus loin
- Modèle de droits : adminLevel, wakaRoles, appRights
- Invitations : exemple complet de feature + droit combinés