# 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

```typescript
// 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

```gherkin
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

```gherkin
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

```gherkin
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

```gherkin
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

```gherkin
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

```gherkin
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

```typescript
// 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

```typescript
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

```typescript
@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 |
