RF33: Usuario selecciona modelo de suscripción
Descripción
Como usuario autenticado, quiero seleccionar un plan de suscripción para iniciar el proceso de contratación y obtener acceso premium.
Al seleccionar un plan de pago se inicia el flujo de checkout: se asegura un Customer de Stripe y se prepara la creación de la Subscription con el Price correspondiente. El pago efectivo se realiza en RF38.
| Campo | Valor |
|---|---|
| Módulo | Subscription Module |
| Actor | Usuario autenticado |
| Endpoint | POST /subscription/checkout |
| Precondiciones | Sesión activa; plan válido seleccionado |
| Prioridad | Alta (MVP) |
| Etapa | MVP |
| Requisitos relacionados | RF32, RF35, RF38 |
Reglas de negocio
- RN-33.1 — Si el usuario no tiene
stripe_customer_id, se crea unCustomeren Stripe y se persiste (idempotente). - RN-33.2 — Seleccionar el plan Free no requiere pago; aplica de inmediato.
- RN-33.3 — Para planes de pago, se prepara el checkout y se solicita método de pago si no existe (RF35).
- RN-33.4 — Un cambio entre planes de pago (upgrade/downgrade) usa
subscriptions.update()con prorrateo automático de Stripe. - RN-33.5 — En móvil, si el cobro es in-app, se usa el flujo de la tienda; si es web-first, se redirige a la web (Suscripciones Mobile).
Validaciones de entrada
| Campo | Reglas | Mensaje de error |
|---|---|---|
planId | Obligatorio. Plan válido del catálogo. | "Selecciona un plan válido." |
Authorization | Bearer válido. | "Sesión no válida." (401) |
Criterios de aceptación
Escenario 1: Selección de plan de pago
Dado que selecciono Pro Mensual,
Cuando confirmo la selección,
Entonces el sistema asegura mi Customer de Stripe,
Y prepara el checkout para ese Price,
Y me solicita registrar un método de pago si no tengo uno (RF35),
Y responde 200 OK con el siguiente paso.
Escenario 2: Selección de plan Free
Dado que selecciono el plan Free, Cuando confirmo, Entonces el sistema aplica el plan Free sin requerir pago.
Escenario 3: Cambio de plan (upgrade/downgrade)
Dado que ya tengo un plan de pago activo,
Cuando selecciono otro plan de pago,
Entonces el sistema usa subscriptions.update() y Stripe calcula el prorrateo.
Escenario 4: Plan inválido
Dado que envío un planId inexistente,
Cuando el backend valida,
Entonces responde 400 con "Selecciona un plan válido".
Criterios no funcionales
- Llamadas de creación a Stripe con idempotency key para evitar duplicar customers/subscriptions.
STRIPE_SECRET_KEYsolo en el servidor; comunicación TLS 1.2+.