From 86564f104132c5740d306b0002dbb05a91a90b0b Mon Sep 17 00:00:00 2001 From: David Date: Mon, 7 Sep 2026 21:40:51 +0200 Subject: [PATCH] fix(subscriptions): un compte ADMIN dispose de l offre Platinium Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_018BAUeCFpDkRD6tU5wGsc1C --- .../services/subscription.service.ts | 11 ++++++-- .../domain/services/subscription-access.ts | 28 +++++++++++++++++++ 2 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 apps/backend/src/domain/services/subscription-access.ts diff --git a/apps/backend/src/application/services/subscription.service.ts b/apps/backend/src/application/services/subscription.service.ts index 741d834..0efd705 100644 --- a/apps/backend/src/application/services/subscription.service.ts +++ b/apps/backend/src/application/services/subscription.service.ts @@ -22,6 +22,10 @@ import { Subscription } from '@domain/entities/subscription.entity'; import { License } from '@domain/entities/license.entity'; import { SubscriptionPlan, SubscriptionPlanType } from '@domain/value-objects/subscription-plan.vo'; import { SubscriptionStatus } from '@domain/value-objects/subscription-status.vo'; +import { + PLATFORM_ADMIN_ROLE, + effectivePlan as resolveEffectivePlan, +} from '@domain/services/subscription-access'; import { NoLicensesAvailableException, LicenseAlreadyAssignedException, @@ -83,9 +87,10 @@ export class SubscriptionService { subscription.id ); - // ADMIN users always have PLATINIUM plan with no expiration - const isAdmin = userRole === 'ADMIN'; - const effectivePlan = isAdmin ? SubscriptionPlan.platinium() : subscription.plan; + // ADMIN users always have PLATINIUM plan with no expiration. + // La regle vit dans le domaine : l'assistant la lit au meme endroit. + const isAdmin = userRole === PLATFORM_ADMIN_ROLE; + const effectivePlan = resolveEffectivePlan(userRole, subscription.plan); const maxLicenses = effectivePlan.maxLicenses; const availableLicenses = effectivePlan.isUnlimited() ? -1 diff --git a/apps/backend/src/domain/services/subscription-access.ts b/apps/backend/src/domain/services/subscription-access.ts new file mode 100644 index 0000000..e74ebd2 --- /dev/null +++ b/apps/backend/src/domain/services/subscription-access.ts @@ -0,0 +1,28 @@ +import { SubscriptionPlan } from '../value-objects/subscription-plan.vo'; + +export const PLATFORM_ADMIN_ROLE = 'ADMIN'; + +/** + * Offre effective d'un utilisateur. + * + * Un compte ADMIN dispose de l'offre Platinium quelle que soit celle de son + * organisation : c'est deja ce que renvoie l'apercu d'abonnement, donc ce que + * lit toute l'interface (badge d'offre, licences illimitees, absence + * d'echeance). + * + * Cette regle vivait uniquement dans `SubscriptionService`. L'assistant, qui + * lisait l'abonnement brut, appliquait donc le quota Bronze de l'organisation a + * un administrateur a qui le produit affichait « Platinium » partout ailleurs. + * La regle est ici pour qu'un seul endroit la porte et que les deux lectures ne + * puissent plus diverger. + * + * @param role Role de l'utilisateur, tel qu'il figure dans le JWT. + * @param plan Offre de l'organisation, ou `null` sans abonnement exploitable. + */ +export function effectivePlan( + role: string | undefined, + plan: SubscriptionPlan | null +): SubscriptionPlan { + if (role === PLATFORM_ADMIN_ROLE) return SubscriptionPlan.platinium(); + return plan ?? SubscriptionPlan.bronze(); +}