# 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)
