--- id: "RF-PAY-001" title: "Sistema de Planes y Suscripciones" type: "Requirement" status: "Done" priority: "Alta" epic: "OQI-005" project: "trading-platform" version: "1.0.0" created_date: "2025-12-05" updated_date: "2026-01-04" --- # RF-PAY-001: Sistema de Planes y Suscripciones **Version:** 1.0.0 **Fecha:** 2025-12-05 **Estado:** ✅ Implementado **Prioridad:** P0 (Crítica) **Story Points:** 8 **Épica:** [OQI-005](../_MAP.md) --- ## Descripción El sistema debe permitir a los usuarios suscribirse a planes mensuales de pago recurrente integrados con Stripe Subscriptions, otorgando acceso diferenciado a funcionalidades premium según el nivel del plan. --- ## Objetivo de Negocio - Generar ingresos recurrentes predecibles (MRR) - Segmentar usuarios por valor (freemium → premium) - Reducir churn con facturación automática - Facilitar upgrades/downgrades entre planes --- ## Planes Disponibles | Plan | Precio | Price ID Stripe | Características | |------|--------|-----------------|-----------------| | Free | $0/mes | - | Predicciones básicas (5/día), cursos introductorios | | Basic | $19/mes | `price_1Sb3k64dPtEGmLmpeAdxvmIu` | Predicciones básicas ilimitadas, todos los cursos básicos | | Pro | $49/mes | `price_1Sb3k64dPtEGmLmpm5n5bbJH` | Predicciones avanzadas, todos los cursos, indicadores técnicos | | Premium | $99/mes | `price_1Sb3k74dPtEGmLmpHfLpUkvQ` | Todo incluido, soporte prioritario, análisis personalizados | --- ## Requisitos Funcionales ### RF-PAY-001.1: Creación de Suscripción **DEBE:** 1. Crear Customer en Stripe si no existe 2. Adjuntar método de pago al Customer 3. Crear Subscription con el Price ID correspondiente 4. Guardar registro en tabla `billing.subscriptions` 5. Sincronizar estado inicial (`active`, `incomplete`, `trialing`) ### RF-PAY-001.2: Gestión de Método de Pago **DEBE:** 1. Permitir agregar/actualizar tarjeta de crédito 2. Soportar Stripe Elements para PCI compliance 3. Guardar PaymentMethod como default del Customer 4. Mostrar últimos 4 dígitos y marca de tarjeta ### RF-PAY-001.3: Cambio de Plan (Upgrade/Downgrade) **DEBE:** 1. Permitir cambiar de plan en cualquier momento 2. Proration automática de Stripe: - **Upgrade:** Cobrar diferencia prorrateada inmediatamente - **Downgrade:** Aplicar crédito para próximo ciclo 3. Actualizar `subscription.plan` en BD 4. Mantener `currentPeriodEnd` original ### RF-PAY-001.4: Cancelación de Suscripción **DEBE:** 1. Permitir cancelar en cualquier momento 2. Mantener acceso hasta `currentPeriodEnd` 3. Marcar `cancelAtPeriodEnd = true` 4. Enviar email de confirmación de cancelación 5. No reembolsar período actual ### RF-PAY-001.5: Renovación Automática **DEBE:** 1. Stripe intenta cobro automático en `currentPeriodEnd` 2. Si falla, reintentar según configuración Stripe (3 días) 3. Actualizar estado a `past_due` si falla 4. Enviar email de fallo de pago 5. Cancelar automáticamente si falla después de reintentos ### RF-PAY-001.6: Período de Prueba (Trial) **DEBE:** 1. Ofrecer 7 días gratis en primer suscripción Pro/Premium 2. Crear suscripción con `trial_end` timestamp 3. No cobrar hasta que termine trial 4. Permitir cancelar durante trial sin cargo 5. Convertir a `active` automáticamente al finalizar trial --- ## Flujo de Creación de Suscripción ``` ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ Usuario │ │ Frontend │ │ Backend │ │ Stripe │ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │ │ │ │ │ Selecciona plan │ │ │ │ "Pro" │ │ │ │──────────────────▶│ │ │ │ │ │ │ │ │ POST /payments/ │ │ │ │ subscriptions │ │ │ │ { plan: "pro", │ │ │ │ paymentMethodId }│ │ │ │──────────────────▶│ │ │ │ │ │ │ │ │ 1. Get/Create │ │ │ │ Customer │ │ │ │──────────────────▶│ │ │ │◀──────────────────│ │ │ │ customer_id │ │ │ │ │ │ │ │ 2. Attach │ │ │ │ PaymentMethod │ │ │ │──────────────────▶│ │ │ │◀──────────────────│ │ │ │ │ │ │ │ 3. Create │ │ │ │ Subscription │ │ │ │──────────────────▶│ │ │ │◀──────────────────│ │ │ │ subscription │ │ │ │ │ │ │ │ 4. Save to DB │ │ │ │ (subscriptions) │ │ │ │ │ │ │◀──────────────────│ │ │ │ { subscription, │ │ │ │ status: "active"}│ │ │ │ │ │ │◀──────────────────│ │ │ │ "Suscripción │ │ │ │ activada!" │ │ │ │ │ │ │ ``` --- ## Reglas de Negocio ### RN-001: Un Plan Activo por Usuario - Un usuario solo puede tener **1 suscripción activa** a la vez - Cambiar plan cancela la anterior y crea una nueva - Free plan no genera registro en `subscriptions` ### RN-002: Acceso Según Plan | Recurso | Free | Basic | Pro | Premium | |---------|------|-------|-----|---------| | Predicciones básicas | 5/día | ∞ | ∞ | ∞ | | Predicciones avanzadas | ❌ | ❌ | ✅ | ✅ | | Cursos básicos | 3 | ✅ | ✅ | ✅ | | Cursos avanzados | ❌ | ❌ | ✅ | ✅ | | Indicadores técnicos | ❌ | ❌ | ✅ | ✅ | | Soporte prioritario | ❌ | ❌ | ❌ | ✅ | | Análisis personalizados | ❌ | ❌ | ❌ | ✅ | ### RN-003: Cambio de Plan **Upgrade (Free → Basic, Basic → Pro, etc.):** - Aplicar inmediatamente - Cobrar diferencia prorrateada - Extender `currentPeriodEnd` proporcionalmente **Downgrade (Premium → Pro, Pro → Basic, etc.):** - Aplicar al finalizar período actual - Generar crédito para próximo ciclo - Notificar fecha de cambio efectivo ### RN-004: Cancelación y Reactivación **Cancelación:** - Mantener acceso hasta `currentPeriodEnd` - Marcar `cancelAtPeriodEnd = true` - No permitir reactivación automática después de `currentPeriodEnd` **Reactivación:** - Solo permitir si `cancelAtPeriodEnd = true` y antes de `currentPeriodEnd` - Marcar `cancelAtPeriodEnd = false` en Stripe --- ## Estados de Suscripción | Estado | Descripción | Acceso | |--------|-------------|--------| | `active` | Suscripción activa y al corriente | ✅ Completo | | `trialing` | En período de prueba | ✅ Completo | | `past_due` | Pago falló, en reintentos | ⚠️ Limitado | | `canceled` | Cancelada por usuario o falta de pago | ❌ Free tier | | `incomplete` | Pago inicial falló | ❌ Sin acceso | | `incomplete_expired` | Pago falló y expiró (24h) | ❌ Sin acceso | | `unpaid` | Todos los reintentos fallaron | ❌ Sin acceso | --- ## Manejo de Errores | Error | Código | Mensaje Usuario | Acción | |-------|--------|-----------------|--------| | Tarjeta declinada | 402 | Tu tarjeta fue rechazada. Intenta con otra. | Solicitar nuevo método | | Customer no existe | 404 | Error de configuración. Contacta soporte. | Crear Customer | | Ya tiene suscripción | 409 | Ya tienes una suscripción activa. Cancela primero. | Redirigir a /settings | | Plan inválido | 400 | El plan seleccionado no existe. | Mostrar planes válidos | | Stripe API error | 502 | Error de procesamiento. Intenta más tarde. | Retry con backoff | --- ## Seguridad ### Validaciones - Verificar que `userId` del token coincida con Customer - No permitir modificar suscripciones de otros usuarios - Validar Price ID contra lista permitida - Verificar estado de Customer en Stripe antes de cambios ### Datos Sensibles - **NUNCA** almacenar números de tarjeta completos - Guardar solo `paymentMethod.last4` y `brand` - Tokens `pm_xxx` son seguros para guardar - Usar Stripe Elements para PCI compliance --- ## Configuración Requerida ```env # Stripe Keys STRIPE_SECRET_KEY=sk_test_51Sb3k64dPtEGmLmp... STRIPE_PUBLISHABLE_KEY=pk_test_51Sb3k64dPtEGmLmp... STRIPE_WEBHOOK_SECRET=whsec_... # Price IDs (desde Stripe Dashboard) STRIPE_PRICE_BASIC=price_1Sb3k64dPtEGmLmpeAdxvmIu STRIPE_PRICE_PRO=price_1Sb3k64dPtEGmLmpm5n5bbJH STRIPE_PRICE_PREMIUM=price_1Sb3k74dPtEGmLmpHfLpUkvQ # Configuración de Trial TRIAL_PERIOD_DAYS=7 ``` --- ## Webhooks Relacionados | Evento | Acción | |--------|--------| | `customer.subscription.created` | Crear registro en BD | | `customer.subscription.updated` | Sincronizar estado y plan | | `customer.subscription.deleted` | Marcar como `canceled` | | `customer.subscription.trial_will_end` | Enviar email recordatorio (3 días antes) | | `invoice.payment_succeeded` | Crear registro en `payments` | | `invoice.payment_failed` | Actualizar a `past_due`, enviar email | --- ## Métricas de Negocio ### KPIs a Rastrear - **MRR (Monthly Recurring Revenue):** Suma de todas las suscripciones activas - **Churn Rate:** (Cancelaciones del mes / Suscripciones inicio mes) * 100 - **ARPU (Average Revenue Per User):** MRR / Total usuarios suscritos - **LTV (Lifetime Value):** ARPU / Churn Rate - **Conversion Rate:** Trials → Paid --- ## Criterios de Aceptación - [ ] Usuario puede suscribirse a Basic/Pro/Premium - [ ] Usuario puede agregar/actualizar método de pago - [ ] Usuario puede hacer upgrade inmediatamente - [ ] Usuario puede hacer downgrade al final del período - [ ] Usuario puede cancelar manteniendo acceso hasta period_end - [ ] Usuario puede reactivar suscripción cancelada antes de expirar - [ ] Trial de 7 días se aplica correctamente en primera suscripción - [ ] Estados se sincronizan correctamente con webhooks - [ ] Acceso a recursos se controla según plan activo - [ ] Emails se envían en eventos clave (creación, cancelación, fallo) --- ## Especificación Técnica Relacionada - [ET-PAY-001: Stripe Subscriptions](../especificaciones/ET-PAY-001-stripe-subscriptions.md) ## Historias de Usuario Relacionadas - [US-PAY-001: Ver Planes Disponibles](../historias-usuario/US-PAY-001-ver-planes.md) - [US-PAY-002: Suscribirse a Plan](../historias-usuario/US-PAY-002-suscribirse.md) - [US-PAY-006: Agregar Método de Pago](../historias-usuario/US-PAY-006-agregar-metodo-pago.md)