ML Engine Updates: - Updated BTCUSD with Polygon API data (2024-2025): 215,699 new records - Re-trained all ML models: Attention (R²: 0.223), Base, Metamodel (87.3% confidence) - Backtest results: +176.71R profit with aggressive_filter strategy Documentation Consolidation: - Created docs/99-analisis/_MAP.md index with 13 new analysis documents - Consolidated inventories: removed duplicates from orchestration/inventarios/ - Updated ML_INVENTORY.yml with BTCUSD metrics and training results - Added execution reports: FASE11-BTCUSD, correction issues, alignment validation Architecture & Integration: - Updated all module documentation with NEXUS v3.4 frontmatter - Fixed _MAP.md indexes across all folders - Updated orchestration plans and traces Files: 229 changed, 5064 insertions(+), 1872 deletions(-) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
407 lines
14 KiB
Markdown
407 lines
14 KiB
Markdown
---
|
|
id: "US-PAY-005"
|
|
title: "Comprar Curso con Pago Único"
|
|
type: "User Story"
|
|
status: "Done"
|
|
priority: "Media"
|
|
epic: "OQI-005"
|
|
project: "trading-platform"
|
|
story_points: 3
|
|
created_date: "2025-12-05"
|
|
updated_date: "2026-01-04"
|
|
---
|
|
|
|
# US-PAY-005: Comprar Curso con Pago Único
|
|
|
|
**Version:** 1.0.0
|
|
**Fecha:** 2025-12-05
|
|
**Estado:** ✅ Implementado
|
|
**Story Points:** 3
|
|
**Prioridad:** P1 (Alta)
|
|
**Épica:** [OQI-005](../_MAP.md)
|
|
|
|
---
|
|
|
|
## Historia de Usuario
|
|
|
|
**Como** usuario de Trading Platform (con o sin suscripción)
|
|
**Quiero** comprar acceso a un curso específico con pago único
|
|
**Para** aprender sobre trading sin compromiso de suscripción mensual
|
|
|
|
---
|
|
|
|
## Criterios de Aceptación
|
|
|
|
### AC-001: Ver Precio del Curso
|
|
|
|
**Dado** que estoy viendo la página de un curso
|
|
**Cuando** no tengo acceso al curso
|
|
**Entonces** debería ver:
|
|
- Precio del curso claramente visible (ej: $29.00 USD)
|
|
- Botón "Comprar Curso"
|
|
- Nota: "Acceso de por vida"
|
|
- Si tengo suscripción que incluye curso → Badge "Incluido en tu plan Pro"
|
|
|
|
### AC-002: Iniciar Compra
|
|
|
|
**Dado** que quiero comprar un curso
|
|
**Cuando** hago click en "Comprar Curso"
|
|
**Entonces** debería:
|
|
- Si NO estoy logueado → Ir a login/registro
|
|
- Si estoy logueado → Ir a checkout del curso
|
|
|
|
### AC-003: Checkout de Curso
|
|
|
|
**Dado** que estoy en checkout del curso
|
|
**Cuando** veo la página
|
|
**Entonces** debería ver:
|
|
- Resumen del curso (nombre, descripción breve, imagen)
|
|
- Precio total
|
|
- Opción de pago:
|
|
- Wallet (si tengo saldo)
|
|
- Tarjeta de crédito/débito
|
|
- Combinación (wallet + tarjeta si saldo insuficiente)
|
|
- Stripe Elements para ingresar tarjeta (si elijo tarjeta)
|
|
- Botón "Completar Compra"
|
|
|
|
### AC-004: Pago con Wallet
|
|
|
|
**Dado** que tengo $50 USD en mi wallet
|
|
**Cuando** intento comprar curso de $29 USD
|
|
**Entonces** debería:
|
|
- Ver opción "Pagar con Wallet" preseleccionada
|
|
- Ver balance actual: "$50.00 disponible"
|
|
- Ver balance después de compra: "$21.00"
|
|
- Poder confirmar compra con un click
|
|
- NO ver formulario de tarjeta
|
|
|
|
### AC-005: Pago con Tarjeta
|
|
|
|
**Dado** que elijo pagar con tarjeta
|
|
**Cuando** ingreso datos de tarjeta válidos
|
|
**Entonces** debería:
|
|
- Ver Stripe Elements para tarjeta
|
|
- Completar datos (número, vencimiento, CVC, nombre)
|
|
- Confirmar pago
|
|
- Ver indicador de procesamiento
|
|
- Recibir confirmación después de 2-5 segundos
|
|
|
|
### AC-006: Pago Mixto (Wallet + Tarjeta)
|
|
|
|
**Dado** que tengo $20 en wallet pero curso cuesta $29
|
|
**Cuando** selecciono "Usar wallet + tarjeta"
|
|
**Entonces** debería:
|
|
- Ver desglose:
|
|
- "Wallet: $20.00"
|
|
- "Tarjeta: $9.00"
|
|
- "Total: $29.00"
|
|
- Ingresar solo tarjeta para $9.00
|
|
- Confirmar compra
|
|
- Ver ambos débitos aplicados correctamente
|
|
|
|
### AC-007: Confirmación de Compra
|
|
|
|
**Dado** que completé el pago exitosamente
|
|
**Cuando** se confirma la compra
|
|
**Entonces** debería:
|
|
- Ver página de confirmación: "¡Compra exitosa!"
|
|
- Ver mensaje: "Ya tienes acceso a {nombre del curso}"
|
|
- Ver botón "Comenzar Curso"
|
|
- Recibir email con:
|
|
- Confirmación de compra
|
|
- Link directo al curso
|
|
- Factura en PDF adjunta
|
|
|
|
### AC-008: Acceso Inmediato al Curso
|
|
|
|
**Dado** que compré el curso exitosamente
|
|
**Cuando** navego al curso
|
|
**Entonces** debería:
|
|
- Tener acceso completo inmediato
|
|
- Ver botón "Continuar" o "Comenzar" en lugar de "Comprar"
|
|
- Poder reproducir todos los videos
|
|
- Poder descargar recursos del curso
|
|
- Ver progreso guardado automáticamente
|
|
|
|
### AC-009: Ya Tengo Acceso al Curso
|
|
|
|
**Dado** que ya compré el curso previamente
|
|
**Cuando** intento comprarlo de nuevo
|
|
**Entonces** debería:
|
|
- Ver mensaje: "Ya tienes acceso a este curso"
|
|
- Ver botón "Ir al Curso" en lugar de "Comprar"
|
|
- NO permitir compra duplicada
|
|
|
|
### AC-010: Curso Incluido en Suscripción
|
|
|
|
**Dado** que tengo suscripción Pro que incluye todos los cursos
|
|
**Cuando** veo un curso
|
|
**Entonces** debería:
|
|
- Ver badge: "Incluido en tu plan Pro"
|
|
- NO ver precio ni botón de compra
|
|
- Ver botón "Comenzar Curso"
|
|
- Tener acceso inmediato
|
|
|
|
### AC-011: Error de Pago
|
|
|
|
**Dado** que mi pago falla (tarjeta rechazada)
|
|
**Cuando** intento completar la compra
|
|
**Entonces** debería:
|
|
- Ver mensaje de error específico
|
|
- Permanecer en checkout
|
|
- Poder reintentar con otra tarjeta
|
|
- NO tener acceso al curso
|
|
- NO tener registro de compra en historial
|
|
|
|
---
|
|
|
|
## Mockup
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ │
|
|
│ Comprar: Trading Básico 101 │
|
|
│ │
|
|
├─────────────────────────────────────────────────────────────┤
|
|
│ │
|
|
│ ┌────────────────┐ Trading Básico 101 │
|
|
│ │ │ Aprende los fundamentos del trading │
|
|
│ │ [Curso IMG] │ │
|
|
│ │ │ 4.8 ⭐ (234 reviews) │
|
|
│ └────────────────┘ 12 módulos • 8 horas │
|
|
│ │
|
|
│ ─────────────────────────────────────────────────────── │
|
|
│ │
|
|
│ 💰 Precio: $29.00 USD │
|
|
│ ✅ Acceso de por vida │
|
|
│ ✅ Certificado de finalización │
|
|
│ │
|
|
│ ─────────────────────────────────────────────────────── │
|
|
│ │
|
|
│ Método de Pago: │
|
|
│ │
|
|
│ ○ Wallet ($50.00 disponible) │
|
|
│ Balance después: $21.00 │
|
|
│ │
|
|
│ ● Tarjeta de Crédito/Débito │
|
|
│ │
|
|
│ ┌─────────────────────────────────────────────────┐ │
|
|
│ │ Número de tarjeta │ │
|
|
│ │ ┌─────────────────────────────────────────┐ │ │
|
|
│ │ │ 4242 4242 4242 4242 [Visa] │ │ │
|
|
│ │ └─────────────────────────────────────────┘ │ │
|
|
│ │ │ │
|
|
│ │ ┌──────────────┐ ┌──────────────┐ │ │
|
|
│ │ │ 12 / 25 │ │ 123 │ │ │
|
|
│ │ └──────────────┘ └──────────────┘ │ │
|
|
│ │ │ │
|
|
│ │ ┌─────────────────────────────────────────┐ │ │
|
|
│ │ │ Juan Pérez │ │ │
|
|
│ │ └─────────────────────────────────────────┘ │ │
|
|
│ └─────────────────────────────────────────────────┘ │
|
|
│ │
|
|
│ ○ Wallet + Tarjeta ($20 wallet + $9 tarjeta) │
|
|
│ │
|
|
│ ─────────────────────────────────────────────────────── │
|
|
│ │
|
|
│ Total a pagar: $29.00 USD │
|
|
│ │
|
|
│ ┌─────────────────────────────────────────────────────┐ │
|
|
│ │ Completar Compra - $29.00 │ │
|
|
│ └─────────────────────────────────────────────────────┘ │
|
|
│ │
|
|
│ 🔒 Pago seguro con Stripe │
|
|
│ 📧 Recibirás factura por email │
|
|
│ │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## Flujo de Compra (Gherkin)
|
|
|
|
```gherkin
|
|
Feature: Comprar Curso con Pago Único
|
|
|
|
Scenario: Compra exitosa con tarjeta
|
|
Given que soy usuario logueado "juan@example.com"
|
|
And estoy viendo el curso "Trading Básico 101" que cuesta $29 USD
|
|
And NO tengo acceso al curso
|
|
When hago click en "Comprar Curso"
|
|
Then debería ver página de checkout del curso
|
|
|
|
When selecciono "Tarjeta de crédito/débito"
|
|
And ingreso tarjeta "4242 4242 4242 4242"
|
|
And completo datos de pago
|
|
And hago click en "Completar Compra"
|
|
Then debería ver indicador de procesamiento
|
|
And después de 3 segundos debería ver "¡Compra exitosa!"
|
|
|
|
And debería ver botón "Comenzar Curso"
|
|
And debería recibir email con factura
|
|
And debería tener acceso completo al curso
|
|
And mi historial debería mostrar pago de $29 USD
|
|
|
|
Scenario: Compra con wallet
|
|
Given que tengo $50 en mi wallet
|
|
And estoy en checkout de curso de $29 USD
|
|
When selecciono "Pagar con Wallet"
|
|
And hago click en "Completar Compra"
|
|
Then la compra se completa instantáneamente
|
|
And mi wallet debería tener $21.00
|
|
And debería ver "¡Compra exitosa!"
|
|
|
|
Scenario: Intento comprar curso que ya tengo
|
|
Given que ya compré el curso "Trading Básico 101"
|
|
When intento acceder a checkout del mismo curso
|
|
Then debería ver mensaje "Ya tienes acceso a este curso"
|
|
And debería ver botón "Ir al Curso"
|
|
And NO debería ver formulario de pago
|
|
|
|
Scenario: Curso incluido en mi suscripción
|
|
Given que tengo suscripción "Pro"
|
|
And el plan Pro incluye todos los cursos
|
|
When veo la página del curso "Trading Básico 101"
|
|
Then debería ver badge "Incluido en tu plan Pro"
|
|
And NO debería ver precio ni botón "Comprar"
|
|
And debería ver botón "Comenzar Curso"
|
|
```
|
|
|
|
---
|
|
|
|
## Notas Técnicas
|
|
|
|
### Frontend
|
|
|
|
- Componente: `apps/frontend/src/pages/CourseCheckout.tsx`
|
|
- Props: `courseId`, `price`, `courseName`
|
|
- Integrar Stripe Elements (CardElement)
|
|
- Verificar balance de wallet
|
|
- Mostrar opciones de pago según disponibilidad
|
|
|
|
### Backend
|
|
|
|
- Endpoint: `POST /api/v1/payments/create-payment-intent`
|
|
- Request:
|
|
```json
|
|
{
|
|
"amount": 2900,
|
|
"currency": "usd",
|
|
"type": "course_purchase",
|
|
"courseId": "uuid-curso",
|
|
"description": "Trading Básico 101",
|
|
"paymentMethod": "card" | "wallet" | "mixed"
|
|
}
|
|
```
|
|
|
|
- Response:
|
|
```json
|
|
{
|
|
"clientSecret": "pi_xxx_secret_yyy",
|
|
"paymentIntentId": "pi_xxx",
|
|
"amount": 2900,
|
|
"currency": "usd"
|
|
}
|
|
```
|
|
|
|
### Webhook Processing
|
|
|
|
Cuando `payment_intent.succeeded`:
|
|
1. Verificar `metadata.type === 'course_purchase'`
|
|
2. Obtener `metadata.courseId` y `metadata.userId`
|
|
3. Otorgar acceso: `user_courses.create({ userId, courseId, purchasedAt })`
|
|
4. Actualizar payment status
|
|
5. Generar factura PDF
|
|
6. Enviar email de confirmación
|
|
|
|
### Database
|
|
|
|
**Tablas afectadas:**
|
|
```sql
|
|
-- Registro de pago
|
|
billing.payments (
|
|
id, userId, type='course_purchase',
|
|
status='succeeded', amount=29.00, courseId
|
|
)
|
|
|
|
-- Acceso al curso
|
|
education.user_courses (
|
|
id, userId, courseId, access_type='purchased',
|
|
purchasedAt, expiresAt=null
|
|
)
|
|
```
|
|
|
|
### Email Template
|
|
|
|
**Subject:** Tu compra de "Trading Básico 101"
|
|
|
|
```
|
|
Hola Juan,
|
|
|
|
¡Gracias por tu compra! 🎉
|
|
|
|
Ya tienes acceso completo al curso:
|
|
📚 Trading Básico 101
|
|
|
|
[Comenzar Curso]
|
|
|
|
Tu factura está adjunta a este email.
|
|
|
|
Detalles de la compra:
|
|
- Curso: Trading Básico 101
|
|
- Precio: $29.00 USD
|
|
- Fecha: 05/12/2025
|
|
- Factura: INV-2025-000042
|
|
|
|
¿Necesitas ayuda? Escríbenos a support@trading.com
|
|
|
|
¡Feliz aprendizaje!
|
|
El equipo de Trading Platform
|
|
```
|
|
|
|
---
|
|
|
|
## Dependencias
|
|
|
|
- [US-PAY-006: Agregar Método de Pago](US-PAY-006-agregar-metodo-pago.md)
|
|
- Módulo de educación (cursos)
|
|
- Sistema de wallet (RF-PAY-003)
|
|
|
|
---
|
|
|
|
## Requerimientos Relacionados
|
|
|
|
- [RF-PAY-002: Checkout con Stripe Elements](../requerimientos/RF-PAY-002-checkout.md)
|
|
- [RF-PAY-003: Sistema de Wallet](../requerimientos/RF-PAY-003-wallet.md)
|
|
- [RF-PAY-004: Sistema de Facturación](../requerimientos/RF-PAY-004-facturacion.md)
|
|
|
|
---
|
|
|
|
## Tareas Técnicas
|
|
|
|
### Frontend
|
|
- [ ] Página `CourseCheckout.tsx`
|
|
- [ ] Selector de método de pago (wallet/card/mixed)
|
|
- [ ] Integración Stripe Elements
|
|
- [ ] Cálculo dinámico de pago mixto
|
|
- [ ] Página de confirmación
|
|
- [ ] Manejo de errores
|
|
|
|
### Backend
|
|
- [ ] Endpoint `POST /payments/create-payment-intent`
|
|
- [ ] Validar que usuario NO tenga acceso ya
|
|
- [ ] Validar balance de wallet si aplica
|
|
- [ ] Crear PaymentIntent con metadata correcta
|
|
- [ ] Webhook: Otorgar acceso al curso
|
|
- [ ] Generar factura PDF
|
|
- [ ] Enviar email de confirmación
|
|
|
|
### Testing
|
|
- [ ] Test: Compra con tarjeta exitosa
|
|
- [ ] Test: Compra con wallet exitosa
|
|
- [ ] Test: Compra mixta wallet+tarjeta exitosa
|
|
- [ ] Test: No permite comprar curso que ya tiene
|
|
- [ ] Test: No permite comprar si incluido en suscripción
|
|
- [ ] Test: Acceso se otorga inmediatamente
|
|
- [ ] Test: Factura se genera correctamente
|