268 lines
6.4 KiB
Markdown
268 lines
6.4 KiB
Markdown
# MODELO DE DOMINIO: Autenticación y Autorización
|
|
|
|
**Módulos:** MGN-001 (Fundamentos), MGN-002 (Empresas)
|
|
**Fecha:** 2025-11-24
|
|
**Referencia Odoo:** base, auth_signup
|
|
**Referencia Gamilit:** auth_management schema
|
|
|
|
---
|
|
|
|
## Diagrama de Entidades (Texto UML)
|
|
|
|
```
|
|
[Tenant]
|
|
- id: UUID (PK)
|
|
- name: String
|
|
- subdomain: String
|
|
- schema_name: String
|
|
- status: ENUM (active, suspended)
|
|
- settings: JSONB
|
|
|
|
1 <----> * [Company]
|
|
1 <----> * [User]
|
|
|
|
[Company]
|
|
- id: UUID (PK)
|
|
- tenant_id: UUID (FK)
|
|
- name: String
|
|
- tax_id: String
|
|
- currency_id: UUID (FK)
|
|
- settings: JSONB
|
|
|
|
1 <----> * [User]
|
|
|
|
[User]
|
|
- id: UUID (PK)
|
|
- tenant_id: UUID (FK)
|
|
- email: String (UNIQUE per tenant)
|
|
- password_hash: String
|
|
- full_name: String
|
|
- status: ENUM (active, inactive, suspended)
|
|
- is_superuser: Boolean
|
|
|
|
* <----> * [Role] (through UserRole)
|
|
1 <----> * [Session]
|
|
|
|
[Role]
|
|
- id: UUID (PK)
|
|
- tenant_id: UUID (FK)
|
|
- name: String
|
|
- code: String
|
|
- description: Text
|
|
|
|
* <----> * [Permission] (through RolePermission)
|
|
|
|
[Permission]
|
|
- id: UUID (PK)
|
|
- resource: String (ej: 'purchase_orders')
|
|
- action: ENUM (create, read, update, delete, approve)
|
|
- description: Text
|
|
|
|
[Session]
|
|
- id: UUID (PK)
|
|
- user_id: UUID (FK)
|
|
- token: String
|
|
- expires_at: Timestamp
|
|
- ip_address: String
|
|
- user_agent: String
|
|
|
|
[UserRole] (many-to-many)
|
|
- user_id: UUID (FK)
|
|
- role_id: UUID (FK)
|
|
|
|
[RolePermission] (many-to-many)
|
|
- role_id: UUID (FK)
|
|
- permission_id: UUID (FK)
|
|
```
|
|
|
|
## Entidades Principales
|
|
|
|
### 1. Tenant (Multi-Tenancy)
|
|
**Descripción:** Representa un tenant (empresa matriz o grupo). Cada tenant tiene su propio schema PostgreSQL.
|
|
|
|
**Atributos:**
|
|
- `id`: Identificador único
|
|
- `name`: Nombre del tenant
|
|
- `subdomain`: Subdominio (ej: 'acme' → acme.erp.com)
|
|
- `schema_name`: Nombre del schema PostgreSQL (ej: 'tenant_acme')
|
|
- `status`: Estado (active, suspended)
|
|
- `settings`: Configuración JSON (logo, tema, etc.)
|
|
|
|
**Relaciones:**
|
|
- 1 Tenant → N Companies
|
|
- 1 Tenant → N Users
|
|
|
|
**Patrón Odoo:** Similar a res.company pero en un nivel superior
|
|
**Patrón Gamilit:** Implementado con schema-level isolation
|
|
|
|
**RLS Policy:**
|
|
```sql
|
|
-- Usuarios solo ven su tenant
|
|
CREATE POLICY tenant_isolation ON tenants
|
|
USING (id = get_current_tenant_id());
|
|
```
|
|
|
|
### 2. Company (Empresa)
|
|
**Descripción:** Empresa dentro de un tenant. Permite multi-empresa.
|
|
|
|
**Atributos:**
|
|
- `id`: UUID
|
|
- `tenant_id`: Tenant propietario
|
|
- `name`: Nombre empresa
|
|
- `tax_id`: RFC/Tax ID
|
|
- `currency_id`: Moneda por defecto
|
|
- `settings`: JSONB (dirección, contacto, etc.)
|
|
|
|
**Relaciones:**
|
|
- N Companies → 1 Tenant
|
|
- 1 Company → N Users (usuarios pueden estar en múltiples empresas)
|
|
|
|
**Patrón Odoo:** res.company
|
|
**Validaciones:**
|
|
- Un tenant debe tener al menos 1 company
|
|
- tax_id único por tenant
|
|
|
|
### 3. User (Usuario)
|
|
**Descripción:** Usuario del sistema con roles y permisos.
|
|
|
|
**Atributos:**
|
|
- `id`: UUID
|
|
- `tenant_id`: Tenant propietario
|
|
- `email`: Email (único por tenant)
|
|
- `password_hash`: bcrypt hash
|
|
- `full_name`: Nombre completo
|
|
- `status`: active, inactive, suspended
|
|
- `is_superuser`: Admin total del tenant
|
|
|
|
**Relaciones:**
|
|
- N Users → 1 Tenant
|
|
- N Users ←→ N Roles (many-to-many)
|
|
- 1 User → N Sessions
|
|
|
|
**Patrón Odoo:** res.users
|
|
**Patrón Gamilit:** auth.users con tenant_id
|
|
|
|
**Validaciones:**
|
|
- email único por tenant (no global)
|
|
- password mínimo 8 caracteres
|
|
- is_superuser requiere aprobación
|
|
|
|
**RLS Policy:**
|
|
```sql
|
|
CREATE POLICY users_own_tenant ON users
|
|
USING (tenant_id = get_current_tenant_id());
|
|
```
|
|
|
|
### 4. Role (Rol)
|
|
**Descripción:** Rol con permisos asignados (RBAC).
|
|
|
|
**Atributos:**
|
|
- `id`: UUID
|
|
- `tenant_id`: Tenant propietario
|
|
- `name`: Nombre del rol
|
|
- `code`: Código único (ej: 'admin', 'buyer')
|
|
- `description`: Descripción
|
|
|
|
**Relaciones:**
|
|
- N Roles → 1 Tenant
|
|
- N Roles ←→ N Permissions
|
|
|
|
**Patrón Odoo:** res.groups
|
|
**Roles predefinidos:**
|
|
- `admin`: Administrador del tenant
|
|
- `manager`: Gerente (full access transaccional)
|
|
- `user`: Usuario normal
|
|
- `readonly`: Solo lectura
|
|
|
|
### 5. Permission (Permiso)
|
|
**Descripción:** Permiso granular sobre recursos.
|
|
|
|
**Atributos:**
|
|
- `id`: UUID
|
|
- `resource`: Recurso (tabla/endpoint) (ej: 'purchase_orders')
|
|
- `action`: create, read, update, delete, approve, cancel
|
|
|
|
**Ejemplo de permisos:**
|
|
```
|
|
Resource: purchase_orders
|
|
Actions: create, read, update, delete, approve
|
|
```
|
|
|
|
**Patrón Odoo:** ir.model.access + ir.rule
|
|
**Implementación:** Validado en backend + RLS policies en BD
|
|
|
|
### 6. Session (Sesión)
|
|
**Descripción:** Sesión JWT de usuario.
|
|
|
|
**Atributos:**
|
|
- `id`: UUID
|
|
- `user_id`: Usuario propietario
|
|
- `token`: JWT token
|
|
- `expires_at`: Expiración
|
|
- `ip_address`: IP de origen
|
|
- `user_agent`: Navegador
|
|
|
|
**Patrón Gamilit:** auth.sessions
|
|
|
|
## Reglas de Negocio
|
|
|
|
### RN-AUTH-001: Multi-Tenancy Obligatorio
|
|
- TODO usuario pertenece a exactamente 1 tenant
|
|
- TODO dato transaccional tiene tenant_id
|
|
- Aislamiento completo entre tenants (schema-level)
|
|
|
|
### RN-AUTH-002: RBAC Granular
|
|
- Usuario puede tener múltiples roles
|
|
- Permisos se calculan como UNION de permisos de roles
|
|
- is_superuser bypassa todos los checks
|
|
|
|
### RN-AUTH-003: Sesiones JWT
|
|
- Expiración: 8 horas
|
|
- Refresh token: 30 días
|
|
- Invalidación: Logout o expiración
|
|
|
|
### RN-AUTH-004: Passwords Seguros
|
|
- Mínimo 8 caracteres
|
|
- Debe incluir: mayúscula, minúscula, número
|
|
- bcrypt hash (cost factor 12)
|
|
|
|
## Casos de Uso Principales
|
|
|
|
1. **UC-AUTH-001:** Login de usuario
|
|
2. **UC-AUTH-002:** Registro de nuevo tenant
|
|
3. **UC-AUTH-003:** Asignar rol a usuario
|
|
4. **UC-AUTH-004:** Validar permisos para acción
|
|
5. **UC-AUTH-005:** Reset password
|
|
6. **UC-AUTH-006:** Cambiar de empresa (multi-company)
|
|
|
|
## Validaciones y Constraints
|
|
|
|
```sql
|
|
-- Email único por tenant
|
|
UNIQUE (tenant_id, email)
|
|
|
|
-- Status válidos
|
|
CHECK (status IN ('active', 'inactive', 'suspended'))
|
|
|
|
-- Al menos 1 admin por tenant
|
|
-- (trigger custom)
|
|
|
|
-- Session expiration
|
|
CHECK (expires_at > created_at)
|
|
```
|
|
|
|
## Índices Requeridos
|
|
|
|
```sql
|
|
CREATE INDEX idx_users_tenant_id ON auth.users(tenant_id);
|
|
CREATE INDEX idx_users_email ON auth.users(email);
|
|
CREATE INDEX idx_sessions_user_id ON auth.sessions(user_id);
|
|
CREATE INDEX idx_sessions_token ON auth.sessions(token);
|
|
CREATE INDEX idx_user_roles_user_id ON auth.user_roles(user_id);
|
|
```
|
|
|
|
## Referencias
|
|
- [ALCANCE-POR-MODULO.md - MGN-001](../../01-definicion-modulos/ALCANCE-POR-MODULO.md#mgn-001)
|
|
- [odoo-base-analysis.md](../../00-analisis-referencias/odoo/odoo-base-analysis.md)
|
|
- [ADR-006: RBAC](../../adr/ADR-006-rbac-sistema-permisos.md)
|