Cas CP-020 : Gestion des modules : tenant suspendu + API du catalogue de modules¶
Module
: plan de contrôle Tranche
: tranche 7b de l'architecture (dissociée du CP-007) Contexte de marque
: [LES DEUX] Papillon HR Suite + ALTARYS ENTERPRISE HR Suite Priorité
: 7 (après le CP-007) Dépend de
: CP-007 Complexité estimée
: S
Objectif¶
Étendre le backend de gestion des modules avec deux fonctionnalités : (1) refus d'écriture pour les tenants suspendus — lorsqu'un tenant est SUSPENDU, toutes les opérations d'écriture (POST, PUT, PATCH, DELETE) sur les modules gérés sont bloquées tandis que les lectures (GET) restent autorisées ; et (2) l'API du catalogue de modules qui renvoie les modules souscrits et les modules disponibles avec les tarifs pour le segment du tenant.
Portée du backend¶
Entités et enregistrements¶
Réutilise les entités de CP-007 : - Entité TenantModule
(déjà créée dans CP-007) - Énumération ModuleStatus
: ACTIVE, INACTIVE, TRIAL (déjà créée dans CP-007)
DTO (provenant de CP-007, utilisés ici) :
public record TenantModuleResponse(
String moduleCode, String moduleName, ModuleStatus status,
@Nullable Instant activatedDate, @Nullable Instant deactivatedDate,
boolean isSellable, @Nullable String description, @Nullable String price
) {}
public record ModuleCatalogResponse(
List<TenantModuleResponse> subscribedModules,
List<ModuleCatalogEntry> availableModules
) {}
public record ModuleCatalogEntry(
String moduleCode, String moduleName, String description,
String iconName, boolean available, @Nullable String comingSoonDate,
@Nullable String priceForSegment
) {}
```### Couche de référentiel
Réutilise `TenantModuleRepository` de CP-007. Aucun nouveau repository.
### Couche de service
**ModuleGatingInterceptor.java (extension de CP-007) :**
- Ajout d'une vérification du statut « SUSPENDED » du tenant : SI le statut du tenant est « SUSPENDED » → refuser TOUTES les opérations d'écriture (POST, PUT, PATCH, DELETE) pour les modules contrôlés. La lecture (GET) reste autorisée.
- Réponse HTTP 403 pour les écritures suspendues :
```json
{
"error": "TENANT_SUSPENDED",
"message": "Votre compte est suspendu. Les modifications ne sont pas autorisées."
}
```
**ModuleGatingService.java (extension de CP-007) :**
- `getModuleCatalog(UUID tenantId) → ModuleCatalogResponse` — NOUVELLE méthode
- Renvoie subscribedModules (modules actifs/d'essai du tenant) + availableModules (tous les modules commercialisables non souscrits, avec les prix correspondant au segment de nombre d'employés du tenant)
- Les métadonnées des modules (nom, description, icône, prix) sont codées en dur dans une classe constante `ModuleCatalog` (non pilotée par la base de données pour le MVP)
**Codes des modules vendables (référence issue de CP-007) :**
HRCORE, EMPMGT, ABSMGT, QRCONTR, TIMACT, EXPMGT, COMMIT, PAYROL, HSEMGT, PERFOB, GPEC, LTRAIN, ATSMGT, ADVDOC, CRMMGT
**Non vendables (inclus automatiquement) :**
BUDMGT
**Toujours actifs (sans restriction d'accès) :**
CP (Control Plane), ORGDATA (Organisation et données de référence)
### Endpoints API
| Method | Path | Request Body | Response | Auth |
|--------|------|-------------|----------|------|
| GET | /api/v1/tenant/modules/catalog | — | ModuleCatalogResponse | Any authenticated |
### Règles de validation
- Le catalogue ne renvoie que les modules valides et commercialisables
- Les prix renvoyés correspondent au segment de nombre d'employés du tenant
- BUDMGT n'apparaît jamais dans availableModules (inclus automatiquement uniquement)
### Considérations relatives à l'environnement multi-tenant
- Le catalogue de modules est limité au tenant (chaque tenant voit ses abonnements et les modules disponibles)
- La vérification des tenants suspendus utilise le statut du tenant provenant de TenantContext (résolu par l'infrastructure CP-001)
- La réponse du catalogue est mise en cache par tenant dans Caffeine (TTL : 5 min, invalidée en cas de changement de statut du module)
### Pages et routes
N/A — Tranche backend uniquement.
### États de l'interface utilisateur (TOUS OBLIGATOIRES)
N/A — Tranche backend uniquement.
### Comportement réactif
N/A
### Interactions
N/A
---
## Critères d'acceptation
```gherkin
AC-056: Suspended tenant blocks writes
Given my tenant is SUSPENDED
When I call POST /api/v1/employees (write operation)
Then I receive HTTP 403 with {"error": "TENANT_SUSPENDED"}
When I call GET /api/v1/employees (read operation)
Then the request succeeds (reads allowed during suspension)
AC-060: Module catalog returns correct data
Given my tenant has 2 active modules and 13 available
When I call GET /api/v1/tenant/modules/catalog
Then I receive subscribedModules (2) and availableModules (13 with prices for my segment)
OHADA et règles réglementaires¶
- Règle métier : les tenants suspendus conservent un accès en lecture à toutes leurs données. Ceci est important pour se conformer à l'article 24 de l'AUDCIF — les données financières doivent rester accessibles pendant 10 ans, même en cas de suspension.
- Aucune exigence réglementaire OHADA directe pour le catalogue de modules.
Normes et conventions¶
docs/standards/java-spring-guidelines.md— §Intercepteurs Spring, §Mise en cache Caffeinedocs/standards/api-guidelines.md— §Format d'erreur 403 pour la suspension d'un tenant, §Format de réponse du catalogue de modules
Exigences de test¶
Tests unitaires¶
- ModuleGatingInterceptor : tenant SUSPENDU → écriture refusée (POST, PUT, PATCH, DELETE)
- ModuleGatingInterceptor : tenant SUSPENDU → lecture autorisée (GET)
- ModuleGatingService : le catalogue renvoie la répartition correcte entre les modules souscrits et disponibles
- ModuleGatingService : BUDMGT exclu des modules disponibles
Tests d'intégration¶
- Locataire suspendu : POST → 403, GET → succès
- Endpoint du catalogue : nombre et prix des modules corrects pour le segment de locataires
- Catalogue : le locataire A voit des abonnements différents de ceux du locataire B (isolation des locataires)
Ce que l'assurance qualité va valider¶
- Refus d'écriture pour le tenant suspendu vérifié via des appels API
- Le catalogue de modules renvoie la structure et les données attendues
Hors du périmètre¶
- Intégration de la navigation + cartes de vente incitative (frontend) — CP-021
- Interface utilisateur d'activation/désactivation des modules — CP-009
- Suspension par module — V2
- Remplacement du module d'administration — CP-012
Définition de « terminé »¶
- [ ] Tous les endpoints backend sont implémentés et renvoient des réponses correctes
- [ ] Toutes les pages frontend s'affichent correctement à 360px, 768px, 1024px — N/A (backend uniquement)
- [ ] Les 5 états de l'interface utilisateur sont implémentés — N/A (backend uniquement)
- [ ] Les micro-textes en français correspondent exactement aux spécifications de conception — N/A (backend uniquement)
- [ ] Tous les critères d'acceptation sont validés manuellement
- [ ] Les tests unitaires sont écrits et réussis
- [ ] Les tests d'intégration sont écrits et réussis
- [ ] Isolation multi-tenant vérifiée (aucune fuite de données entre tenants)
- [ ] Écriture et synchronisation hors ligne fonctionnelles — N/A
- [ ] Pas de
anyen TypeScript — N/A (backend uniquement) - [ ] Pas de types bruts en Java — tous les génériques sont explicites
- [ ] Les réponses API respectent le format d'enveloppe standard
- [ ] Entrées de piste d'audit créées pour chaque mutation de données