Changes include: - Updated architecture documentation - Enhanced module definitions (OQI-001 to OQI-008) - ML integration documentation updates - Trading strategies documentation - Orchestration and inventory updates - Docker configuration updates 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
315 lines
12 KiB
Markdown
315 lines
12 KiB
Markdown
---
|
|
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)
|