Notes de version — 3 avril 2026
Cette version complète le système d'application du dépassement de limite lors du rétrogradement — backend, frontend et e-mails — pour assurer que les utilisateurs ayant rétrogradé vers FREE ne puissent pas continuer à utiliser les ressources au-delà des limites de leur niveau.
Application du dépassement de limite lors du rétrogradement
Limites par niveau
| Niveau | Membres | Projets | Tâches | Entrées de temps |
|---|---|---|---|---|
| FREE | 3 | 3 | 15 | 100 |
| PRO | 20 | Illimité | 70 | 1 000 |
| ENTERPRISE | Illimité | Illimité | Illimité | Illimité |
Middleware Backend : requireNotOverLimitLocked
Un nouveau middleware requireNotOverLimitLocked a été appliqué à tous les points de terminaison d'écriture (projets, tâches, membres de l'équipe, entrées de temps).
Les utilisateurs dont le compte est verrouillé (isOverLimitLocked: true) reçoivent 403 LIMIT_EXCEEDED sur toute opération d'écriture.
Points de terminaison protégés :
| Point de terminaison | Effet du verrouillage |
|---|---|
POST /time-entries | |
PUT /time-entries/:id | |
DELETE /time-entries/:id | |
POST /projects | |
POST /tasks | |
POST /team/invite | |
POST /timer/start | LIMIT_EXCEEDED |
Blocage du démarrage du minuteur
Le démarrage du minuteur est également bloqué lorsque le nombre d'entrées de temps dans la période de facturation actuelle dépasse la limite du niveau.
Webhook de verrouillage des membres
Lors d'un événement de rétrogradement d'abonnement Stripe (customer.subscription.updated), un webhook verrouille automatiquement les membres excédentaires.
Logique de verrouillage :
- Les membres sont triés par date d'adhésion (du plus récent au plus ancien)
- Les membres excédentaires au-delà de la limite du niveau sont verrouillés
- Les statuts
activeetpendingcomptent dans le total (correctif de bogue)
E-mails
E-mail de résumé de rétrogradement (au propriétaire) :
- Résumé de tous les membres verrouillés
- Liste des ressources excédentaires (projets, tâches)
- Lien pour mettre à niveau l'abonnement
E-mail de notification d'accès limité (à chaque membre verrouillé) :
- Informations sur les raisons du verrouillage
- Détails de contact du propriétaire de l'espace de travail
- Conseils pour obtenir un accès
Mises à jour Frontend
Bannière globale pour les utilisateurs verrouillés
AppShell.tsx affiche désormais une bannière persistante pour les utilisateurs dont le compte est verrouillé (isOverLimitLocked: true).
La bannière reste visible sur toutes les pages jusqu'à ce que le propriétaire mette à niveau l'abonnement.
Bannières de dépassement de limite par page
Des bannières d'alerte contextuelles ont été ajoutées aux pages suivantes :
| Page | Condition | Message |
|---|---|---|
| Page Projets | projectCount > maxProjects | "Dépassement de limite de projets" |
| Page Tâches | taskCount > maxTasks | "Dépassement de limite de tâches" |
| Page Suivi du temps | entryCount > maxEntries | "Dépassement de limite d'entrées" |
| Page Équipe | memberCount > maxMembers | "Dépassement de limite de membres" |
Correction stricte > : La bannière de la page Membres de l'équipe utilisait >= (affiché à la limite exacte). Elle utilise maintenant > (strictement au-dessus). Être à la limite est normal ; la dépasser est un état exceptionnel.
Projets excédentaires en lecture seule
ProjectDetailsPage et ProjectTasksTab affichent une bannière en lecture seule pour les projets marqués isExcessProject: true.
La création de tâches est désactivée sur les projets excédentaires.
États désactivés dans les sélecteurs
| Sélecteur | Condition | Affichage |
|---|---|---|
| Créer une tâche — Projet | isExcessProject: true | 🔒 Badge "Dépassement de limite" |
| Modifier une tâche — Projet | isExcessProject: true | 🔒 Badge "Dépassement de limite" |
| Créer une tâche — Responsables | isOverLimitLocked: true | 🔒 Badge "Accès limité" |
| Modifier une tâche — Responsables | isOverLimitLocked: true | 🔒 Badge "Accès limité" |
| Minuteur / Saisie manuelle — Projet/Tâche | isExcessProject: true | 🔒 Badge "Dépassement de limite" |
Corrections de bogues
Requête de verrouillage des membres : membres en attente inclus
markExcessMembersAsLocked() ne cherchait précédemment que les membres avec status: 'active'. Puisque les membres pending comptent également dans la limite d'utilisation dans UsageTrackingService, cela créait une incohérence entre la logique de verrouillage et le compteur.
Correction : La requête utilise désormais { status: { $in: ['active', 'pending'] } }.
Limites de niveau du modèle Unit corrigées
Le hook pré-sauvegarde du modèle Unit avait des valeurs codées en dur (FREE: 5 membres, PRO: 25 membres) qui étaient en conflit avec les valeurs faisant autorité dans tiers.config.ts.
Correction : Le hook pré-sauvegarde utilise maintenant les valeurs correctes : FREE: 3, PRO: 20.
Outils Développeur / Ops
Script manual-downgrade-to-free.mjs
Rétrograde manuellement une unité vers FREE dans la base de données — utile pour les tests et les flux de travail de support sans déclencher un vrai événement Stripe.
node scripts/manual-downgrade-to-free.mjs <unitBundle>
Actions : Définit le niveau, les limites, cancelAtPeriodEnd, currentPeriodEnd, et exécute markExcessMembersAsLocked() immédiatement.
Script test-downgrade-enforcement.mjs
Simule le cycle complet d'application de rétrogradement/mise à niveau sans Stripe.
node scripts/test-downgrade-enforcement.mjs <unitBundle> [status|downgrade|upgrade]
| Scénario | Effet |
|---|---|
status | Afficher l'état de verrouillage actuel de tous les membres |
downgrade | Simuler PRO → FREE, verrouiller les membres excédentaires |
upgrade | Simuler une mise à niveau, déverrouiller tous les membres |
Résumé
| Zone | Modification |
|---|---|
| Backend | Vérification de limite startTimer() — minuteur déjà appliqué (confirmé) |
| Backend | Vérification de limite de membres inviteUser() — déjà appliqué (confirmé) |
| Backend | Middleware requireNotOverLimitLocked — appliqué à toutes les routes d'écriture |
| Backend | markExcessMembersAsLocked inclut maintenant les membres pending |
| Backend | Limites du hook pré-sauvegarde Unit.model.ts corrigées (FREE: 3, PRO: 20) |
| Backend | Le webhook de rétrogradement envoie un e-mail récapitulatif au propriétaire |
| Backend | Les membres verrouillés reçoivent un e-mail de notification d'accès limité |
| Frontend | Bannière de la page Membres de l'équipe : >= → > (dépassement strict) |
| Frontend | Dialogue Créer une tâche : membres verrouillés affichés comme désactivés avec badge |
| Frontend | Dialogue Modifier une tâche : membres verrouillés affichés comme désactivés avec badge |
| Frontend | Dialogue Créer une tâche : projets excédentaires affichés comme désactivés avec badge |
| Frontend | Dialogue Modifier une tâche : projets excédentaires affichés comme désactivés avec badge |
| Frontend | Sélecteur Projet/Tâche : ressources verrouillées affichées comme désactivées avec badge |
| Frontend | AppShell.tsx : bannière persistante globale pour les utilisateurs verrouillés |
| Frontend | ProjectDetailsPage : bannière en lecture seule sur les projets excédentaires |
| Frontend | ProjectTasksTab : bannière de désactivation de création de tâches sur les projets excédentaires |
| Frontend | TimeTrackingPage : bannière de dépassement + blocage du widget minuteur |
| Frontend | ProjectsPage : bannière de dépassement |
| Frontend | TaskManagementPage : bannière de dépassement |
| Scripts | manual-downgrade-to-free.mjs ajouté |
| Scripts | test-downgrade-enforcement.mjs ajouté |
Disponibilité : Tous les plans (l'application s'active automatiquement lors du rétrogradement)