- HERENCIA-SIMCO.md actualizado con directivas v3.7 y v3.8 - Actualizaciones de configuracion Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
201 lines
4.3 KiB
Markdown
201 lines
4.3 KiB
Markdown
---
|
|
id: "SAAS-002"
|
|
title: "Multi-Tenancy"
|
|
type: "Module"
|
|
status: "Published"
|
|
priority: "P0"
|
|
module: "tenants"
|
|
version: "1.0.0"
|
|
created_date: "2026-01-07"
|
|
updated_date: "2026-01-10"
|
|
---
|
|
|
|
# SAAS-002: Multi-Tenancy
|
|
|
|
## Metadata
|
|
- **Codigo:** SAAS-002
|
|
- **Modulo:** Tenants
|
|
- **Prioridad:** P0
|
|
- **Estado:** Completado
|
|
- **Fase:** 1 - Foundation
|
|
|
|
## Descripcion
|
|
|
|
Sistema de multi-tenancy con aislamiento completo de datos via Row-Level Security (RLS): creacion de tenants, configuracion por tenant, y contexto automatico en todas las operaciones.
|
|
|
|
## Objetivos
|
|
|
|
1. Aislamiento de datos por tenant
|
|
2. RLS en todas las tablas
|
|
3. Tenant context automatico
|
|
4. Configuracion por tenant
|
|
5. Subdominios/custom domains
|
|
|
|
## Alcance
|
|
|
|
### Incluido
|
|
- Creacion de tenant al registrar owner
|
|
- RLS policies en todas las tablas
|
|
- Tenant context via middleware
|
|
- tenant_id en JWT claims
|
|
- Configuraciones por tenant (JSONB)
|
|
- Slug unico por tenant
|
|
|
|
### Excluido
|
|
- Custom domains - fase posterior
|
|
- White-labeling completo
|
|
- Tenant isolation fisica (DB separadas)
|
|
|
|
## Modelo de Datos
|
|
|
|
### Tablas (schema: tenants)
|
|
|
|
**tenants**
|
|
- id, name, slug (unique)
|
|
- domain, logo_url, favicon_url
|
|
- settings (JSONB), status
|
|
- trial_ends_at, created_at
|
|
|
|
**tenant_settings**
|
|
- id, tenant_id, key, value
|
|
- created_at, updated_at
|
|
|
|
## Estrategia RLS
|
|
|
|
### Implementacion
|
|
```sql
|
|
-- Funcion de contexto
|
|
CREATE FUNCTION current_tenant_id() RETURNS UUID AS $$
|
|
SELECT current_setting('app.tenant_id', TRUE)::UUID;
|
|
$$ LANGUAGE SQL STABLE;
|
|
|
|
-- Policy generica
|
|
CREATE POLICY tenant_isolation ON table_name
|
|
USING (tenant_id = current_tenant_id());
|
|
```
|
|
|
|
### Middleware Backend
|
|
```typescript
|
|
// Set tenant context antes de queries
|
|
await db.query(`SELECT set_config('app.tenant_id', $1, true)`, [tenantId]);
|
|
```
|
|
|
|
## Endpoints API
|
|
|
|
| Metodo | Endpoint | Descripcion |
|
|
|--------|----------|-------------|
|
|
| GET | /tenants/current | Tenant actual (incluye settings) |
|
|
| PATCH | /tenants/current | Actualizar tenant (incluye settings) |
|
|
| GET | /tenants/:id | Obtener tenant por ID |
|
|
| POST | /tenants | Crear tenant |
|
|
|
|
### Configuraciones de Tenant
|
|
|
|
Las configuraciones se almacenan en el campo `settings` (JSONB) de la tabla tenants.
|
|
|
|
**Acceso via API:**
|
|
- GET `/tenants/current` - Retorna tenant con settings incluidos
|
|
- PATCH `/tenants/current` - Permite actualizar settings junto con otros campos
|
|
|
|
**Estructura del Campo Settings:**
|
|
```json
|
|
{
|
|
"branding": {
|
|
"logo_url": "https://...",
|
|
"primary_color": "#3B82F6"
|
|
},
|
|
"notifications": {
|
|
"email_enabled": true,
|
|
"push_enabled": false
|
|
},
|
|
"features": {
|
|
"ai_enabled": true,
|
|
"whatsapp_enabled": false
|
|
}
|
|
}
|
|
```
|
|
|
|
**Nota:** Los endpoints dedicados `/tenants/current/settings` y `/tenants/current/logo` estan planificados pero no implementados actualmente
|
|
|
|
## Flujos
|
|
|
|
### Creacion de Tenant
|
|
```
|
|
1. Usuario se registra como owner
|
|
2. Se crea usuario
|
|
3. Se crea tenant con slug unico
|
|
4. Se asocia usuario a tenant
|
|
5. Se aplican settings default
|
|
6. Se inicia trial
|
|
```
|
|
|
|
### Resolucion de Tenant
|
|
```
|
|
Request llega a API
|
|
│
|
|
├─► JWT contiene tenant_id?
|
|
│ └─► Si: usar ese tenant_id
|
|
│
|
|
├─► Header X-Tenant-ID?
|
|
│ └─► Si: validar y usar
|
|
│
|
|
└─► Subdominio?
|
|
└─► Si: buscar tenant por slug
|
|
```
|
|
|
|
## Configuraciones Default
|
|
|
|
```typescript
|
|
const DEFAULT_SETTINGS = {
|
|
timezone: 'America/Mexico_City',
|
|
locale: 'es-MX',
|
|
currency: 'MXN',
|
|
date_format: 'DD/MM/YYYY',
|
|
features: {
|
|
ai_enabled: false,
|
|
webhooks_enabled: false
|
|
},
|
|
limits: {
|
|
users: 5,
|
|
storage_mb: 1000
|
|
}
|
|
};
|
|
```
|
|
|
|
## Entregables
|
|
|
|
| Entregable | Estado | Archivo |
|
|
|------------|--------|---------|
|
|
| tenants.module.ts | Completado | `modules/tenants/` |
|
|
| tenant.middleware.ts | Completado | `middleware/` |
|
|
| DDL tenants schema | Completado | `ddl/schemas/tenants/` |
|
|
| RLS policies | Completado | En cada schema |
|
|
|
|
## Dependencias
|
|
|
|
### Depende de
|
|
- SAAS-001 (Auth)
|
|
|
|
### Bloquea a
|
|
- SAAS-003 (Users)
|
|
- Todos los modulos multi-tenant
|
|
|
|
## Criterios de Aceptacion
|
|
|
|
- [x] Tenant se crea automaticamente
|
|
- [x] RLS aisla datos correctamente
|
|
- [x] Contexto se setea automaticamente
|
|
- [x] Settings se guardan y recuperan
|
|
- [x] Slug es unico
|
|
|
|
## Seguridad
|
|
|
|
- RLS activo en todas las tablas (excepto plans)
|
|
- Tenant ID no modificable por usuario
|
|
- Validacion de pertenencia a tenant
|
|
- Logs de cambios en configuracion
|
|
|
|
---
|
|
|
|
**Ultima actualizacion:** 2026-01-10
|