Appearance
Arquitectura General - Portal PWA Multi-Tenant
Visión General
El Portal PWA de Clientes es un sistema multi-tenant por dominio donde cada empresa tiene su propio dominio web que identifica automáticamente al tenant, permitiendo a los clientes acceder a sus cuentas corrientes, consultar deudas y realizar pagos online.
Principios Arquitectónicos
1. Separación de Frontend y Backend
DECISIÓN CLAVE: Desarrollar frontend y backend de forma separada pero integrada.
Frontend PWA (Nuevo Proyecto)
- Ubicación: Repositorio independiente
- Tecnología: PWA con React
- Propósito: Aplicación optimizada para clientes (mobile-first, instalable, ligera)
- Independencia: Separada del ERP administrativo
- Despliegue: Build estático servido por servidor web
Backend API (Extensión del Servidor Existente)
- Ubicación: Servidor existente de Bautista (reutiliza infraestructura)
- Nuevos endpoints:
/portal/* - Reutilización: Modelos existentes (Cliente, CuentaCorriente, Servicios de recibos)
- Beneficio: No duplica lógica de negocio
2. Multi-Tenancy (Multi-Inquilino) por Dominio
Patrón: Una sola aplicación para todos los clientes. El dominio identifica al tenant (inquilino).
https://ctacte.empresaA.com.ar → Tenant: EmpresaA (DB: empresa_a, Schema: public)
https://portal.clubXYZ.com → Tenant: ClubXYZ (DB: club_xyz, Schema: public)
https://clientes.ferreteriaZ.ar → Tenant: FerreteriaZ (DB: ferreteria_z, Schema: public)Ventajas:
- ✅ Cada empresa tiene su propia identidad (dominio personalizado)
- ✅ Branding completamente personalizable
- ✅ Aislamiento de datos por tenant
- ✅ Escalabilidad: agregar tenants sin cambiar código
- ✅ Mantenimiento: una sola codebase
Diagrama de Arquitectura
┌─────────────────────────────────────────────────────────────┐
│ CLIENTE (Navegador/PWA) │
│ https://ctacte.empresaA.com.ar o https://portal.clubXYZ.com│
└────────────────────────┬────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ FRONTEND PWA (Proyecto Separado) │
│ - PWA con React │
│ - Cliente API HTTP │
│ - Instalable como app móvil │
│ - Build estático │
└────────────────────────┬────────────────────────────────────┘
│ Peticiones HTTP
▼
┌─────────────────────────────────────────────────────────────┐
│ BACKEND API (Servidor Existente) │
│ │
│ Middleware: Autenticación + Conexión multi-tenant │
│ Controllers: Auth, CtaCte, Pagos, Cupones │
│ Services: Identificación, Consultas, Pagos, Cupones │
│ Models: Nuevos (PortalClient, Payments, Cupones) │
│ + Reutilizados (Cliente, CuentaCorriente) │
└────────────────────────┬────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ POSTGRESQL MULTI-TENANT │
│ │
│ DB ini: Configuración global de tenants │
│ DB {tenant}: Datos del portal y clientes por tenant │
└─────────────────────────────────────────────────────────────┘Flujo de Datos
1. Resolución de Tenant
1. Cliente accede a un dominio (ej: ctacte.empresaA.com.ar)
↓
2. Middleware de autenticación extrae el dominio
↓
3. Busca en tabla tenant_domains para identificar el tenant
↓
4. Obtiene configuración: tenant_id, database, branding
↓
5. Middleware de conexión configura acceso a BD del tenant
↓
6. Request procede con contexto de tenant inyectado2. Autenticación de Cliente
1. Cliente ingresa DNI/CUIT
↓
2. POST /portal/auth/identify-client
↓
3. Servicio de identificación:
- Busca en portal_clients por DNI
- Si no existe, busca en tabla de clientes existente
- Crea registro en portal_clients si es primera vez
- Valida que no esté bloqueado
↓
4. Genera session o token con datos del cliente
↓
5. Frontend guarda credenciales
↓
6. Peticiones subsiguientes incluyen autenticación3. Consulta de Deudas
1. GET /portal/deudas?cliente_id=123
↓
2. Middleware verifica autenticación
↓
3. Controller de cuenta corriente recibe request
↓
4. Service de cuenta corriente:
- Usa modelo existente de CuentaCorriente
- Obtiene movimientos sin pago
- Enriquece con días de vencimiento
↓
5. Retorna JSON con deudas pendientes4. Pago Online
1. Cliente selecciona facturas → POST /portal/pagos/iniciar
↓
2. Servicio de pagos:
- Crea preferencia en gateway de pago
- Guarda registro con estado "pending"
↓
3. Frontend redirige al gateway de pago
↓
4. Cliente completa el pago en el gateway
↓
5. Gateway envía notificación al backend
↓
6. Servicio de pagos procesa webhook:
- Valida la notificación
- Verifica unicidad
- Si es aprobado: actualiza registro y genera recibo
↓
7. Cliente retorna a página de éxitoDecisiones Arquitectónicas
¿Por qué frontend separado?
| Aspecto | Frontend Separado | Frontend Integrado en /public/ |
|---|---|---|
| Optimización PWA | ✅ Optimizado específicamente para móviles | ❌ Comparte código con ERP admin |
| Tamaño de Bundle | ✅ Ligero (solo portal) | ❌ Pesado (incluye ERP) |
| Instalabilidad | ✅ PWA pura | ⚠️ Complejo |
| Mantenimiento | ✅ Código independiente | ❌ Acoplado al ERP |
| Despliegue | ✅ Build estático en Apache | ❌ Junto con ERP |
| Servidor | ✅ Sin Node.js en producción | ❌ Requiere infraestructura PHP |
¿Por qué reutilizar backend?
| Aspecto | Reutilizar /server/ | Backend Nuevo |
|---|---|---|
| Lógica de negocio | ✅ Reutiliza CuentaCorriente, Recibos | ❌ Duplica código |
| Mantenimiento | ✅ Una sola fuente de verdad | ❌ Sincronizar cambios |
| Multi-tenant | ✅ Ya implementado | ❌ Re-implementar |
| Testing | ✅ Tests existentes | ❌ Crear desde cero |
¿Por qué multi-tenant por dominio?
Alternativas evaluadas:
Subdominios:
empresaA.portal.bautista.com- ❌ Menos profesional
- ❌ Branding limitado
Parámetro en ruta:
portal.bautista.com/empresaA- ❌ SEO pobre
- ❌ URLs poco amigables
Dominio completo:
ctacte.empresaA.com.ar✅- ✅ Branding completo
- ✅ Identidad propia
- ✅ SSL por empresa
- ✅ Escalable
Ventajas del Diseño
- Escalabilidad: Agregar nuevos tenants sin cambiar código
- Mantenimiento: Una base de código para todos los clientes
- Reutilización: Aprovecha infraestructura existente (ConnectionManager, modelos, servicios)
- Seguridad: Aislamiento multi-tenant por schema
- Rendimiento: Frontend PWA optimizado, backend con pooling de conexiones
- Experiencia de Usuario: Instalable como app nativa, capacidad offline
- Branding: Completamente personalizable por empresa
Limitaciones y Compromisos (Trade-offs)
- Complejidad DNS: Requiere configurar dominio por tenant
- SSL Wildcard: Necesita certificado wildcard o certificados individuales
- Incorporación: Proceso de alta de tenant requiere configuración manual (mitigado con scripts CLI)
- Caché: Service Worker debe cachear por dominio
Próximos Pasos
- Revisar database/schema.md para modelo de datos
- Leer backend/README.md para implementación del backend
- Consultar frontend/README.md para PWA
- Ver roadmap/phase-1-mvp.md para comenzar implementación