--- id: "PMC-009-PAYMENTS" title: "PMC-009: Modulo de Payments" type: "Module Definition" epic: "PMC-009" status: "Draft" project: "platform_marketing_content" version: "1.0.0" created_date: "2026-01-04" updated_date: "2026-01-04" --- # PMC-009: Modulo de Payments **Version:** 1.0.0 **Fecha:** 2026-01-04 **Estado:** Definicion **Prioridad:** Alta --- ## Descripcion General El modulo de Payments proporciona la integracion completa con Stripe para gestionar suscripciones, pagos y facturacion del sistema SaaS. Incluye checkout flow con Stripe Elements, gestion de planes de suscripcion, facturacion automatica y sistema de creditos de generacion. ### Objetivos 1. Integrar Stripe como pasarela de pagos principal 2. Gestionar planes de suscripcion (Free, Pro, Enterprise, Internal) 3. Implementar checkout flow con Stripe Elements 4. Automatizar facturacion y cobros recurrentes 5. Gestionar creditos de generacion por tenant 6. Procesar webhooks de Stripe para sincronizar estados --- ## Planes de Suscripcion ```yaml Planes Disponibles: free: nombre: "Free" precio: $0/mes limites: generaciones_mes: 50 storage_gb: 1 usuarios_max: 1 modelos_custom: 0 features: - Generacion basica de imagenes - 1 proyecto activo - Soporte por email pro: nombre: "Pro" precio: $79/mes stripe_price_id: pmc_pro limites: generaciones_mes: 500 storage_gb: 25 usuarios_max: 5 modelos_custom: 3 features: - Todo de Free - Modelos personalizados - API access - Integraciones n8n - Soporte prioritario enterprise: nombre: "Enterprise" precio: $249/mes stripe_price_id: pmc_enterprise limites: generaciones_mes: unlimited storage_gb: 100 usuarios_max: unlimited modelos_custom: unlimited features: - Todo de Pro - Generaciones ilimitadas - Usuarios ilimitados - SSO/SAML - SLA garantizado - Soporte dedicado internal: nombre: "Internal" precio: $0/mes limites: generaciones_mes: unlimited storage_gb: unlimited usuarios_max: unlimited modelos_custom: unlimited features: - Acceso completo sin restricciones - Solo para uso interno de la organizacion ``` --- ## Productos Stripe Propuestos ```yaml Productos Stripe: pmc_pro: type: subscription nombre: "PMC Pro Plan" precio: $79/mes billing_interval: monthly descripcion: "500 generaciones, 25GB storage, 5 usuarios" metadata: plan_code: pro generations: 500 storage_gb: 25 users_max: 5 pmc_enterprise: type: subscription nombre: "PMC Enterprise Plan" precio: $249/mes billing_interval: monthly descripcion: "Generaciones ilimitadas, recursos ilimitados" metadata: plan_code: enterprise generations: unlimited storage_gb: 100 users_max: unlimited pmc_generations_100: type: one_time nombre: "Pack 100 Generaciones Extra" precio: $19 descripcion: "100 creditos de generacion adicionales" metadata: product_type: credits credits_amount: 100 ``` --- ## Entidades del Dominio ### Subscription ```yaml Entidad: Subscription Descripcion: Suscripcion activa de un tenant a un plan Atributos: - id: UUID (PK) - tenant_id: UUID (FK a Tenant) - user_id: UUID (FK a User, quien suscribio) - plan_id: UUID (FK a Plan) - stripe_subscription_id: string (sub_xxx) - stripe_customer_id: string (cus_xxx) - status: enum [active, past_due, canceled, incomplete, trialing, paused] - current_period_start: timestamp - current_period_end: timestamp - cancel_at_period_end: boolean - canceled_at: timestamp - trial_start: timestamp - trial_end: timestamp - metadata: JSONB - created_at: timestamp - updated_at: timestamp Relaciones: - N:1 con Tenant - N:1 con User - N:1 con Plan - 1:N con Invoice ``` ### Invoice ```yaml Entidad: Invoice Descripcion: Factura generada por Stripe Atributos: - id: UUID (PK) - tenant_id: UUID (FK) - subscription_id: UUID (FK a Subscription) - stripe_invoice_id: string (in_xxx) - stripe_invoice_number: string - amount_due: decimal - amount_paid: decimal - currency: string (usd, eur) - status: enum [draft, open, paid, void, uncollectible] - invoice_pdf_url: string - hosted_invoice_url: string - paid_at: timestamp - due_date: timestamp - period_start: timestamp - period_end: timestamp - created_at: timestamp - updated_at: timestamp Relaciones: - N:1 con Tenant - N:1 con Subscription ``` ### PaymentMethod ```yaml Entidad: PaymentMethod Descripcion: Metodo de pago registrado del cliente Atributos: - id: UUID (PK) - tenant_id: UUID (FK) - user_id: UUID (FK) - stripe_payment_method_id: string (pm_xxx) - type: enum [card, sepa_debit, us_bank_account] - card_brand: string (visa, mastercard, amex) - card_last4: string - card_exp_month: integer - card_exp_year: integer - is_default: boolean - billing_details: JSONB (name, email, address) - created_at: timestamp - updated_at: timestamp Relaciones: - N:1 con Tenant - N:1 con User ``` ### GenerationCredit ```yaml Entidad: GenerationCredit Descripcion: Balance de creditos de generacion por tenant Atributos: - id: UUID (PK) - tenant_id: UUID (FK, unico) - credits_included: integer (del plan) - credits_remaining: integer (del periodo actual) - credits_used: integer (del periodo actual) - credits_extra: integer (comprados, no expiran) - resets_at: timestamp (inicio proximo periodo) - last_reset_at: timestamp - created_at: timestamp - updated_at: timestamp Relaciones: - 1:1 con Tenant Notas: - credits_remaining se resetea cada periodo de facturacion - credits_extra no se resetean, son acumulables - Al consumir, primero se usan credits_remaining, luego credits_extra ``` ### CreditTransaction ```yaml Entidad: CreditTransaction Descripcion: Historial de movimientos de creditos Atributos: - id: UUID (PK) - tenant_id: UUID (FK) - type: enum [subscription_reset, purchase, usage, adjustment, refund] - amount: integer (positivo o negativo) - balance_after: integer - description: string - reference_type: string (generation_job, invoice, manual) - reference_id: UUID - created_at: timestamp Relaciones: - N:1 con Tenant ``` --- ## Funcionalidades ### F-009.1: Seleccionar Plan y Suscribirse | ID | Funcionalidad | Descripcion | Prioridad | |----|---------------|-------------|-----------| | F-009.1.1 | Ver planes disponibles | Mostrar comparativa de planes | Alta | | F-009.1.2 | Seleccionar plan | Elegir plan deseado | Alta | | F-009.1.3 | Crear customer Stripe | Registrar cliente en Stripe | Alta | | F-009.1.4 | Iniciar trial | Periodo de prueba de 14 dias | Media | ### F-009.2: Checkout con Stripe Elements | ID | Funcionalidad | Descripcion | Prioridad | |----|---------------|-------------|-----------| | F-009.2.1 | Crear checkout session | Generar sesion de pago Stripe | Alta | | F-009.2.2 | Stripe Elements UI | Formulario de pago embebido | Alta | | F-009.2.3 | Confirmar pago | Procesar transaccion | Alta | | F-009.2.4 | Manejar errores | Reintentos y mensajes claros | Alta | ### F-009.3: Gestionar Suscripcion | ID | Funcionalidad | Descripcion | Prioridad | |----|---------------|-------------|-----------| | F-009.3.1 | Ver suscripcion actual | Detalles del plan activo | Alta | | F-009.3.2 | Upgrade de plan | Cambiar a plan superior | Alta | | F-009.3.3 | Downgrade de plan | Cambiar a plan inferior | Media | | F-009.3.4 | Cancelar suscripcion | Finalizar al terminar periodo | Media | | F-009.3.5 | Reactivar suscripcion | Revertir cancelacion pendiente | Media | ### F-009.4: Ver Facturas e Historial | ID | Funcionalidad | Descripcion | Prioridad | |----|---------------|-------------|-----------| | F-009.4.1 | Listar facturas | Historial de pagos | Alta | | F-009.4.2 | Descargar factura PDF | Obtener comprobante | Alta | | F-009.4.3 | Ver detalle de factura | Items, impuestos, totales | Media | ### F-009.5: Comprar Creditos Adicionales | ID | Funcionalidad | Descripcion | Prioridad | |----|---------------|-------------|-----------| | F-009.5.1 | Ver packs disponibles | Mostrar opciones de creditos | Media | | F-009.5.2 | Comprar pack | Checkout one-time | Media | | F-009.5.3 | Acreditar creditos | Sumar a credits_extra | Media | ### F-009.6: Webhooks de Stripe | ID | Funcionalidad | Descripcion | Prioridad | |----|---------------|-------------|-----------| | F-009.6.1 | invoice.paid | Actualizar estado de factura | Alta | | F-009.6.2 | invoice.payment_failed | Notificar y manejar fallo | Alta | | F-009.6.3 | customer.subscription.updated | Sincronizar cambios de suscripcion | Alta | | F-009.6.4 | customer.subscription.deleted | Manejar cancelacion | Alta | | F-009.6.5 | checkout.session.completed | Confirmar compra one-time | Alta | --- ## API Endpoints ```yaml Base: /api/v1/billing # Checkout y Suscripcion POST /billing/checkout: Descripcion: Crear sesion de checkout Stripe Body: { plan_code: "pro", success_url: string, cancel_url: string } Response: { checkout_url: string, session_id: string } Permisos: tenant_admin GET /billing/subscription: Descripcion: Ver suscripcion actual del tenant Response: { subscription, plan, usage } Permisos: authenticated POST /billing/subscription/upgrade: Descripcion: Upgrade inmediato a plan superior Body: { new_plan_code: string } Response: { subscription, proration_amount } Permisos: tenant_admin POST /billing/subscription/downgrade: Descripcion: Downgrade al final del periodo Body: { new_plan_code: string } Response: { subscription, effective_date } Permisos: tenant_admin POST /billing/subscription/cancel: Descripcion: Cancelar suscripcion al final del periodo Body: { reason?: string, feedback?: string } Response: { subscription, cancel_at } Permisos: tenant_admin POST /billing/subscription/reactivate: Descripcion: Revertir cancelacion pendiente Response: { subscription } Permisos: tenant_admin # Metodos de Pago GET /billing/payment-methods: Descripcion: Listar metodos de pago Response: { payment_methods: [] } Permisos: tenant_admin POST /billing/payment-methods: Descripcion: Agregar metodo de pago Body: { payment_method_id: string } Response: { payment_method } Permisos: tenant_admin DELETE /billing/payment-methods/:id: Descripcion: Eliminar metodo de pago Response: 204 No Content Permisos: tenant_admin PATCH /billing/payment-methods/:id/default: Descripcion: Establecer como metodo predeterminado Response: { payment_method } Permisos: tenant_admin # Facturas GET /billing/invoices: Descripcion: Listar facturas del tenant Query: ?status=paid&page=1&limit=20 Response: { invoices: [], pagination } Permisos: tenant_admin GET /billing/invoices/:id: Descripcion: Detalle de factura Response: { invoice } Permisos: tenant_admin GET /billing/invoices/:id/pdf: Descripcion: Descargar PDF de factura Response: Redirect a URL de Stripe Permisos: tenant_admin # Creditos GET /billing/credits: Descripcion: Ver balance de creditos Response: { credits_remaining, credits_extra, credits_used, resets_at } Permisos: authenticated POST /billing/credits/purchase: Descripcion: Comprar pack de creditos Body: { pack_code: "pmc_generations_100" } Response: { checkout_url, session_id } Permisos: tenant_admin GET /billing/credits/transactions: Descripcion: Historial de movimientos de creditos Query: ?type=usage&page=1&limit=50 Response: { transactions: [], pagination } Permisos: tenant_admin # Webhooks (endpoint publico) POST /billing/webhooks: Descripcion: Endpoint para webhooks de Stripe Headers: Stripe-Signature Response: 200 OK Notas: Verificar firma con STRIPE_WEBHOOK_SECRET ``` --- ## Reglas de Negocio ```yaml RN-009.1: Descripcion: Solo tenant_admin puede cambiar plan Validacion: Verificar rol del usuario Accion: 403 Forbidden si no es admin RN-009.2: Descripcion: Downgrade aplica al final del periodo Validacion: No cambio inmediato, schedule para renewal Accion: Stripe schedule subscription update RN-009.3: Descripcion: Creditos del plan no usados no se transfieren Validacion: credits_remaining se resetea cada periodo Excepcion: credits_extra (comprados) son permanentes RN-009.4: Descripcion: Cancelacion permite usar hasta fin del periodo Validacion: cancel_at_period_end = true Accion: Acceso continua hasta current_period_end RN-009.5: Descripcion: Plan Free no requiere metodo de pago Validacion: Permitir suscripcion sin checkout Accion: Crear subscription con trial infinito o sin cobro RN-009.6: Descripcion: Upgrade es inmediato con prorrateo Validacion: Cobrar diferencia proporcional Accion: Stripe proration automatico RN-009.7: Descripcion: Pago fallido da 3 reintentos Validacion: Stripe Smart Retries habilitado Accion: Notificar usuario, suspender tras fallos RN-009.8: Descripcion: Creditos se consumen en orden Validacion: Primero credits_remaining, luego credits_extra Accion: Logica en GenerationService RN-009.9: Descripcion: Plan Internal solo asignable por super_admin Validacion: Verificar rol super_admin Accion: No disponible en checkout publico ``` --- ## Dependencias ```yaml Dependencias de Modulos: - PMC-001 Tenants: uso: Asociacion tenant-plan, limites por tenant datos: tenant_id, plan_id, limits JSONB - PMC-007 Admin: uso: Permisos de billing, gestion de planes datos: admin.billing permission - PMC-004 Generation: uso: Consumo de creditos por generacion integracion: Decrementar credits al generar Dependencias del Catalogo: - @CATALOG_PAYMENTS: path: shared/catalog/payments/ uso: Patron base de integracion Stripe incluye: - Stripe SDK wrapper - Webhook handling - Customer management - Subscription lifecycle adaptar: - Crear productos/precios PMC en Stripe - Implementar sistema de creditos - Integrar con planes de PMC-001 docs: shared/catalog/payments/README.md - @CATALOG_NOTIFY: path: shared/catalog/notifications/ uso: Notificaciones de pago incluye: - Email de confirmacion de pago - Alerta de pago fallido - Recordatorio de vencimiento docs: shared/catalog/notifications/README.md Servicios Externos: - Stripe: tipo: Payment Gateway productos: - Subscriptions API - Checkout Sessions - Payment Intents - Webhooks - Customer Portal sdk: stripe (npm) version: "^14.0.0" Referencia de Implementacion: - Payment service: projects/gamilit/apps/backend/src/modules/payments/ - Stripe integration: projects/gamilit/apps/backend/src/modules/payments/services/stripe.service.ts - Webhook handler: projects/gamilit/apps/backend/src/modules/payments/controllers/webhooks.controller.ts ``` --- ## Configuracion ```yaml Variables de Entorno: STRIPE_SECRET_KEY: descripcion: API key secreta de Stripe formato: sk_live_xxx o sk_test_xxx requerido: true STRIPE_PUBLISHABLE_KEY: descripcion: API key publica para frontend formato: pk_live_xxx o pk_test_xxx requerido: true STRIPE_WEBHOOK_SECRET: descripcion: Secret para verificar webhooks formato: whsec_xxx requerido: true STRIPE_PRICE_PRO: descripcion: Price ID del plan Pro formato: price_xxx requerido: true STRIPE_PRICE_ENTERPRISE: descripcion: Price ID del plan Enterprise formato: price_xxx requerido: true STRIPE_PRICE_CREDITS_100: descripcion: Price ID del pack de 100 creditos formato: price_xxx requerido: true STRIPE_TRIAL_DAYS: descripcion: Dias de prueba para nuevas suscripciones default: 14 requerido: false BILLING_CURRENCY: descripcion: Moneda por defecto default: "usd" requerido: false ``` --- ## Flujos de Usuario ### Suscribirse a Plan Pro ``` 1. Usuario navega a Settings → Billing → Plans 2. Ve comparativa de planes (Free, Pro, Enterprise) 3. Selecciona "Upgrade to Pro" 4. Sistema crea Checkout Session en Stripe 5. Redirect a Stripe Checkout 6. Usuario ingresa datos de pago (Stripe Elements) 7. Stripe procesa pago 8. Webhook invoice.paid recibido 9. Sistema actualiza subscription y credits 10. Redirect a success_url con confirmacion ``` ### Cancelar Suscripcion ``` 1. Admin navega a Settings → Billing → Subscription 2. Click en "Cancel Subscription" 3. Modal de confirmacion con fecha de fin 4. Opcionalmente ingresa razon/feedback 5. Sistema llama Stripe cancel at period end 6. Suscripcion marcada cancel_at_period_end = true 7. Usuario puede seguir usando hasta current_period_end 8. Al vencer, subscription status = canceled ``` ### Comprar Creditos Extra ``` 1. Usuario ve que credits_remaining esta bajo 2. Navega a Settings → Billing → Credits 3. Ve packs disponibles (100 creditos por $19) 4. Click en "Buy Credits" 5. Checkout Session para one-time payment 6. Stripe procesa pago 7. Webhook checkout.session.completed 8. Sistema suma credits_extra += 100 9. Redirect con confirmacion ``` --- ## Webhooks de Stripe ```yaml Eventos a Procesar: invoice.paid: accion: - Actualizar Invoice status = paid - Si es primera factura, activar subscription - Reset credits_remaining del periodo invoice.payment_failed: accion: - Actualizar Invoice status segun attempt - Notificar usuario por email - Tras 3 fallos, marcar subscription past_due customer.subscription.created: accion: - Crear registro Subscription local - Crear GenerationCredit para tenant - Actualizar tenant.plan_id customer.subscription.updated: accion: - Sincronizar status, period dates - Si cambio de plan, actualizar limits - Recalcular credits si aplica customer.subscription.deleted: accion: - Marcar subscription status = canceled - Cambiar tenant a plan Free - Notificar admin del tenant checkout.session.completed: accion: - Si mode = subscription, ya manejado por invoice.paid - Si mode = payment (creditos), acreditar credits_extra - Crear CreditTransaction customer.created: accion: - Actualizar tenant con stripe_customer_id payment_method.attached: accion: - Crear/actualizar PaymentMethod local ``` --- ## Criterios de Aceptacion - [ ] Checkout con Stripe Elements funciona end-to-end - [ ] Suscripcion se crea correctamente tras pago - [ ] Upgrade inmediato con prorrateo funciona - [ ] Downgrade se programa para fin de periodo - [ ] Cancelacion permite uso hasta vencimiento - [ ] Facturas se sincronizan via webhooks - [ ] PDFs de facturas descargables - [ ] Sistema de creditos funciona correctamente - [ ] Compra de creditos extra funciona - [ ] Webhooks procesan todos los eventos clave - [ ] Notificaciones de pago se envian - [ ] Solo tenant_admin puede gestionar billing --- ## Consideraciones de Seguridad ```yaml Seguridad: - API keys de Stripe solo en backend (nunca en frontend) - Webhook signature verification obligatorio - PCI compliance delegado a Stripe (no almacenar tarjetas) - Audit log de todas las transacciones - Rate limiting en endpoints de billing - Validar que usuario pertenece al tenant ``` --- ## Referencias - [ARQUITECTURA-TECNICA.md](../00-vision-general/ARQUITECTURA-TECNICA.md) - [@CATALOG_PAYMENTS](../../../shared/catalog/payments/) - [PMC-001-TENANTS.md](./PMC-001-TENANTS.md) - [PMC-007-ADMIN.md](./PMC-007-ADMIN.md) - [Stripe Docs](https://stripe.com/docs) --- **Documento generado por:** Requirements-Analyst **Fecha:** 2026-01-04