Saltar al contenido principal

RF38: Usuario realiza pago de suscripción

Descripción

Como usuario autenticado, quiero pagar mi plan de suscripción para activar el acceso premium de Finnova.

El backend crea la Subscription en Stripe vinculada al Price del plan y al PaymentMethod del usuario. La activación del acceso premium se confirma de forma autoritativa por webhook (customer.subscription.created / invoice.payment_succeeded), no solo por la respuesta síncrona (Stripe §1 Alta y §Webhooks).

CampoValor
MóduloSubscription Module
ActorUsuario autenticado
EndpointPOST /subscription + POST /webhooks/stripe
PrecondicionesSesión activa; método de pago válido (RF35); plan seleccionado (RF33)
PrioridadAlta (MVP)
EtapaMVP
Requisitos relacionadosRF33, RF35, RF45, RF40

Reglas de negocio

  • RN-38.1 — La creación de la Subscription usa idempotency key para evitar cobros duplicados ante reintentos.
  • RN-38.2 — El acceso premium se activa cuando llega el webhook validado de pago/suscripción exitosa, no por la respuesta inicial.
  • RN-38.3 — Si el pago requiere 3D Secure, se completa el reto antes de confirmar.
  • RN-38.4 — Si el pago falla, se inicia el flujo de dunning de Stripe y se notifica al usuario (RF41); no se activa premium.
  • RN-38.5 — En móvil, el cobro respeta la estrategia elegida (in-app store billing o web-first con Stripe — Suscripciones Mobile).

Validaciones de entrada

CampoReglasMensaje de error
planIdObligatorio. Plan válido."Selecciona un plan válido."
paymentMethodIdObligatorio si no hay default. Token válido."Registra un método de pago válido."
WebhookFirma verificada con STRIPE_WEBHOOK_SECRET.Se rechaza si la firma no es válida.

Criterios de aceptación

Escenario 1: Pago y activación exitosos

Dado que tengo un método de pago válido y selecciono un plan de pago, Cuando confirmo el pago, Entonces el backend crea la Subscription en Stripe (idempotente), Y al recibir el webhook validado de pago exitoso, activa mi acceso premium, Y responde reflejando la suscripción activa.

Escenario 2: Pago requiere 3D Secure

Dado que mi banco exige 3DS, Cuando pago, Entonces completo el reto 3DS con Stripe, Y la suscripción se activa solo tras la confirmación.

Escenario 3: Pago fallido

Dado que el cobro es rechazado, Cuando intento pagar, Entonces no se activa premium, Y se inicia el dunning y se me notifica (RF41) con un mensaje claro.

Escenario 4: Webhook con firma inválida (seguridad)

Dado que llega un webhook a /webhooks/stripe con firma inválida, Cuando el backend lo procesa, Entonces lo rechaza sin alterar el estado de la suscripción.

Escenario 5: Reintento idempotente

Dado que reintento el pago por un fallo de red, Cuando llega con la misma idempotency key, Entonces Stripe no genera un cargo duplicado.

Criterios no funcionales

  • Finnova nunca almacena datos de tarjeta (PCI SAQ A).
  • La activación premium es consistente con el webhook (fuente de verdad).
  • Comunicación TLS 1.2+; secretos de Stripe solo en el servidor.

Diagrama de secuencia