trading-platform/docs/02-definicion-modulos/OQI-005-payments-stripe/README.md
rckrdmrd a7cca885f0 feat: Major platform documentation and architecture updates
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>
2026-01-07 05:33:35 -06:00

251 lines
6.4 KiB
Markdown

---
id: "README"
title: "Sistema de Pagos con Stripe"
type: "Documentation"
project: "trading-platform"
version: "1.0.0"
updated_date: "2026-01-04"
---
# OQI-005: Sistema de Pagos con Stripe
**Estado:** ✅ Implementado
**Fecha:** 2025-12-05
**Modulo:** `apps/backend/src/modules/payments`
---
## Descripcion
Sistema completo de pagos integrado con Stripe para:
- Pagos unicos (compra de cursos)
- Suscripciones mensuales (planes Basic, Pro, Premium)
- Webhooks para eventos de pago
- Historial de transacciones
---
## Arquitectura
```
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Frontend │────▶│ NestJS API │────▶│ Stripe │
│ (React) │ │ /payments/* │ │ API │
└─────────────────┘ └─────────────────┘ └─────────────────┘
┌─────────────────┐
│ PostgreSQL │
│ billing schema │
└─────────────────┘
```
---
## Endpoints
| Metodo | Ruta | Descripcion | Auth |
|--------|------|-------------|------|
| POST | `/payments/create-payment-intent` | Crear pago directo | JWT |
| POST | `/payments/create-checkout-session` | Checkout hosted | JWT |
| POST | `/payments/subscriptions` | Crear suscripcion | JWT |
| GET | `/payments/subscriptions/current` | Suscripcion actual | JWT |
| DELETE | `/payments/subscriptions/:id` | Cancelar suscripcion | JWT |
| GET | `/payments/history` | Historial de pagos | JWT |
| POST | `/payments/webhook` | Webhook Stripe | - |
---
## Entidades
### Payment
```typescript
@Entity({ name: 'payments', schema: 'billing' })
class Payment {
id: string; // UUID
userId: string; // FK a users
type: PaymentType; // course_purchase | subscription | one_time
status: PaymentStatus; // pending | processing | succeeded | failed | cancelled | refunded
amount: number; // Monto en USD
currency: string; // USD
stripePaymentIntentId: string;
stripeCustomerId: string;
courseId?: string; // Si es compra de curso
subscriptionId?: string; // Si es pago de suscripcion
description?: string;
metadata?: object;
failureReason?: string;
refundedAt?: Date;
createdAt: Date;
updatedAt: Date;
}
```
### Subscription
```typescript
@Entity({ name: 'subscriptions', schema: 'billing' })
class Subscription {
id: string; // UUID
userId: string; // FK a users
plan: SubscriptionPlan; // basic | pro | premium
status: SubscriptionStatus; // active | past_due | cancelled | incomplete | trialing | unpaid
stripeSubscriptionId: string;
stripeCustomerId: string;
stripePriceId: string;
price: number; // Precio mensual
currency: string; // USD
billingInterval: string; // month | year
currentPeriodStart: Date;
currentPeriodEnd: Date;
trialEnd?: Date;
cancelledAt?: Date;
cancelAtPeriodEnd: boolean;
metadata?: object;
createdAt: Date;
updatedAt: Date;
}
```
---
## Planes de Suscripcion
| Plan | Precio | Price ID | Caracteristicas |
|------|--------|----------|-----------------|
| Basic | $19/mes | `price_1Sb3k64dPtEGmLmpeAdxvmIu` | Predicciones basicas, cursos intro |
| Pro | $49/mes | `price_1Sb3k64dPtEGmLmpm5n5bbJH` | Predicciones avanzadas, todos los cursos |
| Premium | $99/mes | `price_1Sb3k74dPtEGmLmpHfLpUkvQ` | Todo + soporte prioritario |
---
## Flujo de Pago
### Pago Unico (Payment Intent)
```
1. Frontend solicita crear payment intent
2. Backend crea PaymentIntent en Stripe
3. Backend guarda registro en BD (status: pending)
4. Frontend recibe clientSecret
5. Frontend muestra formulario de tarjeta (Stripe Elements)
6. Usuario completa pago
7. Stripe envia webhook (payment_intent.succeeded)
8. Backend actualiza status a succeeded
9. Backend otorga acceso al recurso
```
### Suscripcion
```
1. Frontend solicita crear suscripcion
2. Backend obtiene/crea Customer en Stripe
3. Backend adjunta metodo de pago
4. Backend crea Subscription en Stripe
5. Backend guarda registro en BD
6. Stripe cobra automaticamente cada mes
7. Webhooks actualizan estado
```
---
## Configuracion
### Variables de Entorno
```env
STRIPE_SECRET_KEY=sk_test_xxx
STRIPE_WEBHOOK_SECRET=whsec_xxx
FRONTEND_URL=http://localhost:5173
```
### Webhook Events
| Evento | Accion |
|--------|--------|
| `payment_intent.succeeded` | Actualizar pago a succeeded, otorgar acceso |
| `payment_intent.payment_failed` | Actualizar pago a failed |
| `customer.subscription.updated` | Sincronizar estado de suscripcion |
| `customer.subscription.deleted` | Marcar suscripcion como cancelled |
---
## Ejemplo de Uso
### Crear Payment Intent
```bash
curl -X POST http://localhost:3000/payments/create-payment-intent \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"amount": 2900,
"currency": "usd",
"type": "course_purchase",
"courseId": "uuid-del-curso",
"description": "Curso de Trading Basico"
}'
```
Respuesta:
```json
{
"clientSecret": "pi_xxx_secret_xxx",
"paymentIntentId": "pi_xxx",
"amount": 2900,
"currency": "usd"
}
```
### Crear Suscripcion
```bash
curl -X POST http://localhost:3000/payments/subscriptions \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"plan": "pro",
"paymentMethodId": "pm_xxx"
}'
```
---
## Modo Mock
Cuando `STRIPE_SECRET_KEY` no esta configurado, el sistema funciona en modo mock:
- Retorna payment intents simulados
- Las suscripciones se crean localmente
- Util para desarrollo sin cuenta Stripe
---
## Archivos
```
apps/backend/src/modules/payments/
├── dto/
│ ├── payment.dto.ts
│ └── subscription.dto.ts
├── entities/
│ ├── payment.entity.ts
│ └── subscription.entity.ts
├── payments.controller.ts
├── payments.service.ts
└── payments.module.ts
```
---
## Seguridad
- Todos los endpoints requieren JWT (excepto webhook)
- Webhook valida firma de Stripe
- Claves secretas en variables de entorno
- Nunca exponer `sk_test_*` en frontend
---
*Documentacion generada: 2025-12-05*