platform-marketing-content/docs/97-adr/ADR-002-multi-tenancy.md

143 lines
3.3 KiB
Markdown

# ADR-002: Estrategia de Multi-Tenancy
**Fecha:** 2025-12-08
**Estado:** Aceptado
---
## Contexto
La plataforma debe soportar múltiples organizaciones (tenants) con:
1. Aislamiento completo de datos entre tenants
2. Configuración personalizable por tenant
3. Posibilidad de escalar a SaaS público
4. Costos operativos manejables
Opciones de multi-tenancy:
- **Database per tenant:** Una BD por cada tenant
- **Schema per tenant:** Un schema por tenant en misma BD
- **Shared schema:** Todos en mismas tablas con tenant_id
---
## Decisión
### Estrategia: Shared Schema con Row-Level Security (RLS)
Usaremos una sola base de datos con esquemas funcionales (auth, crm, projects, etc.) donde todas las tablas tienen columna `tenant_id` y políticas RLS que filtran automáticamente.
### Implementación
```sql
-- Columna tenant_id en todas las tablas principales
ALTER TABLE crm.clients ADD COLUMN tenant_id UUID NOT NULL;
-- Política RLS
CREATE POLICY tenant_isolation ON crm.clients
USING (tenant_id = current_setting('app.current_tenant')::uuid);
-- Habilitar RLS
ALTER TABLE crm.clients ENABLE ROW LEVEL SECURITY;
```
### Middleware de Tenant
```typescript
@Injectable()
export class TenantMiddleware implements NestMiddleware {
async use(req: Request, res: Response, next: NextFunction) {
const tenantId = this.extractTenantFromJwt(req);
// Set para la conexión actual
await this.dataSource.query(
`SET app.current_tenant = '${tenantId}'`
);
next();
}
}
```
### Storage Isolation
```
bucket/
├── {tenant_slug}/
│ ├── assets/
│ ├── models/
│ └── temp/
```
---
## Consecuencias
### Positivas
- **Un solo deployment:** Una instancia sirve a todos los tenants
- **Costos reducidos:** No hay overhead de múltiples BDs
- **Mantenimiento simple:** Migraciones se aplican una vez
- **RLS nativo:** PostgreSQL garantiza aislamiento a nivel de motor
- **Queries simples:** No hay JOINs entre BDs/schemas
- **Escalabilidad:** Read replicas y sharding posibles
### Negativas
- **Complejidad de RLS:** Requiere configurar políticas en cada tabla
- **Risk de bug:** Error en middleware podría filtrar datos incorrectos
- **Backups:** No hay backups por tenant (todo junto)
- **Noisy neighbors:** Un tenant pesado afecta a todos
### Mitigaciones
1. **Tests exhaustivos** de RLS en cada tabla
2. **Logs de auditoría** de todas las queries con tenant_id
3. **Rate limiting** por tenant
4. **Monitoring** de queries lentas por tenant
---
## Alternativas Consideradas
### 1. Database per Tenant
**Pros:**
- Aislamiento completo
- Backups individuales
- Fácil de escalar por tenant
**Contras:**
- Costos altos (una BD por cliente)
- Complejidad de deployment
- Migraciones en múltiples BDs
- Connection pooling complejo
**Rechazo:** Costos prohibitivos para MVP
### 2. Schema per Tenant
**Pros:**
- Buen aislamiento
- Una sola BD
- Backups parciales posibles
**Contras:**
- Migraciones en múltiples schemas
- Límite de schemas en PostgreSQL
- Complejidad de routing
**Rechazo:** Complejidad sin beneficio claro sobre RLS
---
## Referencias
- [PostgreSQL RLS Documentation](https://www.postgresql.org/docs/current/ddl-rowsecurity.html)
- [Multi-tenant SaaS patterns](https://docs.microsoft.com/en-us/azure/architecture/guide/multitenant/)
---
**Documento generado por:** Requirements-Analyst
**Fecha:** 2025-12-08