RF-TENANT-004: Subscripciones y Limites
Identificacion
| Campo |
Valor |
| ID |
RF-TENANT-004 |
| Modulo |
MGN-004 Tenants |
| Prioridad |
P1 - Alta |
| Estado |
Ready |
| Fecha |
2025-12-05 |
Descripcion
El sistema debe gestionar planes de subscripcion para los tenants, controlando los limites de uso (usuarios, storage, modulos) y el ciclo de facturacion. Cada plan define que funcionalidades y recursos estan disponibles para el tenant.
Actores
| Actor |
Descripcion |
| Platform Admin |
Gestiona planes y subscripciones |
| Tenant Admin |
Ve su subscripcion y puede solicitar upgrades |
| Sistema |
Aplica limites automaticamente |
| Billing System |
Procesa pagos y renovaciones |
Planes de Subscripcion
Planes Disponibles
| Plan |
Usuarios |
Storage |
Modulos |
Precio/mes |
| Trial |
5 |
1 GB |
Basicos |
Gratis (14 dias) |
| Starter |
10 |
5 GB |
Basicos |
$29 USD |
| Professional |
50 |
25 GB |
Todos Standard |
$99 USD |
| Enterprise |
Ilimitado |
100 GB |
Todos + Premium |
$299 USD |
| Custom |
Configurable |
Configurable |
Configurable |
Cotizacion |
Modulos por Plan
| Modulo |
Trial |
Starter |
Professional |
Enterprise |
| Auth |
✓ |
✓ |
✓ |
✓ |
| Users |
✓ |
✓ |
✓ |
✓ |
| Roles |
✓ |
✓ |
✓ |
✓ |
| Inventory |
✓ |
✓ |
✓ |
✓ |
| Financial |
- |
✓ |
✓ |
✓ |
| Reports |
- |
Basic |
Full |
Full |
| CRM |
- |
- |
✓ |
✓ |
| Advanced Analytics |
- |
- |
- |
✓ |
| API Access |
- |
- |
✓ |
✓ |
| White Label |
- |
- |
- |
✓ |
| Priority Support |
- |
- |
- |
✓ |
Flujo Principal
Ver Subscripcion Actual
1. Tenant Admin accede a Configuracion > Subscripcion
2. Sistema muestra:
- Plan actual
- Fecha de inicio
- Proxima renovacion
- Uso actual vs limites
- Historial de facturacion
3. Admin puede ver planes disponibles para upgrade
Solicitar Upgrade
1. Tenant Admin click en "Cambiar Plan"
2. Sistema muestra comparativa de planes
3. Admin selecciona nuevo plan
4. Sistema calcula costo prorrateado
5. Admin confirma y procede al pago
6. Sistema procesa pago
7. Sistema actualiza subscripcion
8. Nuevos limites aplican inmediatamente
9. Sistema envia confirmacion por email
Renovacion Automatica
1. Sistema detecta subscripcion por vencer (3 dias)
2. Sistema envia recordatorio de renovacion
3. En fecha de renovacion:
a. Sistema intenta cobrar metodo de pago guardado
b. Si exitoso: renueva subscripcion
c. Si falla: marca como "payment_pending"
4. Si pago pendiente por 7 dias:
a. Sistema envia advertencias
b. Sistema suspende tenant
Cancelar Subscripcion
1. Tenant Admin solicita cancelacion
2. Sistema muestra encuesta de salida
3. Admin confirma cancelacion
4. Sistema programa cancelacion para fin de periodo
5. Tenant sigue activo hasta fin de periodo pagado
6. Al terminar periodo: downgrade a Trial o suspension
Limites y Enforcement
Tipos de Limites
| Tipo |
Comportamiento |
| Hard Limit |
Bloquea la accion inmediatamente |
| Soft Limit |
Permite con advertencia, bloquea al 110% |
| Usage Based |
Cobra extra por exceso |
Enforcement de Limites
// Verificacion de limite de usuarios
async canCreateUser(tenantId: string): Promise<boolean> {
const subscription = await this.getSubscription(tenantId);
const currentUsers = await this.countUsers(tenantId);
if (currentUsers >= subscription.limits.maxUsers) {
throw new PaymentRequiredException(
`Limite de usuarios alcanzado (${subscription.limits.maxUsers}). ` +
`Actualiza tu plan para agregar mas usuarios.`
);
}
return true;
}
// Verificacion de acceso a modulo
async canAccessModule(tenantId: string, module: string): Promise<boolean> {
const subscription = await this.getSubscription(tenantId);
if (!subscription.modules.includes(module)) {
throw new PaymentRequiredException(
`El modulo "${module}" no esta incluido en tu plan. ` +
`Actualiza a ${this.getMinPlanForModule(module)} para acceder.`
);
}
return true;
}
Reglas de Negocio
| ID |
Regla |
| RN-001 |
Trial expira en 14 dias sin opcion de extension |
| RN-002 |
Downgrade no permitido durante periodo de facturacion |
| RN-003 |
Upgrade aplica inmediatamente con prorrateo |
| RN-004 |
Cancelacion efectiva al fin del periodo pagado |
| RN-005 |
Datos se conservan 30 dias despues de cancelacion |
| RN-006 |
Exceso de storage: soft limit + cargos adicionales |
| RN-007 |
Pago fallido: 7 dias de gracia antes de suspension |
| RN-008 |
Enterprise puede negociar limites custom |
Criterios de Aceptacion
Escenario 1: Ver uso actual vs limites
Given tenant con plan Professional (50 usuarios, 25GB)
And 35 usuarios activos
And 18GB de storage usado
When Tenant Admin ve la subscripcion
Then muestra "Usuarios: 35/50 (70%)"
And muestra "Storage: 18GB/25GB (72%)"
And muestra grafico de uso
Escenario 2: Bloqueo por limite de usuarios
Given tenant con plan Starter (10 usuarios)
And 10 usuarios activos (100%)
When Admin intenta crear usuario #11
Then el sistema responde con status 402
And el mensaje indica limite alcanzado
And sugiere upgrade a Professional
Escenario 3: Bloqueo por modulo no incluido
Given tenant con plan Starter (sin CRM)
When usuario intenta acceder a /api/v1/crm/contacts
Then el sistema responde con status 402
And el mensaje indica modulo no disponible
And sugiere planes que incluyen CRM
Escenario 4: Upgrade de plan
Given tenant en Starter ($29/mes) al dia 15 del mes
When solicita upgrade a Professional ($99/mes)
Then sistema calcula prorrateo: $35 (15 dias de diferencia)
And usuario paga $35
And plan cambia inmediatamente
And nuevos limites aplican
And siguiente factura: $99 el dia 1
Escenario 5: Trial expirado
Given tenant en Trial por 14 dias
When han pasado los 14 dias sin subscription
Then el estado cambia a "trial_expired"
And usuarios no pueden acceder
And datos se conservan
And Admin puede acceder solo para suscribirse
Escenario 6: Advertencia de renovacion
Given subscripcion que vence en 3 dias
When el sistema ejecuta job de notificaciones
Then envia email "Tu subscripcion vence en 3 dias"
And incluye link para verificar metodo de pago
Mockup / Wireframe
+------------------------------------------------------------------+
| [Logo] Mi Subscripcion |
+------------------------------------------------------------------+
| |
| ┌─────────────────────────────────────────────────────────────┐ |
| │ PLAN ACTUAL: Professional [Cambiar Plan] │ |
| │ │ |
| │ $99 USD / mes Proxima renovacion: 01/01/2026 │ |
| │ Facturacion mensual Metodo de pago: •••• 4242 │ |
| └─────────────────────────────────────────────────────────────┘ |
| |
| USO ACTUAL |
| ┌─────────────────────────────────────────────────────────────┐ |
| │ │ |
| │ Usuarios ████████████████████░░░░░░░░░░ 35/50 (70%) │ |
| │ │ |
| │ Storage █████████████████████████░░░░░ 18/25GB (72%) │ |
| │ │ |
| │ API Calls ██████████░░░░░░░░░░░░░░░░░░░░ 5K/50K (10%) │ |
| │ │ |
| └─────────────────────────────────────────────────────────────┘ |
| |
| MODULOS INCLUIDOS |
| ┌─────────────────────────────────────────────────────────────┐ |
| │ ✓ Auth ✓ Users ✓ Roles ✓ Inventory │ |
| │ ✓ Financial ✓ Reports (Full) ✓ CRM ✓ API Access │ |
| │ │ |
| │ No incluidos: Advanced Analytics, White Label │ |
| │ [Ver Enterprise para estas funciones] │ |
| └─────────────────────────────────────────────────────────────┘ |
| |
| HISTORIAL DE FACTURACION |
| ┌─────────────────────────────────────────────────────────────┐ |
| │ Fecha | Descripcion | Monto | Estado │ |
| │------------|----------------------|---------|-------------- │ |
| │ 01/12/2025 | Professional - Dic | $99.00 | ✓ Pagado │ |
| │ 01/11/2025 | Professional - Nov | $99.00 | ✓ Pagado │ |
| │ 15/10/2025 | Upgrade Starter->Pro | $35.00 | ✓ Pagado │ |
| │ 01/10/2025 | Starter - Oct | $29.00 | ✓ Pagado │ |
| └─────────────────────────────────────────────────────────────┘ |
| |
| [Descargar Facturas] [Cancelar Subscripcion] |
+------------------------------------------------------------------+
Notas Tecnicas
API Endpoints
// Ver subscripcion actual
GET /api/v1/tenant/subscription
// Response 200
{
"plan": {
"id": "plan-professional",
"name": "Professional",
"price": 99,
"currency": "USD",
"interval": "monthly"
},
"status": "active",
"currentPeriodStart": "2025-12-01",
"currentPeriodEnd": "2025-12-31",
"cancelAtPeriodEnd": false,
"usage": {
"users": { "current": 35, "limit": 50, "percentage": 70 },
"storage": { "current": 18000000000, "limit": 25000000000, "percentage": 72 },
"apiCalls": { "current": 5000, "limit": 50000, "percentage": 10 }
},
"modules": ["auth", "users", "roles", "inventory", "financial", "reports", "crm", "api"],
"paymentMethod": { "type": "card", "last4": "4242", "brand": "visa" }
}
// Ver planes disponibles
GET /api/v1/subscription/plans
// Solicitar upgrade
POST /api/v1/tenant/subscription/upgrade
{ "planId": "plan-enterprise" }
// Cancelar subscripcion
POST /api/v1/tenant/subscription/cancel
{ "reason": "too_expensive", "feedback": "..." }
// Verificar limite
GET /api/v1/tenant/subscription/check-limit?type=users
// Response 200
{
"type": "users",
"current": 35,
"limit": 50,
"canAdd": true,
"remaining": 15
}
// Response 402 (limite alcanzado)
{
"statusCode": 402,
"error": "Payment Required",
"message": "Limite de usuarios alcanzado",
"upgradeOptions": [
{ "planId": "plan-enterprise", "name": "Enterprise", "newLimit": "unlimited" }
]
}
Modelos de Datos
interface Subscription {
id: string;
tenantId: string;
planId: string;
status: 'trial' | 'active' | 'past_due' | 'canceled' | 'unpaid';
currentPeriodStart: Date;
currentPeriodEnd: Date;
cancelAtPeriodEnd: boolean;
trialEnd?: Date;
paymentMethodId?: string;
}
interface Plan {
id: string;
name: string;
price: number;
currency: string;
interval: 'monthly' | 'yearly';
limits: {
maxUsers: number;
maxStorageBytes: number;
maxApiCalls: number;
};
modules: string[];
features: string[];
isPublic: boolean;
}
Limit Enforcement Guard
@Injectable()
export class LimitGuard implements CanActivate {
constructor(
private subscriptionService: SubscriptionService,
private reflector: Reflector,
) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const limitType = this.reflector.get<string>('checkLimit', context.getHandler());
if (!limitType) return true;
const request = context.switchToHttp().getRequest();
const tenantId = request.tenantId;
const check = await this.subscriptionService.checkLimit(tenantId, limitType);
if (!check.canAdd) {
throw new PaymentRequiredException({
message: `Limite de ${limitType} alcanzado`,
upgradeOptions: check.upgradeOptions,
});
}
return true;
}
}
// Uso en controller
@Post()
@CheckLimit('users')
create(@Body() dto: CreateUserDto) { }
Dependencias
| ID |
Descripcion |
| RF-TENANT-001 |
Tenants existentes |
| Payment Gateway |
Stripe/PayPal para pagos |
| Scheduler |
Jobs para renovaciones y notificaciones |
Estimacion
| Tarea |
Puntos |
| Backend: Subscription service |
4 |
| Backend: Limit enforcement |
4 |
| Backend: Billing integration |
5 |
| Backend: Webhooks de pago |
3 |
| Backend: Tests |
3 |
| Frontend: SubscriptionPage |
4 |
| Frontend: PlanComparison |
3 |
| Frontend: CheckoutFlow |
4 |
| Frontend: Tests |
2 |
| Total |
32 SP |
Historial
| Version |
Fecha |
Autor |
Cambios |
| 1.0 |
2025-12-05 |
System |
Creacion inicial |