template-saas/docs/97-adr/adr/ADR-003-billing-stripe.md
Adrian Flores Cortes 806612a4db
Some checks are pending
CI / Backend CI (push) Waiting to run
CI / Frontend CI (push) Waiting to run
CI / Security Scan (push) Waiting to run
CI / CI Summary (push) Blocked by required conditions
[REESTRUCTURA-DOCS] refactor: Corregir estructura docs/ segun SIMCO-DOCUMENTACION-PROYECTO
- Renombrar 02-integraciones/ → 03-integraciones/ (resolver prefijo duplicado)
- Renombrar 02-devops/ → 04-devops/ (resolver prefijo duplicado)
- Renombrar architecture/ → 97-adr/ (agregar prefijo numerico)
- Actualizar _MAP.md con nueva estructura y version 2.1.0

Estructura final:
- 00-vision-general/
- 01-modulos/
- 02-especificaciones/
- 03-integraciones/
- 04-devops/
- 97-adr/

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 20:34:14 -06:00

215 lines
5.2 KiB
Markdown

---
id: "ADR-003"
title: "Billing Integration con Stripe"
type: "ADR"
status: "Accepted"
priority: "P0"
supersedes: "N/A"
superseded_by: "N/A"
version: "1.0.0"
created_date: "2026-01-07"
updated_date: "2026-01-10"
---
# ADR-003: Billing Integration con Stripe
## Metadata
| Campo | Valor |
|-------|-------|
| ID | ADR-003 |
| Estado | Accepted |
| Fecha | 2026-01-10 |
| Supersede | N/A |
## Contexto
Template SaaS necesita un sistema de billing para:
- Planes de suscripción (mensual/anual)
- Trial periods
- Múltiples métodos de pago
- Facturación automática
- Portal de autoservicio
- Webhooks para sincronización
## Opciones Consideradas
### Opción 1: Implementación Custom
**Descripción:** Sistema de billing propio conectado a pasarelas de pago.
**Pros:**
- Control total
- Sin comisiones de plataforma
- Personalización completa
**Contras:**
- Complejidad extrema (PCI compliance)
- Time-to-market largo
- Mantenimiento costoso
- Riesgos de seguridad
### Opción 2: Stripe ✓
**Descripción:** Plataforma de pagos completa con Billing.
**Pros:**
- Rápido de implementar
- PCI compliance incluido
- Múltiples países/monedas
- Portal de cliente built-in
- Webhooks robustos
- Excelente documentación
**Contras:**
- Comisiones (~2.9% + 30¢)
- Dependencia de tercero
- Algunas limitaciones en personalización
### Opción 3: Paddle/Lemonsqueezy
**Descripción:** Merchant of Record (MoR) completo.
**Pros:**
- Maneja impuestos automáticamente
- Sin necesidad de entidad legal por país
- Más simple que Stripe
**Contras:**
- Comisiones más altas (~5-8%)
- Menos control
- Menos features
## Decisión
**Elegimos Stripe** por:
1. **Balance:** Buen equilibrio entre control y simplicidad
2. **Features:** Billing, Invoicing, Customer Portal, Tax
3. **Ecosistema:** SDKs, webhooks, testing, documentación
4. **Escalabilidad:** Crece con el negocio
5. **Confiabilidad:** Uptime excelente, soporte 24/7
## Implementación
### Arquitectura
```
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Frontend │────▶│ Backend │────▶│ Stripe │
└─────────────┘ └─────────────┘ └─────────────┘
│ │
│◀───────────────────┘
│ Webhooks
┌──────▼──────┐
│ PostgreSQL │
└─────────────┘
```
### Modelos de Datos
```typescript
// Local (sincronizado con Stripe)
Subscription {
id: UUID
tenant_id: UUID
stripe_subscription_id: string
stripe_customer_id: string
plan_id: UUID
status: 'trialing' | 'active' | 'past_due' | 'cancelled'
current_period_start: Date
current_period_end: Date
}
Plan {
id: UUID
stripe_product_id: string
stripe_price_id_monthly: string
stripe_price_id_yearly: string
name: string
price_monthly: number
price_yearly: number
features: JSON
limits: JSON
}
```
### Flujo de Suscripción
```
1. Usuario selecciona plan
2. Backend crea Checkout Session
3. Redirect a Stripe Checkout
4. Usuario completa pago
5. Stripe envía webhook 'checkout.session.completed'
6. Backend crea/actualiza Subscription local
7. Redirect a success page
```
### Webhooks Críticos
| Evento | Acción |
|--------|--------|
| `checkout.session.completed` | Crear suscripción |
| `customer.subscription.updated` | Actualizar estado |
| `customer.subscription.deleted` | Marcar cancelada |
| `invoice.paid` | Registrar pago |
| `invoice.payment_failed` | Notificar, retry |
### Customer Portal
Stripe Customer Portal permite:
- Ver/descargar facturas
- Actualizar método de pago
- Cambiar plan
- Cancelar suscripción
```typescript
// Crear session del portal
const session = await stripe.billingPortal.sessions.create({
customer: tenant.stripe_customer_id,
return_url: 'https://app.example.com/billing',
});
```
### Plan Limits Enforcement
```typescript
// Verificar límite antes de acción
async canAddUser(tenantId: string): Promise<boolean> {
const subscription = await this.getSubscription(tenantId);
const plan = await this.getPlan(subscription.plan_id);
const currentUsers = await this.countUsers(tenantId);
return currentUsers < plan.limits.max_users;
}
```
## Consecuencias
### Positivas
- Time-to-market rápido
- Sin preocupaciones PCI
- Billing Portal listo para usar
- Webhooks confiables
- Soporte multi-moneda
### Negativas
- Comisiones por transacción
- Dependencia de Stripe
- Sincronización de datos necesaria
- Algunas features requieren Stripe Tax adicional
### Testing
- Stripe Test Mode para desarrollo
- Webhook testing con Stripe CLI
- Cards de prueba documentadas
## Referencias
- [Stripe Billing Docs](https://stripe.com/docs/billing)
- [Stripe Webhooks](https://stripe.com/docs/webhooks)
- [Test Cards](https://stripe.com/docs/testing)
- Implementación: `apps/backend/src/modules/billing/`
---
**Fecha decision:** 2026-01-10
**Autores:** Claude Code (Arquitectura)