# Arquitectura de SLM Framework

Este documento describe la arquitectura y patrones de diseño utilizados en SLM Framework.

## Descripción General

SLM Framework es un framework PHP ligero diseñado alrededor de Elasticsearch como almacén de datos principal. Utiliza una extensión de archivo personalizada (`.slm`) para plantillas PHP y sigue un patrón similar a MVC.

## Componentes Principales

### 1. Punto de Entrada (`public/index.slm`)

Todas las peticiones HTTP se enrutan a través del punto de entrada, que:

1. Carga la configuración y funciones auxiliares
2. Inicializa el gestor de sesiones
3. Maneja la autenticación
4. Enruta las peticiones a los módulos apropiados
5. Guarda la sesión al completar

```
┌─────────────────────────────────────────────────────────────┐
│                       index.slm                              │
├─────────────────────────────────────────────────────────────┤
│  1. Cargar config.slm (variables de entorno)                 │
│  2. Cargar helpers.slm (funciones de utilidad)               │
│  3. Cargar _SLM.slm (clase de sesión)                       │
│  4. Cargar slm_api.slm (funciones API core)                 │
│  5. Inicializar sesión desde Elasticsearch                   │
│  6. Enrutar petición basada en estado de autenticación       │
│  7. Guardar sesión en Elasticsearch                          │
└─────────────────────────────────────────────────────────────┘
```

### 2. Gestor de Sesiones (Clase `_SLM`)

La clase `_SLM` gestiona todas las operaciones de sesión:

```php
class _SLM {
    public static array $session;      // Datos de sesión actuales
    public static ?string $appToken;   // Identificador de sesión (cookie)

    // Métodos principales
    public static function loadSession(): void;        // Cargar desde ES (incluye ACL de usuario)
    public static function saveSession(): void;        // Guardar en ES
    public static function auth(): bool;               // Verificar si está autenticado
    public static function logout(): void;             // Destruir sesión
    public static function getUserACL(): ?array;       // Obtener permisos fusionados
    private static function mergeACLs(): array;        // Fusionar ACL de perfil + usuario
}
```

#### Proceso de Carga de Sesión

Cuando se llama a `loadSession()`:

1. Carga la sesión desde Elasticsearch
2. Obtiene el perfil del usuario y el ACL del perfil
3. **NUEVO:** Carga el ACL específico del usuario si existe (campo `user.acl`)
4. Almacena ambos en la sesión:
   - `$session["user"]["profile"]["acl"]` - ACL del Perfil
   - `$session["user"]["user_acl"]` - ACL Específico del Usuario

Los datos de sesión se almacenan en el índice `sessions` de Elasticsearch:

```json
{
  "timestamp": 1704067200000,
  "human_date": "2024-01-01 00:00:00",
  "session": "{\"user\": {...}}",
  "user_id": "user123",
  "app": "SLM",
  "environment": "dev"
}
```

#### Fusión de ACL

Cuando se llama a `getUserACL()`, fusiona los ACLs de perfil y usuario:

```php
public static function getUserACL(): ?array
{
    $profileACL = $_SESSION["user"]["profile"]["acl"] ?? null;
    $userACL = $_SESSION["user"]["user_acl"] ?? null;

    if ($userACL === null) return $profileACL;
    if ($profileACL === null) return $userACL;

    return self::mergeACLs($profileACL, $userACL);
}
```

### 3. Flujo de Peticiones

```
┌──────────────────┐
│  Petición HTTP   │
└────────┬─────────┘
         │
         ▼
┌──────────────────┐
│   index.slm      │
│  (Punto Entrada) │
└────────┬─────────┘
         │
         ▼
┌──────────────────┐
│  Cargar Sesión   │
│   (clase _SLM)   │
└────────┬─────────┘
         │
    ¿Autenticado?
         │
    ┌────┴────┐
   NO        SÍ
    │         │
    ▼         ▼
┌───────┐  ┌─────────────────────┐
│ login │  │  Analizar params    │
│ .slm  │  │  ?v=modulo.accion   │
└───────┘  │  ?a=modulo.accion   │
           └──────────┬──────────┘
                      │
              ┌───────┴───────┐
              │               │
        ?v= (Vista)     ?a= (AJAX)
              │               │
              ▼               ▼
        ┌───────────┐   ┌───────────┐
        │ proc.slm  │   │ slm_api   │
        │ load.slm  │   │ ajax.slm  │
        │ view.slm  │   └─────┬─────┘
        │ end.slm   │         │
        └─────┬─────┘         ▼
              │          ┌─────────┐
              ▼          │  JSON   │
        ┌─────────┐      │Respuesta│
        │  HTML   │      └─────────┘
        │Respuesta│
        └─────────┘
```

### 4. Estructura de Módulos

Cada módulo puede contener estos archivos:

| Archivo | Propósito | Cuándo se Carga |
|---------|-----------|-----------------|
| `slm_api.slm` | Funciones específicas del módulo | Primero |
| `proc.{accion}.slm` | Pre-procesamiento, validación | Antes de load |
| `load.{accion}.slm` | Cargar datos desde ES | Antes de view |
| `view.{accion}.slm` | Plantilla HTML | Contenido principal |
| `end.{accion}.slm` | Código JavaScript | Después de view |
| `ajax.{accion}.slm` | Manejadores de peticiones AJAX | Para peticiones ?a= |

### 5. Integración con Elasticsearch

Todas las operaciones de datos usan Elasticsearch:

```
┌─────────────────────────────────────────────────────────────┐
│                    Elasticsearch                             │
├──────────────────┬──────────────────┬──────────────────────┤
│   slm-app        │   slm-app-log    │   sessions           │
│   (Datos Princ)  │   (Logs)         │   (Sesiones)         │
├──────────────────┼──────────────────┼──────────────────────┤
│ - usuarios       │ - logs de error  │ - sesiones activas   │
│ - perfiles       │ - logs de éxito  │ - datos de sesión    │
│ - items          │ - logs warning   │                      │
│ - (docs custom)  │                  │                      │
└──────────────────┴──────────────────┴──────────────────────┘
```

Estructura de documento:

```json
{
  "name": "Item de Ejemplo",
  "status": "active",
  "slm": {
    "type": "item",
    "timestamp": 1704067200000,
    "created_by": "user123"
  }
}
```

### 6. Flujo de Autenticación

```
┌─────────────┐    ┌─────────────┐    ┌─────────────┐
│   Login     │───▶│  Validar    │───▶│  Generar    │
│ Formulario  │    │   Email     │    │   Token     │
└─────────────┘    └─────────────┘    └──────┬──────┘
                                             │
                                             ▼
┌─────────────┐    ┌─────────────┐    ┌─────────────┐
│  Completar  │◀───│  Validar    │◀───│Enviar Email │
│   Login     │    │   Token     │    │   (Token)   │
└─────────────┘    └─────────────┘    └─────────────┘
```

1. Usuario ingresa email
2. Sistema valida que el usuario existe y está activo
3. Token de 6 dígitos generado (válido 10 minutos)
4. Token enviado por email
5. Usuario ingresa token
6. Sesión creada con datos del usuario

### 7. Control de Acceso (ACL) - Sistema de Permisos de Dos Niveles

SLM Framework implementa un poderoso sistema de permisos de dos niveles:

#### Nivel 1: Permisos Basados en Perfil (Base)

Los permisos se almacenan por perfil:

```json
{
  "slm": { "type": "profile" },
  "name": "Admin",
  "acl": {
    "GROUP_1": {
      "home.main": ["read"],
      "config.users": ["read", "create", "update", "delete"]
    },
    "GROUP_2": {
      "example.items": ["read", "create", "update", "delete"]
    }
  }
}
```

#### Nivel 2: Permisos Específicos de Usuario (Override)

Los usuarios pueden tener permisos personalizados que sobrescriben su perfil:

```json
{
  "slm": { "type": "user" },
  "name": "Juan Pérez",
  "email": "juan@example.com",
  "profile": "PROFILE_ID",
  "acl": {
    "GROUP_1": {
      "config.users": ["read"],           // ← Override: solo lectura
      "reports.advanced": ["read"]        // ← Adicional: módulo nuevo
    }
  }
}
```

#### Estrategia de Fusión

Cuando se llama a `_SLM::getUserACL()`:

1. Carga el ACL del perfil (permisos base)
2. Carga el ACL del usuario (si existe)
3. Fusiona usando estas reglas:
   - **Override**: Los permisos de usuario reemplazan los permisos del perfil por módulo
   - **Revocación**: Array vacío `[]` elimina acceso al módulo
   - **Adicional**: Usuario puede acceder a módulos que no están en el perfil
   - **Herencia**: Módulos no definidos en ACL de usuario heredan del perfil

```php
// ACL del Perfil
["GROUP_1" => ["config.users" => ["read", "create", "update", "delete"]]]

// ACL del Usuario
["GROUP_1" => ["config.users" => ["read"]]]

// Resultado (después de fusionar)
["GROUP_1" => ["config.users" => ["read"]]]  // ← Override aplicado
```

#### Verificación de Permisos

```php
$permissions = _SLM::getSecurityAccess('example.items');
// Retorna permisos fusionados: ['read', 'create', 'update', 'delete']

if (in_array('delete', $permissions)) {
    // Usuario puede eliminar (ya sea del perfil o del ACL específico)
}
```

#### Módulos de Configuración Core

El perfil **SLM Super** proporciona acceso a los módulos de configuración:

- **config.users**: Gestión de usuarios y permisos específicos de usuario
- **config.profile**: Gestión de perfiles y ACL
- **config.modules**: Registro de módulos

Estos módulos son esenciales para la configuración del sistema y solo deben ser accesibles para administradores.

### 8. Formato de Respuesta

Todas las respuestas AJAX siguen este formato:

```json
{
  "error": false,
  "message": "Mensaje de éxito",
  "data": { ... }
}
```

Para DataTables:

```json
{
  "draw": 1,
  "recordsTotal": 100,
  "recordsFiltered": 50,
  "data": [...]
}
```

### 9. Patrón de Manejo de Errores

```php
function myFunction(): void
{
    $response = _response(true);  // Iniciar con estado de error
    $log_type = 'error';
    $log_data = [];

    try {
        // Validar
        validateRequiredFields(['name', 'email']);

        // Procesar
        $result = doSomething();

        // Éxito
        $response = _response(false, 'Éxito');
        $log_type = 'success';

    } catch (Exception $e) {
        $response['message'] = $e->getMessage();
    } finally {
        $log_data['return'] = $response;
        addToLog($log_type, 'module', __FUNCTION__, $log_data);
    }

    exit(json_encode($response));
}
```

### 10. Convenciones de Nomenclatura de Archivos

| Tipo | Patrón | Ejemplo |
|------|---------|---------|
| Archivos de vista | `view.{accion}.slm` | `view.users.slm` |
| Archivos AJAX | `ajax.{accion}.slm` | `ajax.users.slm` |
| Archivos de carga | `load.{accion}.slm` | `load.users.slm` |
| Archivos de proceso | `proc.{accion}.slm` | `proc.users.slm` |
| Archivos finales | `end.{accion}.slm` | `end.users.slm` |
| Archivos del sistema | `{nombre}.slm` | `config.slm` |
| Archivos de librería | `{NombreClase}.slm` | `Curl.slm` |

## Patrones de Diseño

### Patrón Repository (Operaciones ES)

```php
// Crear
setNewObject($data);

// Leer
getObjectById($id);
getObjectWithValue($type, $field, $value);

// Actualizar
updateObjectByID($id, $data);

// Eliminar (suave)
updateObjectByID($id, ['status' => 'inactive']);
```

### Patrón Factory (Mailer)

```php
function createMailer(): PHPMailer {
    $mail = new PHPMailer();
    // Configurar...
    return $mail;
}
```

### Patrón Singleton (Session)

```php
class _SLM {
    public static array $session = [];
    // Todos los métodos son estáticos, instancia única
}
```

## Consideraciones de Seguridad

1. **Autenticación**: Dos factores con token por email
2. **Almacenamiento de Sesión**: Encriptado en Elasticsearch
3. **ACL**: Verificación de permisos en cada petición
4. **Validación de Entrada**: Funciones auxiliares para sanitización
5. **Prevención XSS**: Escape de salida en plantillas
6. **CSRF**: Protección basada en tokens (recomendado)

## Optimizaciones de Rendimiento

1. **Caché de Sesión**: Solo guardar si cambió
2. **Optimización de Consultas ES**: Usar campos keyword para coincidencias exactas
3. **SSP para DataTables**: Procesamiento del lado del servidor
4. **Assets CDN**: Librerías externas desde CDN
