# Manual Funcional - Tresipunt Manager

Este manual está dirigido a usuarios operativos y perfiles funcionales que necesitan operar el sistema de gestión de licencias. Incluye pasos detallados, requisitos de permisos, validaciones y ejemplos prácticos.

## Índice

1. [Usuarios](#1-usuarios)
2. [Roles y Permisos](#2-roles-y-permisos)
3. [Sitios (Environments)](#3-sitios-environments)
4. [Productos](#4-productos)
5. [Tokens / Licencias](#5-tokens--licencias)
6. [Gestión de Contenido](#6-gestión-de-contenido)
7. [Setups](#7-setups)

---

## 1. Usuarios

### 1.1. Crear Usuario

**Permiso requerido**: `admin.users.create` (solo rol Admin)

**Pasos**:
1. Acceder al menú **Usuarios** → **Crear**
2. Completar el formulario:
   - **Nombre** (obligatorio): Nombre completo del usuario
   - **Email** (obligatorio): Email único en el sistema
   - **Contraseña** (obligatorio): Mínimo 8 caracteres
   - **Confirmar contraseña** (obligatorio): Debe coincidir con la contraseña
   - **Rol** (obligatorio): Seleccionar un rol existente (Admin, Manager, Developer, Support, System, WebService)
3. Hacer clic en **Guardar**

**Validaciones**:
- Email debe ser único en el sistema
- Contraseña mínimo 8 caracteres
- El rol debe existir en la base de datos
- Todos los campos obligatorios deben estar completos

**Ejemplo de error común**:
- "El email ya está en uso" → El email ya existe, usar otro o editar el usuario existente

### 1.2. Editar Usuario

**Permiso requerido**: `admin.users.edit` (solo rol Admin)

**Restricciones importantes**:
- **No puedes editar un usuario Admin si tú no eres Admin**
- Si intentas editar un Admin sin ser Admin, verás el mensaje: "Este usuario no se puede editar"

**Pasos**:
1. Acceder al listado de usuarios
2. Hacer clic en **Editar** sobre el usuario deseado
3. Modificar los campos necesarios:
   - **Nombre**: Editable
   - **Email**: Editable (debe ser único)
   - **Contraseña**: Opcional (solo si quieres cambiarla)
   - **Rol**: Editable
4. Hacer clic en **Guardar**

**Nota**: Si no introduces una nueva contraseña, se mantendrá la actual.

### 1.3. Desactivar / Eliminar Usuario

**Permiso requerido**: `admin.users.destroy` (solo rol Admin)

**Restricciones**:
- **Los usuarios con rol Admin NO se pueden eliminar**
- Si intentas eliminar un Admin, verás: "Este usuario no se puede borrar porque es un administrador"

**Pasos para eliminar**:
1. Acceder al listado de usuarios
2. Hacer clic en **Editar** sobre el usuario
3. Hacer clic en el botón **Eliminar**
4. Confirmar la eliminación

**Nota**: La eliminación es "soft delete", el usuario se marca como eliminado pero no se borra físicamente de la base de datos.

### 1.4. Reset de Contraseña

#### Opción 1: Desde el perfil del usuario

Si el usuario está logueado, puede cambiar su contraseña desde su perfil:
1. Acceder a **Perfil** (menú superior)
2. Ir a la sección **Cambiar contraseña**
3. Introducir contraseña actual
4. Introducir nueva contraseña (mínimo 8 caracteres)
5. Confirmar nueva contraseña
6. Guardar

#### Opción 2: Recuperación de contraseña (Olvidé mi contraseña)

Si el usuario olvidó su contraseña:
1. En la pantalla de login, hacer clic en **¿Olvidaste tu contraseña?**
2. Introducir el email del usuario
3. Hacer clic en **Enviar enlace de recuperación**
4. Revisar el email (si está configurado el servicio de correo)
5. Hacer clic en el enlace recibido
6. Introducir nueva contraseña
7. Confirmar nueva contraseña
8. Guardar

**Nota**: Para que el envío de emails funcione, debe estar configurado correctamente el servicio de correo en `.env` (MAIL_*).

**Errores comunes**:
- "No podemos encontrar un usuario con ese email" → El email no existe en el sistema
- El email no llega → Verificar configuración de MAIL_* en `.env` o usar la opción de cambio desde perfil (si el usuario tiene acceso)

---

## 2. Roles y Permisos

### 2.1. Gestión de Roles

**Permiso requerido**: 
- Ver listado: `admin.roles.index` (solo Admin)
- Crear: `admin.roles.create` (solo Admin)
- Editar: `admin.roles.edit` (solo Admin)
- Eliminar: `admin.roles.destroy` (solo Admin)

**Acceso**: Configuraciones → Roles

**Crear un nuevo rol**:
1. Acceder a **Configuraciones** → **Roles**
2. Hacer clic en **Crear**
3. Completar campos:
   - **Nombre** (obligatorio): Nombre técnico del rol (ej: "ContentManager")
   - **Nombre completo** (obligatorio): Nombre legible (ej: "Gestor de Contenido")
   - **Descripción** (opcional): Descripción del rol
4. Guardar

**Editar un rol**:
1. Acceder al listado de roles
2. Hacer clic en **Editar** sobre el rol
3. Modificar campos
4. Guardar

**Vincular permisos a roles**:
1. Editar el rol
2. En la sección de permisos, seleccionar los permisos que deseas asignar
3. Guardar

### 2.2. Vincular Roles a Usuarios

Los roles se vinculan a usuarios durante la creación o edición del usuario:

1. Al crear/editar un usuario, seleccionar el **Rol** deseado
2. Un usuario puede tener múltiples roles (aunque en la interfaz actual solo se muestra uno)
3. Guardar

**Nota**: El sistema usa Spatie Laravel Permission, que permite múltiples roles por usuario, aunque la interfaz actual muestra solo uno.

### 2.3. Matriz de Permisos

Esta tabla muestra qué roles pueden realizar qué acciones en el sistema:

| Módulo | Acción | Admin | Manager | Developer | Support | System | WebService |
|--------|--------|-------|---------|-----------|---------|--------|------------|
| **Dashboard** | Ver panel | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| **Usuarios** | Ver/Editar/Crear/Eliminar | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| **Roles** | Ver/Editar/Crear/Eliminar | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| **Permisos** | Ver/Editar/Crear/Eliminar | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| **Entornos** | Ver listado | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ |
| **Entornos** | Crear/Editar/Eliminar | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| **Clientes** | Ver/Editar/Crear/Eliminar | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| **Productos** | Ver/Editar/Crear/Eliminar | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
| **Setups** | Ver/Editar/Crear | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
| **Features** | Ver/Editar/Crear/Eliminar | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
| **Tutoriales** | Ver/Editar/Crear/Eliminar | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
| **Recursos** | Ver/Editar/Crear/Eliminar | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
| **SCSS** | Ver/Editar/Crear | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
| **JS** | Ver/Editar/Crear | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
| **SCSS CDN** | Ver/Editar/Crear | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
| **License Tokens** | Ver/Editar/Crear | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
| **License Tokens** | Eliminar | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| **Configuraciones** | Tipos de entornos | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ |
| **Configuraciones** | Productos | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ |
| **API** | Acceso vía token | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ |
| **API** | Listar tipos | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ |

**Nota**: El rol Admin tiene automáticamente TODOS los permisos del sistema, incluso los que se creen después.

---

## 3. Sitios (Environments)

Los "sitios" o "entornos" representan instancias de Moodle u otras plataformas que consumen los productos del Manager.

### 3.1. Crear Sitio

**Permiso requerido**: `admin.environments.create` (solo Admin)

**Pasos**:
1. Acceder a **Entornos** → **Crear**
2. Completar el formulario:
   - **Nombre** (obligatorio): Nombre descriptivo del entorno (ej: "Moodle Producción Cliente X")
   - **Dominio** (obligatorio, único): URL completa del sitio (ej: "https://moodle.cliente.com")
   - **Descripción** (opcional): Descripción del entorno
   - **Versión** (obligatorio): Versión técnica de Moodle (ej: "2025081101")
   - **Entorno** (obligatorio): Seleccionar entre:
     - `local`: Desarrollo local
     - `develop`: Desarrollo
     - `pre`: Pre-producción
     - `pro`: Producción
   - **Cliente** (opcional): Asociar a un cliente existente
   - **Tipo** (opcional): Tipo de plataforma (Moodle, Workplace, etc.)
   - **Activo**: Checkbox para activar/desactivar
3. Hacer clic en **Guardar**

**Validaciones**:
- El dominio debe ser único en el sistema
- La versión debe tener formato válido
- El entorno debe ser uno de los valores permitidos

**Ejemplo de error común**:
- "El dominio ya está en uso" → El dominio ya existe, usar otro o editar el existente

### 3.2. Vincular Sitio con Productos / Licencias

Los sitios se vinculan a productos a través de los **License Tokens**:

**Flujo completo**:
1. Crear o editar un **License Token** (ver sección 5)
2. En el paso 2 del wizard, seleccionar los entornos que usarán este token
3. En el paso 3, seleccionar los productos que estarán disponibles para estos entornos
4. Al guardar, el token queda vinculado a los entornos y productos seleccionados

**Gestionar entornos de un token existente**:
1. Acceder a **License Tokens** → Seleccionar un token → **Gestionar Entornos**
2. Agregar o quitar entornos asociados al token
3. Guardar

**Nota**: Un entorno solo puede estar asociado a un token a la vez. Si asignas un entorno a un nuevo token, se desasocia del anterior.

### 3.3. Estados del Sitio y Flujo Esperado

**Estados**:
- **Activo** (`active = true`): El entorno está operativo y puede recibir peticiones de la API
- **Inactivo** (`active = false`): El entorno está deshabilitado, las peticiones de la API fallarán

**Flujo esperado**:
1. **Creación manual**: Un administrador crea el entorno desde la interfaz
2. **Registro inicial**: El plugin de Moodle hace una petición `sync` a la API con información del sitio
3. **Sincronización**: El Manager actualiza automáticamente la versión y otros datos del entorno
4. **Uso**: El entorno consume productos, configuraciones, archivos, etc. a través de la API

**Sincronización automática**:
- Cuando un entorno hace una petición `sync` a la API, el Manager actualiza:
  - Versión de Moodle
  - Release
  - Last version / Last minor
  - Token de Moodle (opcional)
  - Tipo de entorno
  - Fecha de última sincronización (`refresh_at`)

**Importante**: Los sitios NO se crean automáticamente desde la API. Deben existir previamente en el Manager. La acción `sync` solo actualiza información de sitios existentes.

---

## 4. Productos

Los productos representan plugins o temas de Moodle que se gestionan a través del Manager.

### 4.1. Crear / Editar Producto

**Permisos requeridos**:
- Crear: `admin.products.create` (Admin, Manager, Developer)
- Editar: `admin.products.edit` (Admin, Manager, Developer)
- Ver: `admin.products.show` (Admin, Manager, Developer)

**Pasos para crear**:
1. Acceder a **Productos** → **Crear**
2. Completar el formulario:
   - **Slug** (obligatorio, único): Identificador técnico único (ej: "theme_fresk", "block_tresipuntsepe")
   - **Nombre** (obligatorio): Nombre del producto (ej: "Tema Fresk")
   - **Resumen** (obligatorio): Resumen breve del producto
   - **Descripción** (opcional): Descripción detallada
   - **Tech** (obligatorio): Tecnología (ej: "Moodle", "WordPress")
   - **Tipo** (obligatorio): Tipo de producto (ej: "theme", "block", "local")
   - **Metadata** (opcional): JSON con metadatos adicionales
   - **Activo** (checkbox): Si el producto está activo en el sistema
   - **Habilitado** (checkbox): Si el producto está habilitado para uso
3. Hacer clic en **Guardar**

**Validaciones**:
- Slug debe ser único y tener máximo 200 caracteres
- Nombre máximo 200 caracteres
- Resumen es obligatorio
- Tech y Type máximo 50 caracteres
- Metadata debe ser JSON válido (si se proporciona)

**Campos clave explicados**:
- **`actived`**: Indica si el producto está activo en el sistema (visible en listados, puede tener contenido)
- **`enabled`**: Indica si el producto está habilitado para uso (puede ser consumido vía API)
- **`type`**: Tipo de producto (theme, block, local, etc.)
- **`metadata`**: JSON con información adicional (ej: `{"version": "1.0", "author": "Tresipunt"}`)

### 4.2. Versionado

El sistema soporta versionado para diferentes tipos de contenido asociados a productos:

**Tipos de contenido versionados**:
- **Features**: Funcionalidades documentadas
- **Tutoriales**: Vídeos de YouTube/Vimeo
- **Recursos**: Archivos y enlaces externos
- **SCSS**: Archivos de estilos
- **JS**: Archivos JavaScript
- **SCSS CDN**: Bundles de SCSS para CDN
- **Setups**: Configuraciones YAML

**Formato de versión**: `YYYYMMDDXX`
- `YYYY`: Año (4 dígitos)
- `MM`: Mes (2 dígitos)
- `DD`: Día (2 dígitos)
- `XX`: Número de versión del día (2 dígitos, 01-99)

**Ejemplos**:
- `2025110401`: Primera versión del 4 de noviembre de 2025
- `2025110402`: Segunda versión del mismo día
- `2025121501`: Primera versión del 15 de diciembre de 2025

**Cómo funciona el versionado**:
1. Se crea una "versión" del tipo de contenido (ej: FeatureVersion, TutorialVersion)
2. Dentro de esa versión se crean los elementos (Features, Tutorials, etc.)
3. Cuando se consume vía API, el sistema busca la versión compatible más alta (≤ versión del plugin solicitante)

### 4.3. Configuración del Producto

**Campos de configuración importantes**:

| Campo | Descripción | Valores |
|-------|-------------|---------|
| `slug` | Identificador único técnico | Debe ser único, usado en API |
| `actived` | Producto activo en sistema | `true`/`false` |
| `enabled` | Producto habilitado para uso | `true`/`false` |
| `type` | Tipo de producto | theme, block, local, etc. |
| `metadata` | Metadatos adicionales | JSON válido |

**Configuración desde Configuraciones**:
Existe una sección especial **Configuraciones → Productos** (requiere permisos `admin.configurations.products.*`) que permite:
- Asociar tipos de entornos válidos para el producto
- Subir imagen del producto
- Configuraciones avanzadas

---

## 5. Tokens / Licencias

Los tokens de licencia son claves que permiten a los sitios Moodle consumir productos del Manager a través de la API.

### 5.1. Crear Token

**Permiso requerido**: `admin.license-tokens.create` (Admin, Manager)

**Proceso**: Wizard de 4 pasos

#### Paso 1: Cliente y Token

1. **Seleccionar Cliente** (obligatorio):
   - Buscar cliente en el listado
   - Seleccionar el cliente propietario del token

2. **Nombre del Token** (opcional):
   - Nombre descriptivo (ej: "Licencia Producción Cliente X")

3. **Token** (obligatorio):
   - **Generación automática**: Por defecto se genera automáticamente
   - **Formato**: `3IP-XXXX-XXXX-XXXX-XXXX` (ej: `3IP-A1B2-C3D4-E5F6-G7H8`)
   - **Generar manualmente**: Desmarcar "Generar automáticamente" y hacer clic en "Generar Token"
   - **Token personalizado**: Puedes introducir tu propio token (debe ser único)

4. **Fechas** (opcionales):
   - **Fecha de inicio**: Desde cuándo es válido el token
   - **Fecha de fin**: Hasta cuándo es válido (si se establece inicio, se auto-completa fin = inicio + 1 año)

5. **Observaciones** (opcional):
   - Notas internas sobre el token

6. Hacer clic en **Siguiente**

**Validaciones**:
- Cliente debe existir
- Token debe ser único en el sistema
- Si hay fecha de fin, debe ser >= fecha de inicio

#### Paso 2: Entornos

Seleccionar los entornos que usarán este token:

**Opción A: Entornos existentes**
1. Seleccionar "Usar entornos existentes"
2. Buscar y seleccionar uno o más entornos de la lista
3. Los entornos seleccionados quedarán vinculados al token

**Opción B: Crear nuevo entorno**
1. Seleccionar "Crear nuevo entorno"
2. Completar datos del nuevo entorno:
   - Nombre (obligatorio)
   - Dominio (obligatorio, único)
   - Descripción (opcional)
   - Versión (obligatorio)
   - Entorno: local/develop/pre/pro (obligatorio)
   - Tipo (opcional)
3. El entorno se creará automáticamente al guardar el token

Hacer clic en **Siguiente**

#### Paso 3: Productos

1. Seleccionar uno o más productos que estarán disponibles para este token
2. Los productos seleccionados quedarán asociados al token con estado "active"
3. Hacer clic en **Siguiente**

#### Paso 4: Resumen y Confirmación

1. Revisar toda la información
2. Hacer clic en **Crear Licencia**
3. El token se crea y se asocian todos los elementos seleccionados

### 5.2. Revocar Token

**Permiso requerido**: `admin.license-tokens.edit` (Admin, Manager)

**Métodos para revocar**:

#### Método 1: Desactivar token
1. Editar el token
2. Desmarcar el checkbox **Activo**
3. Guardar

**Efecto**: El token queda inactivo, todas las peticiones de la API fallarán con error 403.

#### Método 2: Establecer fecha de expiración
1. Editar el token
2. Establecer **Fecha de fin** en una fecha pasada
3. Guardar

**Efecto**: El token queda expirado, las peticiones fallarán con error 403.

### 5.3. Regenerar Token

**Permiso requerido**: `admin.license-tokens.edit` (Admin, Manager)

**Pasos**:
1. Editar el token
2. Hacer clic en el botón **Generar Token**
3. Se generará un nuevo token único con formato `3IP-XXXX-XXXX-XXXX-XXXX`
4. **Importante**: Guardar el nuevo token y comunicarlo al cliente, ya que el token anterior dejará de funcionar
5. Guardar

**Nota**: El token anterior quedará invalidado. Cualquier sitio que use el token antiguo dejará de funcionar.

### 5.4. Asociaciones

**Token → Cliente**:
- Un token pertenece a un cliente
- Se establece en el Paso 1 del wizard

**Token → Productos**:
- Un token puede tener múltiples productos asociados
- Se establece en el Paso 3 del wizard
- La relación se guarda en la tabla `license_token_product` con campos adicionales:
  - `status`: Estado de la asociación (active/inactive)
  - `start_at`: Fecha de inicio de validez
  - `end_at`: Fecha de fin de validez
  - `assigned_by`: Usuario que asignó el producto
  - `observation`: Observaciones

**Token → Entornos**:
- Un token puede tener múltiples entornos asociados
- Un entorno solo puede estar asociado a un token a la vez
- Se establece en el Paso 2 del wizard o desde "Gestionar Entornos"

### 5.5. Reglas de Validez

Para que un token sea válido y pueda usarse en la API, deben cumplirse TODAS estas condiciones:

1. **Token activo**: `active = true`
2. **Fechas válidas**:
   - Si existe `start_at`: `ahora >= start_at`
   - Si existe `end_at`: `ahora <= end_at`
3. **Límite de uso**: Si existe `usage_limit`, no debe haberse excedido (rate limiting)
4. **Host vinculado**: El host de la petición debe estar asociado al token (excepto para acción `sync`)

**Errores comunes en la API**:
- `401 Unauthorized`: Token no válido o no proporcionado
- `403 Forbidden`: Token inactivo, expirado o sin permisos
- `429 Too Many Requests`: Límite de peticiones excedido

---

## 6. Gestión de Contenido

El contenido se organiza por producto y versión. Primero se crea una versión, luego se crean los elementos dentro de esa versión.

### 6.1. Tutoriales

Los tutoriales son vídeos de YouTube o Vimeo que se muestran en la interfaz del plugin.

**Permisos requeridos**: `admin.tutorials.*` (Admin, Manager, Developer)

**Flujo de creación**:
1. Acceder a **Productos** → Seleccionar producto → **Tutoriales**
2. **Crear versión**:
   - Hacer clic en **Crear Versión**
   - Introducir versión (formato YYYYMMDDXX)
   - Descripción (opcional)
   - Guardar
3. **Crear tutoriales dentro de la versión**:
   - Desde la versión creada, hacer clic en **Crear Tutorial**
   - Completar campos:
     - **ID del vídeo** (obligatorio): ID del vídeo de YouTube o Vimeo
     - **Plataforma** (obligatorio): `youtube` o `vimeo`
     - **Título** (obligatorio): Título del tutorial
     - **Descripción** (opcional): Descripción del tutorial
     - **Estado** (obligatorio): 
       - `published`: Publicado (visible en API)
       - `draft`: Borrador (no visible)
       - `archived`: Archivado (no visible)
     - **Orden** (opcional): Número para ordenar (menor = primero)
   - Guardar

**Consumo vía API**: Acción `tutorials`
- Solo se devuelven tutoriales con estado `published`
- Ordenados por `sort_order` ascendente

### 6.2. Features (Funcionalidades)

Las features son funcionalidades documentadas del producto, con contenido HTML enriquecido.

**Permisos requeridos**: `admin.features.*` (Admin, Manager, Developer)

**Flujo de creación**:
1. Acceder a **Productos** → Seleccionar producto → **Features**
2. **Crear versión** (igual que tutoriales)
3. **Crear feature**:
   - **Título** (obligatorio)
   - **Descripción** (opcional): Descripción breve
   - **Contenido HTML** (opcional): Contenido enriquecido con editor WYSIWYG
   - **Imagen miniatura** (opcional): Imagen pequeña
   - **Imagen de cabecera** (opcional): Imagen grande
   - **Estado**: `published`, `draft`, `archived`
   - **Orden**: Número para ordenar

**Consumo vía API**: Acción `features`
- Solo se devuelven features con estado `published`
- Ordenadas por `sort_order` ascendente

### 6.3. Recursos

Los recursos son archivos o enlaces externos relacionados con el producto.

**Permisos requeridos**: `admin.resources.*` (Admin, Manager, Developer)

**Flujo de creación**:
1. Acceder a **Productos** → Seleccionar producto → **Recursos**
2. **Crear versión** (igual que tutoriales)
3. **Crear recurso**:
   - **Título** (obligatorio)
   - **Descripción** (opcional)
   - **Tipo** (obligatorio):
     - `file`: Archivo subido
     - `link`: Enlace externo
   - **Si tipo = file**:
     - Subir archivo
     - **Público**: Si el archivo es accesible públicamente
   - **Si tipo = link**:
     - **URL** (obligatorio): URL del enlace
   - **Tiempo de lectura** (opcional): Minutos estimados
   - **Estado**: `published`, `draft`, `archived`
   - **Público**: Si el recurso es público (solo para tipo file)
   - **Orden**: Número para ordenar

**Consumo vía API**: Acción `resources`
- Solo se devuelven recursos con estado `published` y `is_public = true`
- Ordenados por `sort_order` ascendente

### 6.4. JS (JavaScript)

Archivos JavaScript versionados para el producto.

**Permisos requeridos**: `admin.js.*` (Admin, Manager, Developer)

**Flujo de creación**:
1. Acceder a **Productos** → Seleccionar producto → **JS**
2. **Crear versión**:
   - Versión (YYYYMMDDXX)
   - Descripción (opcional)
3. **Subir/Crear archivos**:
   - **Opción A - Subir archivos**:
     - Hacer clic en **Subir archivos**
     - Seleccionar uno o más archivos .js
     - Los archivos se suben manteniendo estructura de carpetas
   - **Opción B - Crear archivo manualmente**:
     - Hacer clic en **Crear archivo**
     - Nombre del archivo (con ruta relativa, ej: `js/custom.js`)
     - Contenido del archivo
     - Guardar

**Estructura de carpetas**: Se respeta la estructura de carpetas al subir archivos. Ejemplo:
```
js/
  ├── main.js
  ├── utils/
  │   ├── helpers.js
  │   └── validators.js
  └── components/
      └── modal.js
```

**Consumo vía API**: Acción `js`
- Se devuelven todos los archivos de la versión compatible
- El cliente debe incluir los archivos en el orden correcto

### 6.5. SCSS

Archivos SCSS versionados para el producto.

**Permisos requeridos**: `admin.scss.*` (Admin, Manager, Developer)

**Flujo**: Similar a JS
1. Crear versión
2. Subir o crear archivos SCSS
3. Se respeta estructura de carpetas

**Consumo vía API**: Acción `scss`
- Se puede solicitar archivos específicos mediante `data.files` en el request
- Se devuelve el contenido de cada archivo

### 6.6. SCSS CDN

Bundles de SCSS para servir vía CDN con URLs firmadas.

**Permisos requeridos**: `admin.scss-cdn.*` (Admin, Manager, Developer)

**Flujo de creación**:
1. **Crear bundle**:
   - Acceder a **Productos** → Seleccionar producto → **SCSS CDN**
   - Hacer clic en **Crear Bundle**
   - Versión (YYYYMMDDXX)
   - Descripción (opcional)
   - Guardar

2. **Subir ZIP**:
   - Desde el bundle, hacer clic en **Subir ZIP**
   - Seleccionar archivo ZIP con estructura de archivos SCSS
   - El sistema:
     - Extrae el ZIP
     - Procesa los imports (`@import`)
     - Crea registros de archivos
     - Marca archivos como "servibles" o "no servibles"

3. **Configurar archivos servibles**:
   - Desde el bundle, editar cada archivo
   - Marcar como **Servible** si debe estar disponible vía CDN
   - Los archivos no servibles son dependencias internas (no se sirven directamente)

4. **URLs firmadas**:
   - Cada archivo servible tiene un token seguro único
   - Las URLs tienen formato: `/api/cdn/scss/{token}/{filename}`
   - Expiración: 1 año por defecto, 1 hora para uso en API

**Consumo vía API**: Acción `scss-cdn`
- Se devuelven URLs firmadas de todos los archivos servibles
- El cliente puede usar estas URLs directamente en `<link>` tags
- Las URLs incluyen imports procesados dinámicamente

**Ejemplo de uso**:
```html
<link rel="stylesheet" href="https://manager.tresipunt.com/api/cdn/scss/abc123def456/variables.css">
```

### 6.7. Tipos de Contenido - Cuándo Usar Cada Uno

| Tipo | Cuándo Usar | Ejemplo |
|------|-------------|---------|
| **Tutoriales** | Vídeos explicativos, guías en vídeo | "Cómo configurar el tema", "Tutorial de personalización" |
| **Features** | Funcionalidades documentadas con contenido HTML | "Sistema de notificaciones", "Panel de administración" |
| **Recursos** | Archivos descargables, enlaces externos | "Manual PDF", "Enlace a documentación" |
| **JS** | Funcionalidades JavaScript del plugin | Scripts de interacción, validaciones, componentes |
| **SCSS** | Estilos que se compilan en el cliente | Variables, mixins, estilos base |
| **SCSS CDN** | Estilos que se sirven directamente vía CDN | Estilos finales compilados, sin procesamiento en cliente |
| **Setups** | Configuraciones YAML | Parámetros de configuración, opciones del plugin |

---

## 7. Setups

Los setups son configuraciones YAML versionadas que definen parámetros y opciones para los productos.

### 7.1. Qué es un Setup

Un setup es un archivo YAML que contiene configuración estructurada para un producto en una versión específica. Se almacena en la base de datos (campo `yaml`) y puede referenciar archivos externos si es necesario.

**Ejemplo de setup YAML**:
```yaml
theme:
  colors:
    primary: "#007bff"
    secondary: "#6c757d"
  layout:
    sidebar: true
    header: "fixed"
features:
  notifications: true
  analytics: false
```

### 7.2. Crear / Editar Setup

**Permiso requerido**: `admin.setups.create`, `admin.setups.edit` (Admin, Manager, Developer)

**Pasos**:
1. Acceder a **Productos** → Seleccionar producto → **Setups**
2. Hacer clic en **Crear Setup**
3. Completar formulario:
   - **Versión** (obligatorio): Formato YYYYMMDDXX, debe ser único para el producto
   - **Método de entrada**:
     - **Editor**: Escribir YAML directamente en el editor
     - **Archivo**: Subir archivo .yaml o .yml
   - **YAML** (obligatorio): Contenido YAML válido
   - **Descripción** (opcional): Descripción del setup
4. El sistema valida que el YAML sea válido antes de guardar
5. Guardar

**Validaciones**:
- Versión debe tener formato YYYYMMDDXX (10 dígitos)
- Versión debe ser única para el producto
- YAML debe ser válido (sintaxis correcta)
- Si se sube archivo, máximo 10MB

**Estados**:
- `active`: Setup activo (se devuelve en API)
- `deprecated`: Setup deprecado (no se devuelve en API)

**Editar setup**:
1. Desde el listado de setups, hacer clic en **Editar**
2. Modificar YAML o descripción
3. El sistema guarda un historial de cambios (si está implementado)
4. Guardar

### 7.3. Consumo vía API

**Acción**: `setup`

**Request ejemplo**:
```json
{
  "action": "setup",
  "plugin": "theme_fresk",
  "version": "2025110401",
  "host": "https://moodle.ejemplo.com",
  "environment": {...}
}
```

**Response ejemplo**:
```json
{
  "success": true,
  "error": "",
  "code": 0,
  "action": "setup",
  "data": {
    "version": "2025110401",
    "yaml": {
      "theme": {
        "colors": {
          "primary": "#007bff"
        }
      }
    }
  }
}
```

**Búsqueda de versión compatible**:
- El sistema busca la versión exacta solicitada
- Si no existe, busca la versión compatible más alta que sea ≤ versión solicitada
- Si no hay versión compatible, devuelve error 3002

**Ejemplo**:
- Plugin solicita versión `2025110401`
- Existen setups: `2025110301`, `2025110401`, `2025110501`
- Se devuelve `2025110401` (exacta)
- Si no existiera `2025110401`, se devolvería `2025110301` (más alta compatible)

### 7.4. Casos de Uso y Ejemplos

**Caso 1: Configuración de tema**
```yaml
theme:
  name: "Fresk"
  version: "2.0"
  colors:
    primary: "#007bff"
    secondary: "#6c757d"
    accent: "#28a745"
  layout:
    sidebar_position: "left"
    header_style: "fixed"
```

**Caso 2: Configuración de funcionalidades**
```yaml
features:
  notifications:
    enabled: true
    sound: true
  analytics:
    enabled: true
    track_events: ["page_view", "click"]
  custom_css:
    enabled: false
```

**Caso 3: Configuración de integraciones**
```yaml
integrations:
  api:
    endpoint: "https://api.ejemplo.com"
    timeout: 30
  cache:
    enabled: true
    ttl: 3600
```

---

## Errores Comunes y Soluciones

### Error: "No tienes permisos para realizar esta acción"
**Solución**: Verificar que tu usuario tenga el rol y permisos necesarios. Contactar con un administrador.

### Error: "El email ya está en uso"
**Solución**: El email ya existe. Usar otro email o editar el usuario existente.

### Error: "Este usuario no se puede editar"
**Solución**: Estás intentando editar un usuario Admin sin ser Admin. Solo los Admins pueden editar otros Admins.

### Error: "El dominio ya está en uso"
**Solución**: El dominio del entorno ya existe. Usar otro dominio o editar el entorno existente.

### Error: "Ya existe un setup para este producto y versión"
**Solución**: La versión del setup ya existe para este producto. Usar otra versión o editar el setup existente.

### Error: "YAML inválido"
**Solución**: Revisar la sintaxis del YAML. Usar un validador online o el editor del sistema que muestra errores.

### Error: "Token no válido" en API
**Solución**: 
- Verificar que el token existe y está activo
- Verificar que las fechas de validez son correctas
- Verificar que el host de la petición está asociado al token

---

## Referencias

- [Manual Técnico](MANUAL_TECNICO.md) - Para información técnica y de desarrollo
- [Documentación API](API_DOCUMENTATION.md) - Para detalles completos de la API
- [Guía de Usuario API](API_USER_GUIDE.md) - Para desarrolladores que integran la API

---

**Última actualización**: 2025-01-XX

