From 44d7bb5df9096616e854e77fe375866310808fb6 Mon Sep 17 00:00:00 2001
From: Manuel Aranda
Date: Thu, 16 Oct 2025 12:40:05 +0200
Subject: [PATCH] New version 1.1.0
---
CHANGELOG.md | 9 +
README.md | 1412 ++++++++++++-----
migrations/Version20251015080216.php | 31 +
ogCore_Documentacion_Tecnica.html | 1151 ++++++--------
ogCore_Documentacion_Tecnica.pdf | Bin 328369 -> 391675 bytes
src/Command/LoadDefaultMenuCommand.php | 2 +-
.../ChangeOrganizationalUnitAction.php | 10 +-
.../OgBoot/PxeBootFile/PostAction.php | 2 +-
src/Dto/Input/ClientInput.php | 14 +-
src/Dto/Input/DeployGitImageInput.php | 4 +-
src/Dto/Input/DeployImageInput.php | 4 +-
src/Dto/Input/OrganizationalUnitInput.php | 8 +
src/Dto/Output/ClientOutput.php | 8 +
src/Dto/Output/MenuOutput.php | 4 +-
src/Entity/Client.php | 14 +
src/State/Processor/ClientProcessor.php | 1 +
...ClientsHaveSamePartitionCountValidator.php | 39 -
...t.php => ClientsHaveSamePartitionSize.php} | 4 +-
.../ClientsHaveSamePartitionSizeValidator.php | 76 +
.../Constraints/OrganizationalUnitParent.php | 4 +-
.../OrganizationalUnitParentValidator.php | 9 +
translations/validators.en.yaml | 5 +
translations/validators.es.yaml | 5 +
23 files changed, 1717 insertions(+), 1099 deletions(-)
create mode 100644 migrations/Version20251015080216.php
delete mode 100644 src/Validator/Constraints/ClientsHaveSamePartitionCountValidator.php
rename src/Validator/Constraints/{ClientsHaveSamePartitionCount.php => ClientsHaveSamePartitionSize.php} (69%)
create mode 100644 src/Validator/Constraints/ClientsHaveSamePartitionSizeValidator.php
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8c41b04..47a0fa8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,13 @@
# Changelog
+## [1.1.0] - 2025-10-16
+### Added
+- Se ha añadido un nuevo campo en el cliente, para guardar la resolucion del menu browser.
+- Se ha añadido un validador en el asistente "deploy", el cual comprueba que el tamaño de la partition destino de todos los clientes sea igual.
+
+### Fixed
+- Se ha corregido un bug a la hora de mover clientes cuando el aula destino no tiene plantilla PXE asignada.
+
+---
## [1.0.0] - 2025-10-09
### Added
- Se ha añadido nuevo readme
diff --git a/README.md b/README.md
index 1a52c11..559fd35 100644
--- a/README.md
+++ b/README.md
@@ -8,8 +8,8 @@
4. [Tecnologías Utilizadas](#4-tecnologías-utilizadas)
5. [Requisitos del Sistema](#5-requisitos-del-sistema)
6. [Instalación y Configuración](#6-instalación-y-configuración)
-7. [Modelo de Datos](#7-modelo-de-datos)
-8. [Componentes del Sistema](#8-componentes-del-sistema)
+7. [Componentes del Sistema](#7-componentes-del-sistema)
+8. [Guía de Desarrollo - Crear Nueva Entidad](#8-guía-de-desarrollo---crear-nueva-entidad)
9. [API RESTful](#9-api-restful)
10. [Seguridad y Autenticación](#10-seguridad-y-autenticación)
11. [Servicios Principales](#11-servicios-principales)
@@ -71,8 +71,7 @@ ogCore es el núcleo central de OpenGnsys desarrollado con tecnologías modernas
- **Arquitectura basada en eventos** con notificaciones en tiempo real (Mercure)
- **Sistema de colas** para la ejecución de tareas programadas
- **Integración con múltiples servicios** externos
-- **Migraciones automatizadas** desde OpenGnsys 1.1
-- **Versionado de imágenes** con integración Git
+- **Creación de imágenes** con integración Git y sistema monolítico
- **Sistema de trazabilidad** completo
- **Gestión de hardware** con inventario automático
- **Despliegues masivos** de imágenes (unicast, multicast, torrent, p2p)
@@ -81,7 +80,7 @@ ogCore es el núcleo central de OpenGnsys desarrollado con tecnologías modernas
### 2.3 Versión Actual
-- **Versión**: 0.5.0
+- **Versión**: 1.0.0
- **Estado**: En desarrollo activo
- **Última actualización**: Octubre 2025
@@ -103,7 +102,7 @@ ogCore sigue una arquitectura de **microservicios** basada en el patrón **API-F
+---------------------------v---------------------------------+
| ogCore API (Symfony) |
| +------------------------------------------------------+ |
-| | Controllers | States | DTOs | Validators | Filters | |
+| | Controllers | States | DTOs | Validators | Filters | |
| +------------------------------------------------------+ |
| +------------------------------------------------------+ |
| | Business Logic (Services) | |
@@ -248,7 +247,7 @@ ogCore sigue una arquitectura de **microservicios** basada en el patrón **API-F
## 6. Instalación y Configuración
-### 6.1 Instalación con Docker (Recomendado)
+### 6.1 Instalación con Docker
#### 6.1.1 Clonar el Repositorio
@@ -380,275 +379,9 @@ Asegúrate de:
---
-## 7. Modelo de Datos
+## 7. Componentes del Sistema
-### 7.1 Diagrama de Entidades
-
-El sistema cuenta con 35 entidades principales agrupadas en los siguientes dominios:
-
-### 7.2 Entidades Principales
-
-#### 7.2.1 Client (Cliente)
-
-Representa un equipo físico en el sistema.
-
-**Campos principales:**
-- `id`: UUID único
-- `name`: Nombre del cliente
-- `serialNumber`: Número de serie
-- `mac`: Dirección MAC (única)
-- `ip`: Dirección IP (única)
-- `status`: Estado del cliente (active, inactive, busy, windows, linux, etc.)
-- `netiface`: Interfaz de red
-- `netDriver`: Driver de red
-- `validation`: Estado de validación
-- `maintenance`: Modo mantenimiento
-- `position`: Posición en el aula (x, y)
-- `firmwareType`: Tipo de firmware (BIOS/UEFI)
-- `agentJobId`: ID del trabajo del agente en ejecución
-- `pxeSync`: Sincronización PXE
-- `token`: Token de autenticación del cliente
-
-**Relaciones:**
-- `organizationalUnit`: Pertenece a una unidad organizativa (aula/grupo)
-- `partitions`: Tiene múltiples particiones
-- `menu`: Menú de arranque asignado
-- `hardwareProfile`: Perfil de hardware asociado
-- `template`: Plantilla PXE asignada
-- `repository`: Repositorio de imágenes
-- `subnet`: Subred a la que pertenece
-- `ogLive`: Imagen Live asignada
-
-#### 7.2.2 OrganizationalUnit (Unidad Organizativa)
-
-Representa aulas o grupos de equipos.
-
-**Campos principales:**
-- `id`: UUID único
-- `name`: Nombre de la unidad
-- `description`: Descripción
-- `type`: Tipo (aula, grupo, etc.)
-
-**Relaciones:**
-- `parent`: Unidad organizativa padre (jerarquía)
-- `children`: Unidades hijas
-- `clients`: Clientes pertenecientes
-- `networkSettings`: Configuración de red heredable
-- `remoteCalendar`: Calendario remoto asociado
-
-#### 7.2.3 Image (Imagen)
-
-Representa una imagen de sistema operativo.
-
-**Campos principales:**
-- `id`: UUID único
-- `name`: Nombre de la imagen
-- `description`: Descripción
-- `type`: Tipo de imagen
-- `size`: Tamaño en bytes
-- `partition`: Partición de origen
-- `status`: Estado (creating, success, failed, etc.)
-- `isGlobal`: Imagen global compartida
-- `isVirtual`: Imagen virtual
-- `version`: Versión de la imagen
-
-**Relaciones:**
-- `operativeSystem`: Sistema operativo
-- `softwareProfile`: Perfil de software
-- `repositories`: Repositorios que contienen la imagen
-- `originClient`: Cliente origen de la imagen
-
-#### 7.2.4 Command (Comando)
-
-Comandos ejecutables en el sistema.
-
-**Campos principales:**
-- `id`: UUID único
-- `name`: Nombre del comando
-- `description`: Descripción
-- `script`: Script a ejecutar
-
-**Relaciones:**
-- `commandGroups`: Grupos de comandos a los que pertenece
-
-#### 7.2.5 CommandTask (Tarea de Comando)
-
-Tarea programada para ejecutar comandos.
-
-**Campos principales:**
-- `id`: UUID único
-- `datetime`: Fecha y hora de ejecución
-- `parameters`: Parámetros de ejecución
-- `status`: Estado de la tarea
-
-**Relaciones:**
-- `commands`: Comandos a ejecutar
-- `commandGroups`: Grupos de comandos
-- `clients`: Clientes objetivo
-- `schedule`: Programación recurrente
-
-#### 7.2.6 Trace (Traza)
-
-Registro de ejecución de comandos.
-
-**Campos principales:**
-- `id`: UUID único
-- `command`: Nombre del comando ejecutado
-- `input`: Parámetros de entrada
-- `output`: Resultado de ejecución
-- `status`: Estado (pending, processing, success, failed, cancelled)
-- `executedAt`: Fecha de ejecución
-- `finishedAt`: Fecha de finalización
-- `cancelled`: Indica si fue cancelada
-- `jobId`: ID del trabajo en el agente
-
-**Relaciones:**
-- `client`: Cliente donde se ejecutó
-
-#### 7.2.7 HardwareProfile (Perfil de Hardware)
-
-Inventario de hardware de un cliente.
-
-**Campos principales:**
-- `id`: UUID único
-- `cpu`: Información de CPU
-- `ram`: Memoria RAM
-- `storage`: Almacenamiento
-- `networkCards`: Tarjetas de red
-
-**Relaciones:**
-- `client`: Cliente asociado
-- `hardwareTypes`: Tipos de hardware detectados
-
-#### 7.2.8 SoftwareProfile (Perfil de Software)
-
-Software instalado en una imagen.
-
-**Campos principales:**
-- `id`: UUID único
-- `name`: Nombre del perfil
-
-**Relaciones:**
-- `software`: Software incluido
-- `images`: Imágenes que usan este perfil
-
-#### 7.2.9 ImageRepository (Repositorio de Imágenes)
-
-Servidor de almacenamiento de imágenes.
-
-**Campos principales:**
-- `id`: UUID único
-- `name`: Nombre del repositorio (único)
-- `ip`: Dirección IP o DNS (único)
-- `port`: Puerto
-- `sshPort`: Puerto SSH
-- `sshUser`: Usuario SSH
-- `apiKey`: Clave API
-- `status`: Estado del repositorio
-
-**Relaciones:**
-- `images`: Imágenes almacenadas
-
-#### 7.2.10 Subnet (Subred)
-
-Configuración de red.
-
-**Campos principales:**
-- `id`: UUID único
-- `name`: Nombre de la subred
-- `cidr`: Notación CIDR
-- `gateway`: Puerta de enlace
-- `dns`: Servidores DNS
-- `dhcpStart`: Inicio rango DHCP
-- `dhcpEnd`: Fin rango DHCP
-
-**Relaciones:**
-- `clients`: Clientes en la subred
-
-#### 7.2.11 Partition (Partición)
-
-Partición de disco de un cliente.
-
-**Campos principales:**
-- `id`: UUID único
-- `partitionNumber`: Número de partición
-- `partitionType`: Tipo de partición
-- `partitionSize`: Tamaño
-- `partitionCode`: Código de partición
-- `usedSize`: Tamaño usado
-- `filesystem`: Sistema de archivos
-
-**Relaciones:**
-- `client`: Cliente propietario
-- `image`: Imagen desplegada
-- `operativeSystem`: Sistema operativo instalado
-
-#### 7.2.12 PxeTemplate (Plantilla PXE)
-
-Plantilla de arranque PXE.
-
-**Campos principales:**
-- `id`: UUID único
-- `name`: Nombre de la plantilla
-- `content`: Contenido de la plantilla
-- `default`: Plantilla por defecto
-
-**Relaciones:**
-- `clients`: Clientes que usan la plantilla
-
-#### 7.2.13 RemoteCalendar (Calendario Remoto)
-
-Integración con sistemas de reservas remotas.
-
-**Campos principales:**
-- `id`: UUID único
-- `name`: Nombre del calendario
-- `url`: URL del servicio
-- `available`: Disponibilidad
-
-**Relaciones:**
-- `organizationalUnits`: Unidades organizativas asociadas
-- `rules`: Reglas del calendario
-
-#### 7.2.14 User (Usuario)
-
-Usuario del sistema.
-
-**Campos principales:**
-- `id`: UUID único
-- `username`: Nombre de usuario (único)
-- `password`: Contraseña (hasheada)
-- `email`: Correo electrónico
-- `roles`: Roles del usuario
-
-**Relaciones:**
-- `userGroups`: Grupos de usuarios
-- `view`: Vista preferida
-
-#### 7.2.15 GitRepository (Repositorio Git)
-
-Repositorio Git para versionado de imágenes.
-
-**Campos principales:**
-- `id`: UUID único
-- `name`: Nombre del repositorio
-- `url`: URL del repositorio
-- `branch`: Rama
-- `credentials`: Credenciales de acceso
-
-### 7.3 Índices y Optimizaciones
-
-La base de datos está optimizada con índices en:
-- Campos de búsqueda frecuente (status, updatedAt)
-- Campos únicos (IP, MAC, username)
-- Claves foráneas
-- Índices compuestos para consultas complejas
-
----
-
-## 8. Componentes del Sistema
-
-### 8.1 Controllers (Controladores)
+### 7.1 Controllers (Controladores)
El sistema cuenta con **102 controladores** organizados por dominio:
@@ -662,7 +395,7 @@ El sistema cuenta con **102 controladores** organizados por dominio:
- **SubnetController**: Gestión de subredes
- **RepositoryController**: Gestión de repositorios
-### 8.2 States (Procesadores de Estado)
+### 7.2 States (Procesadores de Estado)
Los States implementan el patrón State de API Platform:
@@ -671,7 +404,7 @@ Los States implementan el patrón State de API Platform:
- **Processors**: Procesamiento de escritura
- **Custom States**: Lógica personalizada
-### 8.3 DTOs (Data Transfer Objects)
+### 7.3 DTOs (Data Transfer Objects)
**93 DTOs** para transferencia de datos:
@@ -680,7 +413,7 @@ Los States implementan el patrón State de API Platform:
- **Output DTOs**: Para envío de datos
- **Transformation DTOs**: Para transformaciones
-### 8.4 Validators (Validadores)
+### 7.4 Validators (Validadores)
**18 validadores personalizados** para:
- Validación de IPs y MACs
@@ -690,7 +423,7 @@ Los States implementan el patrón State de API Platform:
- Validación de comandos
- Validación de usuarios
-### 8.5 EventSubscribers (Suscriptores de Eventos)
+### 7.5 EventSubscribers (Suscriptores de Eventos)
**8 suscriptores** para:
- Publicación en Mercure al cambiar estados
@@ -698,7 +431,7 @@ Los States implementan el patrón State de API Platform:
- Validaciones pre/post persistencia
- Logging de eventos
-### 8.6 Factories (Fábricas)
+### 7.6 Factories (Fábricas)
**24 factories** para testing con Foundry:
- Creación de entidades para tests
@@ -707,9 +440,970 @@ Los States implementan el patrón State de API Platform:
---
+## 8. Guía de Desarrollo - Crear Nueva Entidad
+
+Esta sección proporciona una guía paso a paso para añadir una nueva entidad al sistema ogCore, incluyendo todos los componentes necesarios.
+
+### 8.1 Visión General
+
+Para añadir una nueva entidad completa al sistema necesitarás crear:
+
+1. **Entity** - La entidad Doctrine
+2. **Repository** - Repositorio personalizado
+3. **DTOs** - Input y Output DTOs
+4. **Configuración YAML** - Para API Platform
+5. **States** - Providers y Processors
+6. **Validators** - Validaciones personalizadas (opcional)
+7. **Factory** - Para testing
+8. **Migración** - Cambios en base de datos
+
+### 8.2 Paso 1: Crear la Entidad
+
+Crea la entidad en `src/Entity/`. Ejemplo: `Product.php`
+
+```php
+description;
+ }
+
+ public function setDescription(?string $description): static
+ {
+ $this->description = $description;
+ return $this;
+ }
+
+ public function getPrice(): ?float
+ {
+ return $this->price;
+ }
+
+ public function setPrice(float $price): static
+ {
+ $this->price = $price;
+ return $this;
+ }
+
+ public function getStock(): ?int
+ {
+ return $this->stock;
+ }
+
+ public function setStock(int $stock): static
+ {
+ $this->stock = $stock;
+ return $this;
+ }
+
+ public function isActive(): ?bool
+ {
+ return $this->active;
+ }
+
+ public function setActive(bool $active): static
+ {
+ $this->active = $active;
+ return $this;
+ }
+
+ public function getCategory(): ?Category
+ {
+ return $this->category;
+ }
+
+ public function setCategory(?Category $category): static
+ {
+ $this->category = $category;
+ return $this;
+ }
+}
+```
+
+### 8.3 Paso 2: Crear el Repository
+
+Crea el repositorio en `src/Repository/ProductRepository.php`:
+
+```php
+
+ */
+class ProductRepository extends ServiceEntityRepository
+{
+ public function __construct(ManagerRegistry $registry)
+ {
+ parent::__construct($registry, Product::class);
+ }
+
+ /**
+ * Encuentra productos activos por categoría
+ */
+ public function findActiveByCategory(int $categoryId): array
+ {
+ return $this->createQueryBuilder('p')
+ ->where('p.category = :categoryId')
+ ->andWhere('p.active = true')
+ ->setParameter('categoryId', $categoryId)
+ ->orderBy('p.name', 'ASC')
+ ->getQuery()
+ ->getResult();
+ }
+
+ /**
+ * Encuentra productos con stock bajo
+ */
+ public function findLowStock(int $threshold = 10): array
+ {
+ return $this->createQueryBuilder('p')
+ ->where('p.stock <= :threshold')
+ ->andWhere('p.active = true')
+ ->setParameter('threshold', $threshold)
+ ->getQuery()
+ ->getResult();
+ }
+}
+```
+
+### 8.4 Paso 3: Crear los DTOs
+
+#### 8.4.1 Input DTO
+
+Crea `src/Dto/Input/ProductInput.php`:
+
+```php
+name = $product->getName();
+ $this->description = $product->getDescription();
+ $this->price = $product->getPrice();
+ $this->stock = $product->getStock();
+ $this->active = $product->isActive();
+ $this->category = $product->getCategory()
+ ? CategoryOutput::fromEntity($product->getCategory())
+ : null;
+ }
+ }
+
+ /**
+ * Crea o actualiza una entidad Product desde este DTO
+ */
+ public function createOrUpdateEntity(?Product $product = null): Product
+ {
+ if (!$product) {
+ $product = new Product();
+ }
+
+ $product->setName($this->name);
+ $product->setDescription($this->description);
+ $product->setPrice($this->price);
+ $product->setStock($this->stock);
+ $product->setActive($this->active ?? true);
+
+ // La categoría se asigna en el Processor después de validarla
+
+ return $product;
+ }
+}
+```
+
+#### 8.4.2 Output DTO
+
+Crea `src/Dto/Output/ProductOutput.php`:
+
+```php
+name = $product->getName();
+ $this->description = $product->getDescription();
+ $this->price = $product->getPrice();
+ $this->stock = $product->getStock();
+ $this->active = $product->isActive();
+ $this->category = new CategoryOutput($product->getCategory());
+ $this->createdAt = $product->getCreatedAt();
+ $this->updatedAt = $product->getUpdatedAt();
+ }
+}
+```
+
+### 8.5 Paso 4: Configuración YAML de API Platform
+
+Crea `config/api_platform/Product.yaml`:
+
+```yaml
+App\Entity\Product:
+ operations:
+ get:
+ provider: App\State\Provider\ProductProvider
+ output: App\Dto\Output\ProductOutput
+ getCollection:
+ provider: App\State\Provider\ProductProvider
+ output: App\Dto\Output\ProductOutput
+ filters:
+ - 'App\Filter\SearchFilter'
+ post:
+ input: App\Dto\Input\ProductInput
+ processor: App\State\Processor\ProductProcessor
+ output: App\Dto\Output\ProductOutput
+ security: "is_granted('ROLE_ADMIN')"
+ put:
+ input: App\Dto\Input\ProductInput
+ provider: App\State\Provider\ProductProvider
+ processor: App\State\Processor\ProductProcessor
+ output: App\Dto\Output\ProductOutput
+ security: "is_granted('ROLE_ADMIN')"
+ patch:
+ input: App\Dto\Input\ProductInput
+ provider: App\State\Provider\ProductProvider
+ processor: App\State\Processor\ProductProcessor
+ output: App\Dto\Output\ProductOutput
+ security: "is_granted('ROLE_ADMIN')"
+ delete:
+ processor: App\State\Processor\ProductProcessor
+ security: "is_granted('ROLE_ADMIN')"
+
+ properties:
+ id:
+ identifier: true
+ name:
+ required: true
+ price:
+ required: true
+ stock:
+ required: true
+ active:
+ required: true
+ category:
+ required: true
+ description:
+ required: false
+ createdAt:
+ required: false
+ updatedAt:
+ required: false
+```
+
+### 8.6 Paso 5: Crear States (Provider y Processor)
+
+ogCore usa **un único Provider** y **un único Processor** por entidad que manejan todas las operaciones HTTP.
+
+#### 8.6.1 Provider
+
+Crea `src/State/Provider/ProductProvider.php`:
+
+```php
+provideCollection($operation, $uriVariables, $context);
+ case $operation instanceof Patch:
+ case $operation instanceof Put:
+ return $this->provideInput($operation, $uriVariables, $context);
+ case $operation instanceof Get:
+ return $this->provideItem($operation, $uriVariables, $context);
+ }
+ }
+
+ /**
+ * Proporciona la colección de productos
+ */
+ private function provideCollection(Operation $operation, array $uriVariables = [], array $context = []): object
+ {
+ $filters = $context['filters'] ?? [];
+
+ // Usar el provider de API Platform para paginación automática
+ $paginator = $this->collectionProvider->provide($operation, $uriVariables, $context);
+
+ // Convertir entidades a DTOs
+ $items = new \ArrayObject();
+ foreach ($paginator->getIterator() as $product) {
+ $items[] = new ProductOutput($product);
+ }
+
+ return new TraversablePaginator(
+ $items,
+ $paginator->getCurrentPage(),
+ $paginator->getItemsPerPage(),
+ $paginator->getTotalItems()
+ );
+ }
+
+ /**
+ * Proporciona un producto individual
+ */
+ private function provideItem(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
+ {
+ $product = $this->itemProvider->provide($operation, $uriVariables, $context);
+
+ if (!$product) {
+ throw new NotFoundHttpException('Producto no encontrado');
+ }
+
+ return new ProductOutput($product);
+ }
+
+ /**
+ * Proporciona el Input DTO para PUT/PATCH
+ */
+ private function provideInput(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
+ {
+ if (isset($uriVariables['id'])) {
+ $product = $this->itemProvider->provide($operation, $uriVariables, $context);
+
+ return $product !== null ? new ProductInput($product) : null;
+ }
+
+ return new ProductInput();
+ }
+}
+```
+
+#### 8.6.2 Processor
+
+Crea `src/State/Processor/ProductProcessor.php`:
+
+```php
+processCreateOrUpdate($data, $operation, $uriVariables, $context);
+ case $operation instanceof Delete:
+ return $this->processDelete($data, $operation, $uriVariables, $context);
+ }
+ }
+
+ /**
+ * Procesa creación y actualización (POST, PUT, PATCH)
+ */
+ private function processCreateOrUpdate(
+ mixed $data,
+ Operation $operation,
+ array $uriVariables = [],
+ array $context = []
+ ): ProductOutput {
+ if (!($data instanceof ProductInput)) {
+ throw new \Exception(sprintf('Data is not instance of %s', ProductInput::class));
+ }
+
+ $product = null;
+
+ // Si es actualización, obtener la entidad existente
+ if (isset($uriVariables['id'])) {
+ $product = $this->productRepository->find($uriVariables['id']);
+ }
+
+ // Buscar categoría desde el Output DTO
+ $category = $data->category ? $data->category->getEntity() : null;
+ if (!$category) {
+ throw new BadRequestHttpException('Categoría no encontrada');
+ }
+
+ // Crear o actualizar usando método del Input DTO
+ $product = $data->createOrUpdateEntity($product);
+ $product->setCategory($category);
+
+ // Validar la entidad
+ $this->validator->validate($product);
+
+ // Guardar
+ $this->productRepository->save($product);
+
+ return new ProductOutput($product);
+ }
+
+ /**
+ * Procesa eliminación (DELETE)
+ */
+ private function processDelete(
+ mixed $data,
+ Operation $operation,
+ array $uriVariables = [],
+ array $context = []
+ ): null {
+ $product = $this->productRepository->find($uriVariables['id']);
+
+ if (!$product) {
+ throw new BadRequestHttpException('Producto no encontrado');
+ }
+
+ $this->productRepository->delete($product);
+
+ return null;
+ }
+}
+```
+
+### 8.7 Paso 6: Crear Validadores Personalizados (Opcional)
+
+Si necesitas validaciones complejas, crea un validador. Ejemplo: `src/Validator/ProductStockValidator.php`:
+
+```php
+context->buildViolation($constraint->message)
+ ->setParameter('{{ value }}', $value)
+ ->addViolation();
+ }
+
+ // Validación adicional: stock máximo
+ if ($value > $constraint->maxStock) {
+ $this->context->buildViolation('El stock no puede exceder {{ limit }}')
+ ->setParameter('{{ limit }}', $constraint->maxStock)
+ ->addViolation();
+ }
+ }
+}
+```
+
+Y la constraint `src/Validator/ProductStock.php`:
+
+```php
+
+ */
+final class ProductFactory extends ModelFactory
+{
+ protected function getDefaults(): array
+ {
+ return [
+ 'name' => self::faker()->words(3, true),
+ 'description' => self::faker()->sentence(),
+ 'price' => self::faker()->randomFloat(2, 1, 1000),
+ 'stock' => self::faker()->numberBetween(0, 100),
+ 'active' => self::faker()->boolean(80), // 80% activos
+ 'category' => CategoryFactory::new(),
+ ];
+ }
+
+ protected static function getClass(): string
+ {
+ return Product::class;
+ }
+
+ /**
+ * Estado: producto sin stock
+ */
+ public function outOfStock(): self
+ {
+ return $this->addState(['stock' => 0]);
+ }
+
+ /**
+ * Estado: producto inactivo
+ */
+ public function inactive(): self
+ {
+ return $this->addState(['active' => false]);
+ }
+
+ /**
+ * Estado: producto de lujo (precio alto)
+ */
+ public function luxury(): self
+ {
+ return $this->addState([
+ 'price' => self::faker()->randomFloat(2, 500, 5000)
+ ]);
+ }
+}
+```
+
+### 8.9 Paso 8: Crear Migración
+
+Genera la migración automáticamente:
+
+```bash
+docker exec ogcore-php php bin/console make:migration
+```
+
+Revisa y edita la migración generada en `migrations/`:
+
+```php
+addSql('CREATE TABLE product (
+ id CHAR(36) NOT NULL COMMENT \'(DC2Type:uuid)\',
+ category_id CHAR(36) NOT NULL COMMENT \'(DC2Type:uuid)\',
+ name VARCHAR(255) NOT NULL,
+ description VARCHAR(500) DEFAULT NULL,
+ price DOUBLE PRECISION NOT NULL,
+ stock INT NOT NULL,
+ active TINYINT(1) NOT NULL,
+ created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\',
+ updated_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\',
+ INDEX IDX_PRODUCT_CATEGORY (category_id),
+ INDEX IDX_PRODUCT_ACTIVE (active),
+ PRIMARY KEY(id)
+ ) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
+
+ $this->addSql('ALTER TABLE product ADD CONSTRAINT FK_PRODUCT_CATEGORY
+ FOREIGN KEY (category_id) REFERENCES category (id) ON DELETE CASCADE');
+ }
+
+ public function down(Schema $schema): void
+ {
+ $this->addSql('ALTER TABLE product DROP FOREIGN KEY FK_PRODUCT_CATEGORY');
+ $this->addSql('DROP TABLE product');
+ }
+}
+```
+
+Ejecuta la migración:
+
+```bash
+docker exec ogcore-php php bin/console doctrine:migrations:migrate --no-interaction
+```
+
+### 8.10 Paso 9: Crear Tests
+
+Crea `tests/Functional/ProductTest.php`:
+
+```php
+request('GET', '/products', [
+ 'headers' => ['Accept' => 'application/json']
+ ]);
+
+ $this->assertResponseIsSuccessful();
+ $this->assertJsonContains(['hydra:totalItems' => 5]);
+ }
+
+ public function testPostProduct(): void
+ {
+ $client = static::createClient();
+ $category = CategoryFactory::createOne();
+
+ $client->request('POST', '/products', [
+ 'json' => [
+ 'name' => 'Producto Test',
+ 'description' => 'Descripción de prueba',
+ 'price' => 99.99,
+ 'stock' => 50,
+ 'active' => true,
+ 'categoryId' => $category->getId()
+ ],
+ 'headers' => ['Content-Type' => 'application/json']
+ ]);
+
+ $this->assertResponseStatusCodeSame(201);
+ $this->assertJsonContains([
+ 'name' => 'Producto Test',
+ 'price' => 99.99
+ ]);
+ }
+
+ public function testPutProduct(): void
+ {
+ $client = static::createClient();
+ $product = ProductFactory::createOne();
+ $newCategory = CategoryFactory::createOne();
+
+ $client->request('PUT', '/products/' . $product->getId(), [
+ 'json' => [
+ 'name' => 'Producto Actualizado',
+ 'price' => 149.99,
+ 'stock' => 30,
+ 'categoryId' => $newCategory->getId()
+ ],
+ 'headers' => ['Content-Type' => 'application/json']
+ ]);
+
+ $this->assertResponseIsSuccessful();
+ $this->assertJsonContains([
+ 'name' => 'Producto Actualizado',
+ 'price' => 149.99
+ ]);
+ }
+
+ public function testDeleteProduct(): void
+ {
+ $client = static::createClient();
+ $product = ProductFactory::createOne();
+
+ $client->request('DELETE', '/products/' . $product->getId());
+
+ $this->assertResponseStatusCodeSame(204);
+ }
+
+ public function testValidation(): void
+ {
+ $client = static::createClient();
+
+ $client->request('POST', '/products', [
+ 'json' => [
+ 'name' => 'AB', // Muy corto
+ 'price' => -10, // Negativo
+ ],
+ 'headers' => ['Content-Type' => 'application/json']
+ ]);
+
+ $this->assertResponseStatusCodeSame(422);
+ }
+}
+```
+
+### 8.11 Paso 10: Documentar en Swagger
+
+La configuración YAML de API Platform generará automáticamente la documentación en Swagger. Puedes añadir descripciones adicionales:
+
+```yaml
+App\Entity\Product:
+ description: 'Entidad que representa un producto del catálogo'
+ operations:
+ get:
+ summary: 'Obtener un producto por ID'
+ description: 'Retorna la información detallada de un producto'
+ provider: App\State\Product\ProductProvider
+ output: App\Dto\Output\ProductOutput
+ getCollection:
+ summary: 'Obtener listado de productos'
+ description: 'Retorna una colección paginada de productos'
+ provider: App\State\Product\ProductCollectionProvider
+ output: App\Dto\Output\ProductOutput
+ # ... resto de operaciones
+```
+
+### 8.12 Checklist de Creación de Entidad
+
+Usa este checklist para asegurarte de no olvidar ningún paso:
+
+- [ ] **Entidad creada** en `src/Entity/`
+- [ ] **Repository creado** en `src/Repository/`
+- [ ] **Input DTO creado** en `src/Dto/Input/` con constructor y método `createOrUpdateEntity()`
+- [ ] **Output DTO creado** en `src/Dto/Output/` con método estático `fromEntity()`
+- [ ] **Configuración YAML** en `config/api_platform/`
+- [ ] **Provider creado** en `src/State/Provider/` (un solo archivo que maneja Get y GetCollection)
+- [ ] **Processor creado** en `src/State/Processor/` (un solo archivo que maneja Post, Put, Patch, Delete)
+- [ ] **Validators** personalizados (si aplica) en `src/Validator/`
+- [ ] **Factory** para testing en `src/Factory/`
+- [ ] **Migración generada** con `make:migration` y ejecutada
+- [ ] **Tests funcionales** creados en `tests/Functional/`
+- [ ] **Documentación Swagger** verificada en `/docs`
+- [ ] **Permisos de seguridad** configurados en YAML con `security: "is_granted('ROLE_X')"`
+
+### 8.13 Comandos Útiles
+
+```bash
+# Generar entidad con maker
+docker exec ogcore-php php bin/console make:entity Product
+
+# Generar migración
+docker exec ogcore-php php bin/console make:migration
+
+# Ejecutar migración
+docker exec ogcore-php php bin/console doctrine:migrations:migrate
+
+# Validar esquema
+docker exec ogcore-php php bin/console doctrine:schema:validate
+
+# Ejecutar tests
+docker exec ogcore-php php bin/phpunit tests/Functional/ProductTest.php
+
+# Ver rutas de API
+docker exec ogcore-php php bin/console debug:router | grep product
+```
+
+### 8.14 Buenas Prácticas
+
+1. **Nomenclatura consistente**: Usa el mismo nombre base para entidad, DTOs, States y Factory
+2. **Validaciones**: Siempre valida en el Input DTO y en el Processor si es necesario
+3. **Seguridad**: Define permisos en la configuración YAML (`security: "is_granted('ROLE_ADMIN')"`)
+4. **Tests**: Crea tests para todos los endpoints (GET, POST, PUT, DELETE)
+5. **DTOs separados**: Nunca expongas la entidad directamente, siempre usa DTOs
+6. **Transacciones**: Doctrine maneja transacciones automáticamente, pero para operaciones complejas considera usar `$entityManager->transactional()`
+7. **Lazy loading**: Configura correctamente las relaciones (fetch LAZY/EAGER)
+8. **Índices**: Añade índices en campos que se usan frecuentemente en WHERE/ORDER BY
+9. **Soft Delete**: Si necesitas "borrado suave", usa `SoftDeleteableTrait` de Gedmo
+10. **Eventos**: Usa EventSubscribers para lógica transversal (logging, notificaciones Mercure)
+
+---
+
## 9. API RESTful
-### 9.1 Documentación
+### 8.1 Documentación
La API está completamente documentada con **OpenAPI 3.0** y accesible en:
@@ -717,7 +1411,7 @@ La API está completamente documentada con **OpenAPI 3.0** y accesible en:
http://127.0.0.1:8080/docs
```
-### 9.2 Formato de Respuestas
+### 8.2 Formato de Respuestas
#### Formato estándar (JSON-LD):
@@ -746,7 +1440,7 @@ http://127.0.0.1:8080/docs
}
```
-### 9.3 Paginación
+### 8.3 Paginación
Todas las colecciones soportan paginación:
@@ -773,7 +1467,7 @@ Respuesta:
}
```
-### 9.4 Filtrado
+### 8.4 Filtrado
Soporta filtros avanzados:
@@ -783,14 +1477,14 @@ GET /clients?organizationalUnit.name=Aula1
GET /traces?client.id=123&status=pending
```
-### 9.5 Ordenamiento
+### 8.5 Ordenamiento
```
GET /clients?order[name]=asc
GET /traces?order[createdAt]=desc
```
-### 9.6 Endpoints Principales
+### 8.6 Endpoints Principales
#### 9.6.1 Autenticación
@@ -848,7 +1542,7 @@ PATCH /traces/{id}/complete
PATCH /traces/{id}/cancel
```
-### 9.7 Códigos de Estado HTTP
+### 8.7 Códigos de Estado HTTP
| Código | Significado |
|--------|-------------|
@@ -865,9 +1559,9 @@ PATCH /traces/{id}/cancel
---
-## 10. Seguridad y Autenticación
+## 9. Seguridad y Autenticación
-### 10.1 Sistema de Autenticación JWT
+### 9.1 Sistema de Autenticación JWT
ogCore utiliza **JSON Web Tokens (JWT)** para autenticación:
@@ -912,7 +1606,7 @@ Content-Type: application/json
}
```
-### 10.2 Control de Acceso
+### 9.2 Control de Acceso
#### Rutas Públicas:
- `/auth/login`
@@ -925,7 +1619,7 @@ Content-Type: application/json
#### Rutas Protegidas:
- Todo lo demás requiere `IS_AUTHENTICATED_FULLY`
-### 10.3 Roles de Usuario
+### 9.3 Roles de Usuario
Los roles se gestionan en la entidad `User`:
@@ -934,17 +1628,17 @@ $user->setRoles(['ROLE_USER']);
$user->setRoles(['ROLE_ADMIN']);
```
-### 10.4 Seguridad de Contraseñas
+### 9.4 Seguridad de Contraseñas
- Hashing con **bcrypt** automático
- Validación de fortaleza
- Cambio de contraseña seguro
-### 10.5 CORS (Cross-Origin Resource Sharing)
+### 9.5 CORS (Cross-Origin Resource Sharing)
Configurado en `nelmio_cors.yaml` para permitir acceso desde frontend.
-### 10.6 SSL/TLS
+### 9.6 SSL/TLS
Para producción, habilitar SSL:
@@ -956,9 +1650,9 @@ Configurar certificados en `/certs/`.
---
-## 11. Servicios Principales
+## 10. Servicios Principales
-### 11.1 CreatePartitionService
+### 10.1 CreatePartitionService
**Propósito**: Crear y actualizar particiones de clientes.
@@ -968,7 +1662,7 @@ Configurar certificados en `/certs/`.
- Detecta tipo de firmware (BIOS/UEFI)
- Calcula códigos de partición
-### 11.2 CreateTraceService
+### 10.2 CreateTraceService
**Propósito**: Crear trazas de ejecución para tareas programadas.
@@ -977,7 +1671,7 @@ Configurar certificados en `/certs/`.
- Gestiona comandos agrupados
- Establece estado inicial y fecha de ejecución
-### 11.3 ChangeClientNetworkSettingsService
+### 10.3 ChangeClientNetworkSettingsService
**Propósito**: Cambiar configuración de red de clientes.
@@ -985,7 +1679,7 @@ Configurar certificados en `/certs/`.
- Actualiza subnet, IP, configuración de red
- Sincroniza con servicios externos (DHCP)
-### 11.4 ExternalGitRepositoryService
+### 10.4 ExternalGitRepositoryService
**Propósito**: Gestión de repositorios Git para imágenes.
@@ -994,7 +1688,7 @@ Configurar certificados en `/certs/`.
- Versionado de imágenes
- Sincronización con repositorios remotos
-### 11.5 StatusService (OgBoot/OgDhcp/OgRepository)
+### 10.5 StatusService (OgBoot/OgDhcp/OgRepository)
**Propósito**: Verificar estado de servicios externos.
@@ -1003,7 +1697,7 @@ Configurar certificados en `/certs/`.
- Manejo de errores de conexión
- Logging de estado
-### 11.6 UDSClient
+### 10.6 UDSClient
**Propósito**: Integración con UDS (Universal Desktop Services).
@@ -1013,7 +1707,7 @@ Configurar certificados en `/certs/`.
- Cálculo de asientos disponibles
- Gestión de calendarios remotos
-### 11.7 Trace/CreateService
+### 10.7 Trace/CreateService
**Propósito**: Servicio especializado para creación de trazas.
@@ -1021,25 +1715,25 @@ Configurar certificados en `/certs/`.
- Validación de parámetros de entrada
- Creación de trazas individuales o masivas
-### 11.8 Utils/GetPartitionCodeService
+### 10.8 Utils/GetPartitionCodeService
**Propósito**: Obtener código de partición según tipo y filesystem.
-### 11.9 Utils/SimplifyOgLiveFilenameService
+### 10.9 Utils/SimplifyOgLiveFilenameService
**Propósito**: Simplificar nombres de archivos OgLive para mostrar al usuario.
-### 11.10 Utils/GetIpAddressAndNetmaskFromCIDRService
+### 10.10 Utils/GetIpAddressAndNetmaskFromCIDRService
**Propósito**: Convertir notación CIDR a IP y máscara de red.
---
-## 12. Comandos de Consola
+## 11. Comandos de Consola
ogCore incluye **18 comandos de consola** para tareas administrativas:
-### 12.1 Comandos de Inicialización
+### 11.1 Comandos de Inicialización
#### 12.1.1 Cargar Grupos de Usuario por Defecto
@@ -1089,7 +1783,7 @@ php bin/console app:load-organizational-unit-default
Crea la unidad organizativa raíz.
-### 12.2 Comandos de Operación
+### 11.2 Comandos de Operación
#### 12.2.1 Verificar Disponibilidad de Clientes
@@ -1121,7 +1815,7 @@ php bin/console app:run-scheduled-command-tasks
Ejecuta tareas programadas que han llegado a su hora de ejecución.
-### 12.3 Comandos de Migración
+### 11.3 Comandos de Migración
Comandos para migrar datos desde OpenGnsys 1.1:
@@ -1167,7 +1861,7 @@ php bin/console opengnsys:migration:software-profile
php bin/console opengnsys:migration:partition-client
```
-### 12.4 Comandos de Desarrollo
+### 11.4 Comandos de Desarrollo
#### 12.4.1 Crear Repositorios de Imágenes
@@ -1185,7 +1879,7 @@ php bin/console app:charge-example-trace
Carga trazas de ejemplo para testing.
-### 12.5 Configuración de Cron
+### 11.5 Configuración de Cron
Agregar al crontab:
@@ -1197,9 +1891,9 @@ Agregar al crontab:
---
-## 13. Migraciones de Datos
+## 12. Migraciones de Datos
-### 13.1 Sistema de Migraciones de Doctrine
+### 12.1 Sistema de Migraciones de Doctrine
ogCore utiliza Doctrine Migrations para gestionar cambios en el esquema de base de datos.
@@ -1227,7 +1921,7 @@ docker exec ogcore-php php bin/console doctrine:migrations:status
docker exec ogcore-php php bin/console doctrine:migrations:migrate prev
```
-### 13.2 Migración desde OpenGnsys 1.1
+### 12.2 Migración desde OpenGnsys 1.1
Para migrar datos desde una instalación de OpenGnsys 1.1:
@@ -1256,7 +1950,7 @@ docker exec ogcore-php php bin/console opengnsys:migration:image
docker exec ogcore-php php bin/console opengnsys:migration:software-profile
```
-### 13.3 Backup y Restauración
+### 12.3 Backup y Restauración
#### 13.3.1 Backup de Base de Datos
@@ -1272,13 +1966,13 @@ docker exec -i ogcore-database mysql -u user -p ogcore < backup_20251008.sql
---
-## 14. Testing
+## 13. Testing
-### 14.1 Framework de Testing
+### 13.1 Framework de Testing
ogCore utiliza **PHPUnit** con integración de Symfony y Doctrine.
-### 14.2 Ejecutar Tests
+### 13.2 Ejecutar Tests
#### 14.2.1 Todos los Tests
@@ -1298,7 +1992,7 @@ docker compose exec php bin/phpunit tests/Functional/ClientTest.php
docker compose exec php bin/phpunit --coverage-html coverage/
```
-### 14.3 Tipos de Tests
+### 13.3 Tipos de Tests
#### 14.3.1 Tests Funcionales
@@ -1327,7 +2021,7 @@ public function testCreateClient(): void
}
```
-### 14.4 Factories para Testing
+### 13.4 Factories para Testing
Se utilizan **Zenstruck Foundry** factories (24 factories) para crear datos de prueba:
@@ -1338,7 +2032,7 @@ ClientFactory::createOne([
]);
```
-### 14.5 Base de Datos de Testing
+### 13.5 Base de Datos de Testing
Los tests utilizan **DAMA Doctrine Test Bundle** para:
- Ejecutar cada test en una transacción
@@ -1347,9 +2041,9 @@ Los tests utilizan **DAMA Doctrine Test Bundle** para:
---
-## 15. Despliegue
+## 14. Despliegue
-### 15.1 Despliegue con Docker Compose
+### 14.1 Despliegue con Docker Compose
#### 15.1.1 Desarrollo
@@ -1363,7 +2057,7 @@ docker compose up -d
docker compose -f docker-compose-deploy.yml up -d
```
-### 15.2 Despliegue con Jenkins
+### 14.2 Despliegue con Jenkins
El proyecto incluye **Jenkinsfile** para CI/CD.
@@ -1374,7 +2068,7 @@ El proyecto incluye **Jenkinsfile** para CI/CD.
4. **Package**: Crear paquete Debian
5. **Deploy**: Desplegar en servidor
-### 15.3 Paquete Debian
+### 14.3 Paquete Debian
El proyecto puede empaquetarse como `.deb`:
@@ -1388,7 +2082,7 @@ Estructura del paquete en `debian/`:
- Systemd service file
- Configuración
-### 15.4 Configuración de Producción
+### 14.4 Configuración de Producción
#### 15.4.1 Variables de Entorno
@@ -1414,7 +2108,7 @@ docker exec ogcore-php php bin/console cache:warmup --env=prod
docker exec ogcore-php composer dump-autoload --optimize --classmap-authoritative
```
-### 15.5 Monitoreo
+### 14.5 Monitoreo
#### 15.5.1 Logs
@@ -1427,7 +2121,7 @@ Logs ubicados en `var/log/`:
Los logs también se envían a syslog para centralización.
-### 15.6 Escalabilidad
+### 14.6 Escalabilidad
Para escalar horizontalmente:
@@ -1439,9 +2133,9 @@ Para escalar horizontalmente:
---
-## 16. Mantenimiento y Operaciones
+## 15. Mantenimiento y Operaciones
-### 16.1 Reiniciar Base de Datos
+### 15.1 Reiniciar Base de Datos
```bash
docker exec ogcore-php php bin/console doctrine:database:drop --force
@@ -1450,26 +2144,26 @@ docker exec ogcore-php php bin/console doctrine:migrations:migrate --no-interact
docker exec ogcore-php php bin/console doctrine:fixtures:load --no-interaction
```
-### 16.2 Limpiar Caché
+### 15.2 Limpiar Caché
```bash
docker exec ogcore-php php bin/console cache:clear
docker exec ogcore-php php bin/console cache:warmup
```
-### 16.3 Actualizar Dependencias
+### 15.3 Actualizar Dependencias
```bash
docker exec ogcore-php composer update
```
-### 16.4 Regenerar Claves JWT
+### 15.4 Regenerar Claves JWT
```bash
docker exec ogcore-php php bin/console lexik:jwt:generate-keypair --overwrite
```
-### 16.5 Backups Automáticos
+### 15.5 Backups Automáticos
Script ejemplo para backup automático:
@@ -1489,7 +2183,7 @@ find $BACKUP_DIR -name "*.sql" -mtime +30 -delete
find $BACKUP_DIR -name "*.tar.gz" -mtime +30 -delete
```
-### 16.6 Monitoreo de Salud
+### 15.6 Monitoreo de Salud
#### Health Check Endpoint
@@ -1510,7 +2204,7 @@ docker exec ogcore-nginx nginx -t
docker exec ogcore-database mysqladmin -u user -p status
```
-### 16.7 Rotación de Logs
+### 15.7 Rotación de Logs
Configurar logrotate:
@@ -1528,9 +2222,9 @@ Configurar logrotate:
---
-## 17. Integración con Otros Servicios
+## 16. Integración con Otros Servicios
-### 17.1 ogRepository
+### 16.1 ogRepository
**Propósito**: Gestión de repositorios de imágenes.
@@ -1546,7 +2240,7 @@ Configurar logrotate:
**Webhook**: `/og-repository/webhook`
-### 17.2 ogDhcp
+### 16.2 ogDhcp
**Propósito**: Gestión de DHCP dinámico.
@@ -1556,7 +2250,7 @@ Configurar logrotate:
- Actualizar configuración
- Gestión de subredes
-### 17.3 ogBoot
+### 16.3 ogBoot
**Propósito**: Gestión de archivos de arranque PXE.
@@ -1566,7 +2260,7 @@ Configurar logrotate:
- Eliminar configuraciones
- Sincronización de menús
-### 17.4 ogAgent
+### 16.4 ogAgent
**Propósito**: Agente instalado en clientes para ejecutar comandos.
@@ -1579,7 +2273,7 @@ Configurar logrotate:
- Verificar tamaño de particiones
- Kill jobs
-### 17.5 UDS (Universal Desktop Services)
+### 16.5 UDS (Universal Desktop Services)
**Propósito**: Integración con sistema de escritorios remotos.
@@ -1589,7 +2283,7 @@ Configurar logrotate:
- Calcular disponibilidad
- Gestión de reservas
-### 17.6 Git (Versionado de Imágenes)
+### 16.6 Git (Versionado de Imágenes)
**Propósito**: Versionado de imágenes con Git.
@@ -1599,7 +2293,7 @@ Configurar logrotate:
- Recuperación de versiones
- Sincronización
-### 17.7 Mercure (Notificaciones en Tiempo Real)
+### 16.7 Mercure (Notificaciones en Tiempo Real)
**Propósito**: Notificaciones push en tiempo real.
@@ -1621,11 +2315,11 @@ eventSource.onmessage = event => {
---
-## 18. Roadmap y Changelog
+## 17. Roadmap y Changelog
-### 18.1 Versión Actual: 0.5.0
+### 17.1 Versión Actual: 0.5.0
-### 18.2 Últimas Características (v0.25.1 - Octubre 2025)
+### 17.2 Últimas Características (v0.25.1 - Octubre 2025)
- **Tareas programadas**: Sistema completo de colas y scheduling
- **Inventario hardware**: Obtención automática de inventario
@@ -1640,7 +2334,7 @@ eventSource.onmessage = event => {
- **Mercure**: Notificaciones en tiempo real
- **Despliegue multicast**: Modos torrent y UDPCAST
-### 18.3 Próximas Características (Roadmap)
+### 17.3 Próximas Características (Roadmap)
#### v0.6.0 (Q4 2025)
- [ ] Dashboard de administración mejorado
@@ -1660,7 +2354,7 @@ eventSource.onmessage = event => {
- [ ] Guías de migración finalizadas
- [ ] Certificación de seguridad
-### 18.4 Changelog Resumido
+### 17.4 Changelog Resumido
Ver `CHANGELOG.md` para el historial completo de cambios.
@@ -1683,9 +2377,9 @@ Ver `CHANGELOG.md` para el historial completo de cambios.
---
-## 19. Contribución
+## 18. Contribución
-### 19.1 Guía de Contribución
+### 18.1 Guía de Contribución
Para contribuir al proyecto:
@@ -1695,7 +2389,7 @@ Para contribuir al proyecto:
4. **Push** a la rama: `git push origin feature/nueva-funcionalidad`
5. Crea un **Pull Request**
-### 19.2 Estándares de Código
+### 18.2 Estándares de Código
- Seguir **PSR-12** para PHP
- Usar **Type Hints** en PHP 8.3
@@ -1703,7 +2397,7 @@ Para contribuir al proyecto:
- Tests para nuevas funcionalidades
- Commits descriptivos en español
-### 19.3 Proceso de Revisión
+### 18.3 Proceso de Revisión
1. CI/CD ejecuta tests automáticamente
2. Revisión de código por maintainers
@@ -1711,7 +2405,7 @@ Para contribuir al proyecto:
4. Merge a rama develop
5. Release periódicos a main
-### 19.4 Reportar Bugs
+### 18.4 Reportar Bugs
Usar el sistema de Issues del repositorio:
@@ -1739,25 +2433,25 @@ Si aplica, añadir screenshots.
---
-## 20. Soporte y Contacto
+## 19. Soporte y Contacto
-### 20.1 Documentación Adicional
+### 19.1 Documentación Adicional
- **API Docs**: http://localhost:8080/docs
- **Postman Collection**: `swagger-assets/ogCore.postman_collection.zip`
- **Diagramas**: `swagger-assets/img_bbdd.png`
-### 20.2 Recursos
+### 19.2 Recursos
- **Repositorio**: [URL del repositorio]
- **Wiki**: [URL de la wiki]
- **Issues**: [URL de issues]
-### 20.3 Equipo de Desarrollo
+### 19.3 Equipo de Desarrollo
Proyecto desarrollado por el equipo de OpenGnsys en colaboración con universidades participantes.
-### 20.4 Licencia
+### 19.4 Licencia
Proyecto propietario. Ver archivo `LICENSE` para más información.
diff --git a/migrations/Version20251015080216.php b/migrations/Version20251015080216.php
new file mode 100644
index 0000000..8592658
--- /dev/null
+++ b/migrations/Version20251015080216.php
@@ -0,0 +1,31 @@
+addSql('ALTER TABLE client ADD resolution VARCHAR(255) DEFAULT NULL');
+ }
+
+ public function down(Schema $schema): void
+ {
+ // this down() migration is auto-generated, please modify it to your needs
+ $this->addSql('ALTER TABLE client DROP resolution');
+ }
+}
diff --git a/ogCore_Documentacion_Tecnica.html b/ogCore_Documentacion_Tecnica.html
index 6ccf54d..5c7c6b4 100644
--- a/ogCore_Documentacion_Tecnica.html
+++ b/ogCore_Documentacion_Tecnica.html
@@ -177,10 +177,10 @@ class="toc-section-number">1.6.3 5.3 Puertos Requeridos
id="toc-instalación-y-configuración">1.7 6. Instalación y Configuración
-1.8 7. Modelo de Datos
-
1.9 8. Componentes del Sistema
+class="toc-section-number">1.8 7. Componentes del Sistema
1.10 9. API RESTful
+class="toc-section-number">1.9 8. API RESTful
1.10.2 9.2 Formato de
+class="toc-section-number">1.9.2 8.2 Formato de
Respuestas
1.10.3 9.3 Paginación
+class="toc-section-number">1.9.3 8.3 Paginación
1.10.4 9.4 Filtrado
+class="toc-section-number">1.9.4 8.4 Filtrado
1.10.5 9.5 Ordenamiento
+class="toc-section-number">1.9.5 8.5 Ordenamiento
1.10.6 9.6 Endpoints
+class="toc-section-number">1.9.6 8.6 Endpoints
Principales
1.10.7 9.7 Códigos de Estado
+class="toc-section-number">1.9.7 8.7 Códigos de Estado
HTTP
1.11 10. Seguridad y Autenticación
+class="toc-section-number">1.10 9. Seguridad y Autenticación
1.11.3 10.3 Roles de Usuario
+class="toc-section-number">1.10.3 9.3 Roles de Usuario
1.11.4 10.4 Seguridad de
+class="toc-section-number">1.10.4 9.4 Seguridad de
Contraseñas
1.11.5 10.5 CORS (Cross-Origin
-Resource Sharing)
+class="toc-section-number">1.10.5 9.5 CORS (Cross-Origin Resource
+Sharing)
1.11.6 10.6 SSL/TLS
+class="toc-section-number">1.10.6 9.6 SSL/TLS
1.12 11. Servicios Principales
+class="toc-section-number">1.11 10. Servicios Principales
1.12.7 11.7
+class="toc-section-number">1.11.7 10.7
Trace/CreateService
1.12.8 11.8
+class="toc-section-number">1.11.8 10.8
Utils/GetPartitionCodeService
1.12.9 11.9
+class="toc-section-number">1.11.9 10.9
Utils/SimplifyOgLiveFilenameService
1.12.10 11.10
+class="toc-section-number">1.11.10 10.10
Utils/GetIpAddressAndNetmaskFromCIDRService
1.13 12. Comandos de Consola
+class="toc-section-number">1.12 11. Comandos de Consola
1.14 13. Migraciones de Datos
+class="toc-section-number">1.13 12. Migraciones de Datos
1.15 14. Testing
+class="toc-section-number">1.14 13. Testing
1.15.3 14.3 Tipos de Tests
+class="toc-section-number">1.14.3 13.3 Tipos de Tests
1.15.4 14.4 Factories para
+class="toc-section-number">1.14.4 13.4 Factories para
Testing
1.15.5 14.5 Base de Datos de
+class="toc-section-number">1.14.5 13.5 Base de Datos de
Testing
1.16 15. Despliegue
+class="toc-section-number">1.15 14. Despliegue
1.16.4 15.4 Configuración de
+class="toc-section-number">1.15.4 14.4 Configuración de
Producción
1.16.5 15.5 Monitoreo
+class="toc-section-number">1.15.5 14.5 Monitoreo
1.16.6 15.6 Escalabilidad
+class="toc-section-number">1.15.6 14.6 Escalabilidad
1.17 16. Mantenimiento y
+class="toc-section-number">1.16 15. Mantenimiento y
Operaciones
1.17.3 16.3 Actualizar
+class="toc-section-number">1.16.3 15.3 Actualizar
Dependencias
1.17.4 16.4 Regenerar Claves
+class="toc-section-number">1.16.4 15.4 Regenerar Claves
JWT
1.17.5 16.5 Backups
+class="toc-section-number">1.16.5 15.5 Backups
Automáticos
1.17.6 16.6 Monitoreo de
+class="toc-section-number">1.16.6 15.6 Monitoreo de
Salud
1.17.7 16.7 Rotación de Logs
+class="toc-section-number">1.16.7 15.7 Rotación de Logs
1.18 17. Integración con Otros
+class="toc-section-number">1.17 16. Integración con Otros
Servicios
1.18.2 17.2 ogDhcp
+class="toc-section-number">1.17.2 16.2 ogDhcp
1.18.3 17.3 ogBoot
+class="toc-section-number">1.17.3 16.3 ogBoot
1.18.4 17.4 ogAgent
+class="toc-section-number">1.17.4 16.4 ogAgent
1.18.5 17.5 UDS (Universal Desktop
+class="toc-section-number">1.17.5 16.5 UDS (Universal Desktop
Services)
1.18.6 17.6 Git (Versionado de
+class="toc-section-number">1.17.6 16.6 Git (Versionado de
Imágenes)
1.18.7 17.7 Mercure (Notificaciones en
+class="toc-section-number">1.17.7 16.7 Mercure (Notificaciones en
Tiempo Real)
1.19 18. Roadmap y Changelog
+class="toc-section-number">1.18 17. Roadmap y Changelog
1.20 19. Contribución
+class="toc-section-number">1.19 18. Contribución
1.21 20. Soporte y Contacto
+class="toc-section-number">1.20 19. Soporte y Contacto
1.21.3 20.3 Equipo de
+class="toc-section-number">1.20.3 19.3 Equipo de
Desarrollo
1.21.4 20.4 Licencia
+class="toc-section-number">1.20.4 19.4 Licencia
1.22 Apéndices
+class="toc-section-number">1.21 Apéndices
@@ -541,24 +525,23 @@ Sistema
Requisitos del Sistema
Instalación y
Configuración
-Modelo de Datos
-Componentes del
+Componentes del
Sistema
-API RESTful
-Seguridad y
+API RESTful
+Seguridad y
Autenticación
-Servicios Principales
-Comandos de Consola
-Migraciones de Datos
-Testing
-Despliegue
-Mantenimiento y
+Servicios Principales
+Comandos de Consola
+Migraciones de Datos
+Testing
+Despliegue
+Mantenimiento y
Operaciones
-Integración con Otros
+Integración con Otros
Servicios
-Roadmap y Changelog
-Contribución
-Soporte y Contacto
+Roadmap y Changelog
+Contribución
+Soporte y Contacto
Sistema de colas para la ejecución de tareas
programadas
Integración con múltiples servicios externos
-Migraciones automatizadas desde OpenGnsys 1.1
-Versionado de imágenes con integración Git
+Creación de imágenes con integración Git y sistema
+monolítico
Sistema de trazabilidad completo
Gestión de hardware con inventario automático
Despliegues masivos de imágenes (unicast,
@@ -629,7 +612,7 @@ multicast, torrent, p2p)
2.3 Versión Actual
-- Versión: 0.5.0
+- Versión: 1.0.0
- Estado: En desarrollo activo
- Última actualización: Octubre 2025
@@ -641,35 +624,35 @@ Sistema
class="header-section-number">1.4.1 3.1 Arquitectura General
ogCore sigue una arquitectura de microservicios
basada en el patrón API-First:
-┌─────────────────────────────────────────────────────────────┐
-│ Frontend (Web UI) │
-└────────────────────────┬────────────────────────────────────┘
- │
- │ HTTP/REST
- │
-┌────────────────────────▼────────────────────────────────────┐
-│ ogCore API (Symfony) │
-│ ┌──────────────────────────────────────────────────────┐ │
-│ │ Controllers │ States │ DTOs │ Validators │ Filters │ │
-│ └──────────────────────────────────────────────────────┘ │
-│ ┌──────────────────────────────────────────────────────┐ │
-│ │ Business Logic (Services) │ │
-│ └──────────────────────────────────────────────────────┘ │
-│ ┌──────────────────────────────────────────────────────┐ │
-│ │ Entities │ Repositories │ Doctrine ORM │ │
-│ └──────────────────────────────────────────────────────┘ │
-└────────────────────┬───────────────┬───────────────────────┘
- │ │
- ┌───────────▼──┐ ┌──────▼──────┐
- │ MariaDB │ │ Mercure │
- │ Database │ │ (WebSocket)│
- └──────────────┘ └─────────────┘
++-------------------------------------------------------------+
+| Frontend (Web UI) |
++---------------------------+----------------------------------+
+ |
+ | HTTP/REST
+ |
++---------------------------v---------------------------------+
+| ogCore API (Symfony) |
+| +------------------------------------------------------+ |
+| | Controllers | States | DTOs | Validators | Filters | |
+| +------------------------------------------------------+ |
+| +------------------------------------------------------+ |
+| | Business Logic (Services) | |
+| +------------------------------------------------------+ |
+| +------------------------------------------------------+ |
+| | Entities | Repositories | Doctrine ORM | |
+| +------------------------------------------------------+ |
++---------------------------+----------------+----------------+
+ | |
+ +------------------v--+ +--------v--------+
+ | MariaDB | | Mercure |
+ | Database | | (WebSocket) |
+ +---------------------+ +-----------------+
-┌─────────────────────────────────────────────────────────────┐
-│ Servicios Externos Integrados │
-├──────────────┬──────────────┬──────────────┬────────────────┤
-│ ogRepository│ ogDhcp │ ogBoot │ UDS/Git │
-└──────────────┴──────────────┴──────────────┴────────────────┘
++-------------------------------------------------------------+
+| Servicios Externos Integrados |
++--------------+--------------+--------------+----------------+
+| ogRepository | ogDhcp | ogBoot | UDS/Git |
++--------------+--------------+--------------+----------------+
3.2 Capas de la
Aplicación
@@ -989,9 +972,9 @@ class="header-section-number">1.6.3 5.3 Puertos Requeridos
6. Instalación y
Configuración
-1.7.1 6.1 Instalación con Docker
-(Recomendado)
+1.7.1 6.1 Instalación con
+Docker
6.1.1 Clonar el
Repositorio
@@ -1103,209 +1086,15 @@ Configurar SSL/TLS - Configurar backups automáticos de base de datos -
Configurar monitoreo y alertas - Revisar los límites de recursos de
Docker
-1.8 7. Modelo de Datos
-1.8.1 7.1 Diagrama de
-Entidades
-El sistema cuenta con 35 entidades principales agrupadas en los
-siguientes dominios:
-1.8.2 7.2 Entidades
-Principales
-1.8.2.1 7.2.1 Client (Cliente)
-Representa un equipo físico en el sistema.
-Campos principales: - id
: UUID único -
-name
: Nombre del cliente - serialNumber
:
-Número de serie - mac
: Dirección MAC (única) -
-ip
: Dirección IP (única) - status
: Estado del
-cliente (active, inactive, busy, windows, linux, etc.) -
-netiface
: Interfaz de red - netDriver
: Driver
-de red - validation
: Estado de validación -
-maintenance
: Modo mantenimiento - position
:
-Posición en el aula (x, y) - firmwareType
: Tipo de firmware
-(BIOS/UEFI) - agentJobId
: ID del trabajo del agente en
-ejecución - pxeSync
: Sincronización PXE -
-token
: Token de autenticación del cliente
-Relaciones: - organizationalUnit
:
-Pertenece a una unidad organizativa (aula/grupo) -
-partitions
: Tiene múltiples particiones -
-menu
: Menú de arranque asignado -
-hardwareProfile
: Perfil de hardware asociado -
-template
: Plantilla PXE asignada - repository
:
-Repositorio de imágenes - subnet
: Subred a la que pertenece
-- ogLive
: Imagen Live asignada
-1.8.2.2 7.2.2 OrganizationalUnit
-(Unidad Organizativa)
-Representa aulas o grupos de equipos.
-Campos principales: - id
: UUID único -
-name
: Nombre de la unidad - description
:
-Descripción - type
: Tipo (aula, grupo, etc.)
-Relaciones: - parent
: Unidad
-organizativa padre (jerarquía) - children
: Unidades hijas -
-clients
: Clientes pertenecientes -
-networkSettings
: Configuración de red heredable -
-remoteCalendar
: Calendario remoto asociado
-1.8.2.3 7.2.3 Image (Imagen)
-Representa una imagen de sistema operativo.
-Campos principales: - id
: UUID único -
-name
: Nombre de la imagen - description
:
-Descripción - type
: Tipo de imagen - size
:
-Tamaño en bytes - partition
: Partición de origen -
-status
: Estado (creating, success, failed, etc.) -
-isGlobal
: Imagen global compartida -
-isVirtual
: Imagen virtual - version
: Versión
-de la imagen
-Relaciones: - operativeSystem
: Sistema
-operativo - softwareProfile
: Perfil de software -
-repositories
: Repositorios que contienen la imagen -
-originClient
: Cliente origen de la imagen
-1.8.2.4 7.2.4 Command
-(Comando)
-Comandos ejecutables en el sistema.
-Campos principales: - id
: UUID único -
-name
: Nombre del comando - description
:
-Descripción - script
: Script a ejecutar
-Relaciones: - commandGroups
: Grupos de
-comandos a los que pertenece
-1.8.2.5 7.2.5 CommandTask (Tarea de
-Comando)
-Tarea programada para ejecutar comandos.
-Campos principales: - id
: UUID único -
-datetime
: Fecha y hora de ejecución -
-parameters
: Parámetros de ejecución - status
:
-Estado de la tarea
-Relaciones: - commands
: Comandos a
-ejecutar - commandGroups
: Grupos de comandos -
-clients
: Clientes objetivo - schedule
:
-Programación recurrente
-1.8.2.6 7.2.6 Trace (Traza)
-Registro de ejecución de comandos.
-Campos principales: - id
: UUID único -
-command
: Nombre del comando ejecutado - input
:
-Parámetros de entrada - output
: Resultado de ejecución -
-status
: Estado (pending, processing, success, failed,
-cancelled) - executedAt
: Fecha de ejecución -
-finishedAt
: Fecha de finalización - cancelled
:
-Indica si fue cancelada - jobId
: ID del trabajo en el
-agente
-Relaciones: - client
: Cliente donde se
-ejecutó
-1.8.2.7 7.2.7 HardwareProfile
-(Perfil de Hardware)
-Inventario de hardware de un cliente.
-Campos principales: - id
: UUID único -
-cpu
: Información de CPU - ram
: Memoria RAM -
-storage
: Almacenamiento - networkCards
:
-Tarjetas de red
-Relaciones: - client
: Cliente asociado
-- hardwareTypes
: Tipos de hardware detectados
-1.8.2.8 7.2.8 SoftwareProfile
-(Perfil de Software)
-Software instalado en una imagen.
-Campos principales: - id
: UUID único -
-name
: Nombre del perfil
-Relaciones: - software
: Software
-incluido - images
: Imágenes que usan este perfil
-1.8.2.9 7.2.9 ImageRepository
-(Repositorio de Imágenes)
-Servidor de almacenamiento de imágenes.
-Campos principales: - id
: UUID único -
-name
: Nombre del repositorio (único) - ip
:
-Dirección IP o DNS (único) - port
: Puerto -
-sshPort
: Puerto SSH - sshUser
: Usuario SSH -
-apiKey
: Clave API - status
: Estado del
-repositorio
-Relaciones: - images
: Imágenes
-almacenadas
-1.8.2.10 7.2.10 Subnet
-(Subred)
-Configuración de red.
-Campos principales: - id
: UUID único -
-name
: Nombre de la subred - cidr
: Notación
-CIDR - gateway
: Puerta de enlace - dns
:
-Servidores DNS - dhcpStart
: Inicio rango DHCP -
-dhcpEnd
: Fin rango DHCP
-Relaciones: - clients
: Clientes en la
-subred
-1.8.2.11 7.2.11 Partition
-(Partición)
-Partición de disco de un cliente.
-Campos principales: - id
: UUID único -
-partitionNumber
: Número de partición -
-partitionType
: Tipo de partición -
-partitionSize
: Tamaño - partitionCode
: Código
-de partición - usedSize
: Tamaño usado -
-filesystem
: Sistema de archivos
-Relaciones: - client
: Cliente
-propietario - image
: Imagen desplegada -
-operativeSystem
: Sistema operativo instalado
-1.8.2.12 7.2.12 PxeTemplate
-(Plantilla PXE)
-Plantilla de arranque PXE.
-Campos principales: - id
: UUID único -
-name
: Nombre de la plantilla - content
:
-Contenido de la plantilla - default
: Plantilla por
-defecto
-Relaciones: - clients
: Clientes que
-usan la plantilla
-1.8.2.13 7.2.13 RemoteCalendar
-(Calendario Remoto)
-Integración con sistemas de reservas remotas.
-Campos principales: - id
: UUID único -
-name
: Nombre del calendario - url
: URL del
-servicio - available
: Disponibilidad
-Relaciones: - organizationalUnits
:
-Unidades organizativas asociadas - rules
: Reglas del
-calendario
-1.8.2.14 7.2.14 User (Usuario)
-Usuario del sistema.
-Campos principales: - id
: UUID único -
-username
: Nombre de usuario (único) -
-password
: Contraseña (hasheada) - email
:
-Correo electrónico - roles
: Roles del usuario
-Relaciones: - userGroups
: Grupos de
-usuarios - view
: Vista preferida
-1.8.2.15 7.2.15 GitRepository
-(Repositorio Git)
-Repositorio Git para versionado de imágenes.
-Campos principales: - id
: UUID único -
-name
: Nombre del repositorio - url
: URL del
-repositorio - branch
: Rama - credentials
:
-Credenciales de acceso
-1.8.3 7.3 Índices y
-Optimizaciones
-La base de datos está optimizada con índices en: - Campos de búsqueda
-frecuente (status, updatedAt) - Campos únicos (IP, MAC, username) -
-Claves foráneas - Índices compuestos para consultas complejas
-
-1.9 8. Componentes del Sistema
-1.9.1 8.1 Controllers
+1.8 7. Componentes del Sistema
+1.8.1 7.1 Controllers
(Controladores)
El sistema cuenta con 102 controladores organizados
por dominio:
-1.9.1.1 Controladores
+1.8.1.1 Controladores
principales:
- ClientController: Gestión de clientes
@@ -1318,61 +1107,61 @@ organizativas
- SubnetController: Gestión de subredes
- RepositoryController: Gestión de repositorios
-1.9.2 8.2 States (Procesadores de
+1.8.2 7.2 States (Procesadores de
Estado)
Los States implementan el patrón State de API Platform:
-1.9.2.1 States principales (55
+1.8.2.1 States principales (55
procesadores):
- Providers: Obtención de datos
- Processors: Procesamiento de escritura
- Custom States: Lógica personalizada
-1.9.3 8.3 DTOs (Data Transfer
+1.8.3 7.3 DTOs (Data Transfer
Objects)
93 DTOs para transferencia de datos:
-1.9.3.1 Tipos de DTOs:
+1.8.3.1 Tipos de DTOs:
- Input DTOs: Para recepción de datos
- Output DTOs: Para envío de datos
- Transformation DTOs: Para transformaciones
-1.9.4 8.4 Validators
+1.8.4 7.4 Validators
(Validadores)
18 validadores personalizados para: - Validación de
IPs y MACs - Validación de rangos DHCP - Validación de particiones -
Validación de imágenes - Validación de comandos - Validación de
usuarios
-1.9.5 8.5 EventSubscribers
+class="header-section-number">1.8.5 7.5 EventSubscribers
(Suscriptores de Eventos)
8 suscriptores para: - Publicación en Mercure al
cambiar estados - Limpieza de recursos - Validaciones pre/post
persistencia - Logging de eventos
-1.9.6 8.6 Factories (Fábricas)
+1.8.6 7.6 Factories (Fábricas)
24 factories para testing con Foundry: - Creación de
entidades para tests - Datos de prueba realistas - Estados
predefinidos
-1.10 9. API RESTful
-1.10.1 9.1 Documentación
+1.9 8. API RESTful
+1.9.1 8.1 Documentación
La API está completamente documentada con OpenAPI
3.0 y accesible en:
http://127.0.0.1:8080/docs
-Todas las colecciones soportan paginación:
GET /clients?page=1&itemsPerPage=30
Respuesta:
@@ -1416,25 +1205,25 @@ class="sourceCode json"> "hydra:next": "/clients?page=2"
}
}
-1.10.4 9.4 Filtrado
+1.9.4 8.4 Filtrado
Soporta filtros avanzados:
GET /clients?status=active
GET /clients?organizationalUnit.name=Aula1
GET /traces?client.id=123&status=pending
-1.10.5 9.5 Ordenamiento
+1.9.5 8.5 Ordenamiento
GET /clients?order[name]=asc
GET /traces?order[createdAt]=desc
-1.10.6 9.6 Endpoints
+1.9.6 8.6 Endpoints
Principales
-1.10.6.1 9.6.1 Autenticación
+1.9.6.1 9.6.1 Autenticación
POST /auth/login
POST /auth/refresh
-1.10.6.2 9.6.2 Clientes
+1.9.6.2 9.6.2 Clientes
GET /clients
POST /clients
GET /clients/{id}
@@ -1445,8 +1234,8 @@ POST /clients/batch
POST /clients/{id}/power-on
POST /clients/{id}/power-off
POST /clients/{id}/reboot
-1.10.6.3 9.6.3 Imágenes
+1.9.6.3 9.6.3 Imágenes
GET /images
POST /images
GET /images/{id}
@@ -1455,8 +1244,8 @@ DELETE /images/{id}
POST /images/{id}/deploy
POST /images/{id}/create
POST /images/{id}/backup
-1.10.6.4 9.6.4 Comandos y
+1.9.6.4 9.6.4 Comandos y
Tareas
GET /commands
POST /commands
@@ -1464,15 +1253,15 @@ GET /command-tasks
POST /command-tasks
PUT /command-tasks/{id}
DELETE /command-tasks/{id}
-1.10.6.5 9.6.5 Trazas
+1.9.6.5 9.6.5 Trazas
GET /traces
GET /traces/{id}
PUT /traces/{id}
PATCH /traces/{id}/complete
PATCH /traces/{id}/cancel
-1.10.7 9.7 Códigos de Estado
+1.9.7 8.7 Códigos de Estado
HTTP
@@ -1525,16 +1314,16 @@ HTTP
-1.11 10. Seguridad y
+1.10 9. Seguridad y
Autenticación
-1.11.1 10.1 Sistema de
-Autenticación JWT
+1.10.1 9.1 Sistema de Autenticación
+JWT
ogCore utiliza JSON Web Tokens (JWT) para
autenticación:
-1.11.1.1 10.1.1 Obtener Token
+1.10.1.1 10.1.1 Obtener Token
POST /auth/login
Content-Type: application/json
@@ -1549,14 +1338,14 @@ class="sourceCode json"> "token": "eyJ0eXAiOiJKV1QiLCJhbGc...",
"refresh_token": "def50200a54b7b..."
}
-1.11.1.2 10.1.2 Usar Token
+1.10.1.2 10.1.2 Usar Token
Incluir el token en el header Authorization
:
GET /clients
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGc...
-1.11.1.3 10.1.3 Refresh Token
+1.10.1.3 10.1.3 Refresh Token
POST /auth/refresh
Content-Type: application/json
@@ -1564,10 +1353,10 @@ class="sourceCode bash">{
"refresh_token": "def50200a54b7b..."
}
-1.11.2 10.2 Control de Acceso
-1.11.2.1 Rutas Públicas:
+1.10.2 9.2 Control de Acceso
+1.10.2.1 Rutas Públicas:
/auth/login
/auth/refresh
@@ -1576,236 +1365,236 @@ class="header-section-number">1.11.2.1 Rutas Públicas:
/og-repository/webhook
/menu-browser
-1.11.2.2 Rutas Protegidas:
+1.10.2.2 Rutas Protegidas:
- Todo lo demás requiere
IS_AUTHENTICATED_FULLY
-1.11.3 10.3 Roles de Usuario
+1.10.3 9.3 Roles de Usuario
Los roles se gestionan en la entidad User
:
$user->setRoles(['ROLE_USER']);
$user->setRoles(['ROLE_ADMIN']);
-1.11.4 10.4 Seguridad de
+1.10.4 9.4 Seguridad de
Contraseñas
- Hashing con bcrypt automático
- Validación de fortaleza
- Cambio de contraseña seguro
-1.11.5 10.5 CORS (Cross-Origin
+1.10.5 9.5 CORS (Cross-Origin
Resource Sharing)
Configurado en nelmio_cors.yaml
para permitir acceso
desde frontend.
-1.11.6 10.6 SSL/TLS
+1.10.6 9.6 SSL/TLS
Para producción, habilitar SSL:
Configurar certificados en /certs/
.
-1.12 11. Servicios Principales
-1.12.1 11.1
+1.11 10. Servicios Principales
+1.11.1 10.1
CreatePartitionService
Propósito: Crear y actualizar particiones de
clientes.
Funcionalidad: - Recibe información de particiones
del agente - Crea/actualiza particiones en base de datos - Detecta tipo
de firmware (BIOS/UEFI) - Calcula códigos de partición
-1.12.2 11.2 CreateTraceService
+1.11.2 10.2 CreateTraceService
Propósito: Crear trazas de ejecución para tareas
programadas.
Funcionalidad: - Genera trazas para cada combinación
cliente-comando - Gestiona comandos agrupados - Establece estado inicial
y fecha de ejecución
-1.12.3 11.3
+1.11.3 10.3
ChangeClientNetworkSettingsService
Propósito: Cambiar configuración de red de
clientes.
Funcionalidad: - Actualiza subnet, IP, configuración
de red - Sincroniza con servicios externos (DHCP)
-1.12.4 11.4
+1.11.4 10.4
ExternalGitRepositoryService
Propósito: Gestión de repositorios Git para
imágenes.
Funcionalidad: - Backup de imágenes a Git -
Versionado de imágenes - Sincronización con repositorios remotos
-1.12.5 11.5 StatusService
+class="header-section-number">1.11.5 10.5 StatusService
(OgBoot/OgDhcp/OgRepository)
Propósito: Verificar estado de servicios
externos.
Funcionalidad: - Health checks de servicios - Manejo
de errores de conexión - Logging de estado
-1.12.6 11.6 UDSClient
+1.11.6 10.6 UDSClient
Propósito: Integración con UDS (Universal Desktop
Services).
Funcionalidad: - Autenticación con UDS - Obtención
de service pools - Cálculo de asientos disponibles - Gestión de
calendarios remotos
-1.12.7 11.7
+1.11.7 10.7
Trace/CreateService
Propósito: Servicio especializado para creación de
trazas.
Funcionalidad: - Validación de parámetros de entrada
- Creación de trazas individuales o masivas
-1.12.8 11.8
+1.11.8 10.8
Utils/GetPartitionCodeService
Propósito: Obtener código de partición según tipo y
filesystem.
-1.12.9 11.9
+1.11.9 10.9
Utils/SimplifyOgLiveFilenameService
Propósito: Simplificar nombres de archivos OgLive
para mostrar al usuario.
-1.12.10 11.10
+class="header-section-number">1.11.10 10.10
Utils/GetIpAddressAndNetmaskFromCIDRService
Propósito: Convertir notación CIDR a IP y máscara de
red.
-1.13 12. Comandos de Consola
+1.12 11. Comandos de Consola
ogCore incluye 18 comandos de consola para tareas
administrativas:
-1.13.1 12.1 Comandos de
+1.12.1 11.1 Comandos de
Inicialización
-1.13.1.1 12.1.1 Cargar Grupos de
+class="header-section-number">1.12.1.1 12.1.1 Cargar Grupos de
Usuario por Defecto
php bin/console app:load-default-user-groups
Crea los grupos de usuarios predeterminados del sistema.
-1.13.1.2 12.1.2 Cargar Comandos por
+1.12.1.2 12.1.2 Cargar Comandos por
Defecto
php bin/console app:load-default-commands
Carga los comandos básicos del sistema.
-1.13.1.3 12.1.3 Cargar Usuario
+1.12.1.3 12.1.3 Cargar Usuario
Admin
php bin/console app:load-default-user-admin
Crea el usuario administrador por defecto.
-1.13.1.4 12.1.4 Cargar Menú por
+1.12.1.4 12.1.4 Cargar Menú por
Defecto
php bin/console app:load-default-menu
Carga menús de arranque predeterminados.
-1.13.1.5 12.1.5 Cargar Tipos de
+1.12.1.5 12.1.5 Cargar Tipos de
Hardware
php bin/console app:load-hardware-types
Inicializa la tabla de tipos de hardware.
-1.13.1.6 12.1.6 Cargar Unidad
+class="header-section-number">1.12.1.6 12.1.6 Cargar Unidad
Organizativa por Defecto
php bin/console app:load-organizational-unit-default
Crea la unidad organizativa raíz.
-1.13.2 12.2 Comandos de
+1.12.2 11.2 Comandos de
Operación
-1.13.2.1 12.2.1 Verificar
+class="header-section-number">1.12.2.1 12.2.1 Verificar
Disponibilidad de Clientes
php bin/console app:check-client-availability
Ejecución: Cada 1 minuto (cron)
Verifica el estado de conectividad de los clientes y actualiza su
estado si no responden en un tiempo determinado.
-1.13.2.2 12.2.2 Ejecutar Trazas
+1.12.2.2 12.2.2 Ejecutar Trazas
Pendientes
php bin/console app:execute-pending-traces
Ejecución: Cada 1 minuto (cron)
Procesa las trazas en estado PENDING
y las ejecuta en
los clientes correspondientes.
-1.13.2.3 12.2.3 Ejecutar Tareas
+1.12.2.3 12.2.3 Ejecutar Tareas
Programadas
php bin/console app:run-scheduled-command-tasks
Ejecución: Cada 1 minuto (cron)
Ejecuta tareas programadas que han llegado a su hora de
ejecución.
-1.13.3 12.3 Comandos de
+1.12.3 11.3 Comandos de
Migración
Comandos para migrar datos desde OpenGnsys 1.1:
-1.13.3.1 12.3.1 Migrar Unidades
+1.12.3.1 12.3.1 Migrar Unidades
Organizativas
php bin/console opengnsys:migration:organizational-unit
-1.13.3.2 12.3.2 Migrar Perfiles de
+1.12.3.2 12.3.2 Migrar Perfiles de
Hardware
php bin/console opengnsys:migration:hardware-profile
-1.13.3.3 12.3.3 Migrar
+1.12.3.3 12.3.3 Migrar
Clientes
php bin/console opengnsys:migration:clients
-1.13.3.4 12.3.4 Migrar Sistemas
+1.12.3.4 12.3.4 Migrar Sistemas
Operativos
php bin/console opengnsys:migration:os
-1.13.3.5 12.3.5 Migrar
+1.12.3.5 12.3.5 Migrar
Imágenes
php bin/console opengnsys:migration:image
-1.13.3.6 12.3.6 Migrar Perfiles de
+1.12.3.6 12.3.6 Migrar Perfiles de
Software
php bin/console opengnsys:migration:software-profile
-1.13.3.7 12.3.7 Migrar Particiones
+1.12.3.7 12.3.7 Migrar Particiones
de Clientes
php bin/console opengnsys:migration:partition-client
-1.13.4 12.4 Comandos de
+1.12.4 11.4 Comandos de
Desarrollo
-1.13.4.1 12.4.1 Crear Repositorios
+1.12.4.1 12.4.1 Crear Repositorios
de Imágenes
php bin/console app:create-image-repositories
Crea repositorios de imágenes para desarrollo/testing.
-1.13.4.2 12.4.2 Cargar Trazas de
+1.12.4.2 12.4.2 Cargar Trazas de
Ejemplo
php bin/console app:charge-example-trace
Carga trazas de ejemplo para testing.
-1.13.5 12.5 Configuración de
+1.12.5 11.5 Configuración de
Cron
Agregar al crontab:
* * * * * docker exec ogcore-php php bin/console app:execute-pending-traces
* * * * * docker exec ogcore-php php bin/console app:run-scheduled-command-tasks
-1.14 13. Migraciones de Datos
-1.14.1 13.1 Sistema de Migraciones
+1.13 12. Migraciones de Datos
+1.13.1 12.1 Sistema de Migraciones
de Doctrine
ogCore utiliza Doctrine Migrations para gestionar cambios en el
esquema de base de datos.
-1.14.1.1 13.1.1 Crear una
+1.13.1.1 13.1.1 Crear una
Migración
docker exec ogcore-php php bin/console make:migration
-1.14.1.2 13.1.2 Ejecutar
+1.13.1.2 13.1.2 Ejecutar
Migraciones
docker exec ogcore-php php bin/console doctrine:migrations:migrate
-1.14.1.3 13.1.3 Ver Estado de
+1.13.1.3 13.1.3 Ver Estado de
Migraciones
docker exec ogcore-php php bin/console doctrine:migrations:status
-1.14.1.4 13.1.4 Revertir
+1.13.1.4 13.1.4 Revertir
Migración
docker exec ogcore-php php bin/console doctrine:migrations:migrate prev
-1.14.2 13.2 Migración desde
+1.13.2 12.2 Migración desde
OpenGnsys 1.1
Para migrar datos desde una instalación de OpenGnsys 1.1:
-1.14.2.1 13.2.1 Crear Base de Datos
+1.13.2.1 13.2.1 Crear Base de Datos
Temporal
docker exec ogcore-php php bin/console doctrine:database:create --connection=og_1
-1.14.2.2 13.2.2 Cargar Dump de
+1.13.2.2 13.2.2 Cargar Dump de
OpenGnsys 1.1
docker exec -i ogcore-database mysql -u user -p ogcore_old_og < dump_og_1.1.sql
-1.14.2.3 13.2.3 Ejecutar
+1.13.2.3 13.2.3 Ejecutar
Migraciones
Ejecutar los comandos de migración en orden:
docker exec ogcore-php php bin/console opengnsys:migration:os
docker exec ogcore-php php bin/console opengnsys:migration:image
docker exec ogcore-php php bin/console opengnsys:migration:software-profile
-1.14.3 13.3 Backup y
+1.13.3 12.3 Backup y
Restauración
-1.14.3.1 13.3.1 Backup de Base de
+1.13.3.1 13.3.1 Backup de Base de
Datos
docker exec ogcore-database mysqldump -u user -p ogcore > backup_$(date +%Y%m%d).sql
-1.14.3.2 13.3.2 Restaurar Base de
+1.13.3.2 13.3.2 Restaurar Base de
Datos
docker exec -i ogcore-database mysql -u user -p ogcore < backup_20251008.sql
-1.15 14. Testing
-1.15.1 14.1 Framework de
+1.14 13. Testing
+1.14.1 13.1 Framework de
Testing
ogCore utiliza PHPUnit con integración de Symfony y
Doctrine.
-1.15.2 14.2 Ejecutar Tests
-1.15.2.1 14.2.1 Todos los
+1.14.2 13.2 Ejecutar Tests
+1.14.2.1 14.2.1 Todos los
Tests
docker compose exec php bin/phpunit
-1.15.2.2 14.2.2 Tests
+1.14.2.2 14.2.2 Tests
Específicos
docker compose exec php bin/phpunit tests/Functional/ClientTest.php
-1.15.2.3 14.2.3 Tests con
+1.14.2.3 14.2.3 Tests con
Coverage
docker compose exec php bin/phpunit --coverage-html coverage/
-1.15.3 14.3 Tipos de Tests
-1.15.3.1 14.3.1 Tests
+1.14.3 13.3 Tipos de Tests
+1.14.3.1 14.3.1 Tests
Funcionales
Ubicación: tests/Functional/
20 archivos de tests funcionales que prueban: - Endpoints de API -
@@ -1926,8 +1715,8 @@ class="sourceCode php">
$this->assertResponseStatusCodeSame(201);
}
-
1.15.4 14.4 Factories para
+1.14.4 13.4 Factories para
Testing
Se utilizan Zenstruck Foundry factories (24
factories) para crear datos de prueba:
@@ -1936,32 +1725,32 @@ class="sourceCode php"> 'name' => 'Test PC',
'status' => 'active'
]);
-1.15.5 14.5 Base de Datos de
+1.14.5 13.5 Base de Datos de
Testing
Los tests utilizan DAMA Doctrine Test Bundle para: -
Ejecutar cada test en una transacción - Rollback automático después de
cada test - Aislamiento completo entre tests
-1.16 15. Despliegue
-1.16.1 15.1 Despliegue con Docker
+1.15 14. Despliegue
+1.15.1 14.1 Despliegue con Docker
Compose
-1.16.1.1 15.1.1 Desarrollo
+1.15.1.1 15.1.1 Desarrollo
-1.16.1.2 15.1.2 Producción
+1.15.1.2 15.1.2 Producción
docker compose -f docker-compose-deploy.yml up -d
-1.16.2 15.2 Despliegue con
+1.15.2 14.2 Despliegue con
Jenkins
El proyecto incluye Jenkinsfile para CI/CD.
-1.16.2.1 Pipeline stages:
+1.15.2.1 Pipeline stages:
- Checkout: Clonar repositorio
- Build: Construir imagen Docker
@@ -1969,18 +1758,18 @@ class="header-section-number">1.16.2.1 Pipeline stages:
- Package: Crear paquete Debian
- Deploy: Desplegar en servidor
-1.16.3 15.3 Paquete Debian
+1.15.3 14.3 Paquete Debian
El proyecto puede empaquetarse como .deb
:
Estructura del paquete en debian/
: - Control files -
Postinst/preinst scripts - Systemd service file - Configuración
-1.16.4 15.4 Configuración de
+1.15.4 14.4 Configuración de
Producción
-1.16.4.1 15.4.1 Variables de
+1.15.4.1 15.4.1 Variables de
Entorno
Crear .env.local
con configuración de producción:
APP_DEBUG=0
DATABASE_URL="mysql://user:pass@localhost:3306/ogcore"
# ... más configuración
-1.16.4.2 15.4.2 Optimizaciones
+1.15.4.2 15.4.2 Optimizaciones
# Limpiar caché
docker exec ogcore-php php bin/console cache:clear --env=prod
@@ -1999,19 +1788,19 @@ class="sourceCode bash">
# Optimizar autoloader
docker exec ogcore-php composer dump-autoload --optimize --classmap-authoritative
-1.16.5 15.5 Monitoreo
-1.16.5.1 15.5.1 Logs
+1.15.5 14.5 Monitoreo
+1.15.5.1 15.5.1 Logs
Logs ubicados en var/log/
: - dev.log
/
prod.log
: Logs de aplicación -
nginx/access.log
: Accesos a nginx -
nginx/error.log
: Errores de nginx
-1.16.5.2 15.5.2 Syslog
+1.15.5.2 15.5.2 Syslog
Los logs también se envían a syslog para centralización.
-1.16.6 15.6 Escalabilidad
+1.15.6 14.6 Escalabilidad
Para escalar horizontalmente:
- Base de datos: Usar MariaDB con replicación
@@ -2023,34 +1812,34 @@ carga
- Mercure: Escalar hub de Mercure
-1.17 16. Mantenimiento y
+1.16 15. Mantenimiento y
Operaciones
-1.17.1 16.1 Reiniciar Base de
+1.16.1 15.1 Reiniciar Base de
Datos
docker exec ogcore-php php bin/console doctrine:database:drop --force
docker exec ogcore-php php bin/console doctrine:database:create
docker exec ogcore-php php bin/console doctrine:migrations:migrate --no-interaction
docker exec ogcore-php php bin/console doctrine:fixtures:load --no-interaction
-1.17.2 16.2 Limpiar Caché
+1.16.2 15.2 Limpiar Caché
docker exec ogcore-php php bin/console cache:clear
docker exec ogcore-php php bin/console cache:warmup
-1.17.3 16.3 Actualizar
+1.16.3 15.3 Actualizar
Dependencias
docker exec ogcore-php composer update
-1.17.4 16.4 Regenerar Claves
+1.16.4 15.4 Regenerar Claves
JWT
docker exec ogcore-php php bin/console lexik:jwt:generate-keypair --overwrite
-1.17.5 16.5 Backups
+1.16.5 15.5 Backups
Automáticos
Script ejemplo para backup automático:
# Limpiar backups antiguos (>30 días)
find $BACKUP_DIR -name "*.sql" -mtime +30 -delete
find $BACKUP_DIR -name "*.tar.gz" -mtime +30 -delete
-1.17.6 16.6 Monitoreo de Salud
-1.17.6.1 Health Check Endpoint
+1.16.6 15.6 Monitoreo de Salud
+1.16.6.1 Health Check Endpoint
-1.17.6.2 Verificar Estado de
+1.16.6.2 Verificar Estado de
Servicios
# PHP
@@ -2085,8 +1874,8 @@ class="sourceCode bash">
# MariaDB
docker exec ogcore-database mysqladmin -u user -p status
-1.17.7 16.7 Rotación de Logs
+1.16.7 15.7 Rotación de Logs
Configurar logrotate:
/var/www/html/ogcore/var/log/*.log {
@@ -2099,51 +1888,51 @@ class="sourceCode bash"> sharedscripts
}
-1.18 17. Integración con Otros
+1.17 16. Integración con Otros
Servicios
-1.18.1 17.1 ogRepository
+1.17.1 16.1 ogRepository
Propósito: Gestión de repositorios de imágenes.
Endpoints integrados: - Crear imagen - Desplegar
imagen - Backup imagen - Eliminar imagen - Convertir a imagen virtual -
Importar imagen externa - Verificar integridad - Imagen global
Webhook: /og-repository/webhook
-1.18.2 17.2 ogDhcp
+1.17.2 16.2 ogDhcp
Propósito: Gestión de DHCP dinámico.
Funcionalidades: - Agregar clientes a DHCP -
Eliminar clientes de DHCP - Actualizar configuración - Gestión de
subredes
-1.18.3 17.3 ogBoot
+1.17.3 16.3 ogBoot
Propósito: Gestión de archivos de arranque PXE.
Funcionalidades: - Crear archivos de arranque -
Actualizar plantillas PXE - Eliminar configuraciones - Sincronización de
menús
-1.18.4 17.4 ogAgent
+1.17.4 16.4 ogAgent
Propósito: Agente instalado en clientes para
ejecutar comandos.
Operaciones: - Power on/off/reboot - Crear/desplegar
imágenes - Particionar discos - Ejecutar scripts - Obtener inventario
hardware - Verificar tamaño de particiones - Kill jobs
-1.18.5 17.5 UDS (Universal Desktop
+1.17.5 16.5 UDS (Universal Desktop
Services)
Propósito: Integración con sistema de escritorios
remotos.
Funcionalidades: - Autenticación - Obtener service
pools - Calcular disponibilidad - Gestión de reservas
-1.18.6 17.6 Git (Versionado de
+1.17.6 16.6 Git (Versionado de
Imágenes)
Propósito: Versionado de imágenes con Git.
Funcionalidades: - Backup a repositorio Git -
Versionado automático - Recuperación de versiones - Sincronización
-1.18.7 17.7 Mercure (Notificaciones
+class="header-section-number">1.17.7 16.7 Mercure (Notificaciones
en Tiempo Real)
Propósito: Notificaciones push en tiempo real.
Eventos publicados: - Cambio de estado de clientes -
@@ -2157,14 +1946,14 @@ class="sourceCode javascript"> console.log('Client updated:', data);
};
-1.19 18. Roadmap y Changelog
-1.19.1 18.1 Versión Actual:
+1.18 17. Roadmap y Changelog
+1.18.1 17.1 Versión Actual:
0.5.0
-1.19.2 18.2 Últimas Características
+class="header-section-number">1.18.2 17.2 Últimas Características
(v0.25.1 - Octubre 2025)
- Tareas programadas: Sistema completo de colas y
@@ -2189,11 +1978,11 @@ imágenes
- Mercure: Notificaciones en tiempo real
- Despliegue multicast: Modos torrent y UDPCAST
-1.19.3 18.3 Próximas
+1.18.3 17.3 Próximas
Características (Roadmap)
-1.19.3.1 v0.6.0 (Q4 2025)
+1.18.3.1 v0.6.0 (Q4 2025)
-1.19.3.2 v0.7.0 (Q1 2026)
+1.18.3.2 v0.7.0 (Q1 2026)
-1.19.3.3 v1.0.0 (Q2 2026)
+1.18.3.3 v1.0.0 (Q2 2026)
-1.19.4 18.4 Changelog Resumido
+1.18.4 17.4 Changelog Resumido
Ver CHANGELOG.md
para el historial completo de
cambios.
Versiones destacadas:
@@ -2260,10 +2049,10 @@ aulas
torrent/udpcast
-1.20 19. Contribución
-1.20.1 19.1 Guía de
+1.19 18. Contribución
+1.19.1 18.1 Guía de
Contribución
Para contribuir al proyecto:
@@ -2276,8 +2065,8 @@ Contribución
git push origin feature/nueva-funcionalidad
- Crea un Pull Request
-1.20.2 19.2 Estándares de
+1.19.2 18.2 Estándares de
Código
- Seguir PSR-12 para PHP
@@ -2286,8 +2075,8 @@ Código
Tests para nuevas funcionalidades
Commits descriptivos en español
-1.20.3 19.3 Proceso de
+1.19.3 18.3 Proceso de
Revisión
- CI/CD ejecuta tests automáticamente
@@ -2296,8 +2085,8 @@ Revisión
Merge a rama develop
Release periódicos a main
-1.20.4 19.4 Reportar Bugs
+1.19.4 18.4 Reportar Bugs
Usar el sistema de Issues del repositorio:
Template de Bug:
**Descripción del bug**
@@ -2319,10 +2108,10 @@ Si aplica, añadir screenshots.
- Versión: [ej. 0.5.0]
- Browser: [ej. Firefox 118]
-1.21 20. Soporte y Contacto
-1.21.1 20.1 Documentación
+1.20 19. Soporte y Contacto
+1.20.1 19.1 Documentación
Adicional
- API Docs: http://localhost:8080/docs
@@ -2331,27 +2120,27 @@ Adicional
Diagramas:
swagger-assets/img_bbdd.png
-1.21.2 20.2 Recursos
+1.20.2 19.2 Recursos
- Repositorio: [URL del repositorio]
- Wiki: [URL de la wiki]
- Issues: [URL de issues]
-1.21.3 20.3 Equipo de
+1.20.3 19.3 Equipo de
Desarrollo
Proyecto desarrollado por el equipo de OpenGnsys en colaboración con
universidades participantes.
-1.21.4 20.4 Licencia
+1.20.4 19.4 Licencia
Proyecto propietario. Ver archivo LICENSE
para más
información.
-1.22 Apéndices
-1.22.1 Apéndice A: Glosario de
+1.21 Apéndices
+1.21.1 Apéndice A: Glosario de
Términos
- Cliente: Equipo físico gestionado por el
@@ -2368,8 +2157,8 @@ red
- Repositorio: Servidor de almacenamiento de
imágenes
-1.22.2 Apéndice B: Puertos y
+1.21.2 Apéndice B: Puertos y
Servicios
@@ -2407,39 +2196,39 @@ Servicios
-1.22.3 Apéndice C: Estructura de
+1.21.3 Apéndice C: Estructura de
Directorios
ogcore/
-├── bin/ # Ejecutables (console, phpunit)
-├── config/ # Configuración de Symfony
-│ ├── api_platform/ # Configuración de entidades API
-│ ├── packages/ # Configuración de bundles
-│ └── routes/ # Rutas
-├── migrations/ # Migraciones de base de datos
-├── public/ # Punto de entrada web
-├── src/ # Código fuente
-│ ├── Command/ # Comandos de consola
-│ ├── Controller/ # Controladores
-│ ├── Dto/ # Data Transfer Objects
-│ ├── Entity/ # Entidades Doctrine
-│ ├── EventListener/# Event Listeners
-│ ├── EventSubscriber/ # Event Subscribers
-│ ├── Factory/ # Factories para testing
-│ ├── Filter/ # Filtros de API Platform
-│ ├── Repository/ # Repositorios Doctrine
-│ ├── Security/ # Seguridad y autenticación
-│ ├── Service/ # Servicios de negocio
-│ ├── State/ # States de API Platform
-│ └── Validator/ # Validadores personalizados
-├── tests/ # Tests
-├── translations/ # Traducciones
-├── var/ # Archivos variables (cache, logs)
-└── vendor/ # Dependencias
+|-- bin/ # Ejecutables (console, phpunit)
+|-- config/ # Configuración de Symfony
+| |-- api_platform/ # Configuración de entidades API
+| |-- packages/ # Configuración de bundles
+| +-- routes/ # Rutas
+|-- migrations/ # Migraciones de base de datos
+|-- public/ # Punto de entrada web
+|-- src/ # Código fuente
+| |-- Command/ # Comandos de consola
+| |-- Controller/ # Controladores
+| |-- Dto/ # Data Transfer Objects
+| |-- Entity/ # Entidades Doctrine
+| |-- EventListener/# Event Listeners
+| |-- EventSubscriber/ # Event Subscribers
+| |-- Factory/ # Factories para testing
+| |-- Filter/ # Filtros de API Platform
+| |-- Repository/ # Repositorios Doctrine
+| |-- Security/ # Seguridad y autenticación
+| |-- Service/ # Servicios de negocio
+| |-- State/ # States de API Platform
+| +-- Validator/ # Validadores personalizados
+|-- tests/ # Tests
+|-- translations/ # Traducciones
+|-- var/ # Archivos variables (cache, logs)
++-- vendor/ # Dependencias
-1.22.4 Apéndice D: Variables de
+class="header-section-number">1.21.4 Apéndice D: Variables de
Entorno Completas
Ver archivo .env
para todas las variables de entorno
disponibles.
diff --git a/ogCore_Documentacion_Tecnica.pdf b/ogCore_Documentacion_Tecnica.pdf
index a3c6a00f95a0cd86947e3250ee0e03e0fa11e4bf..7506a560b06580dcc73277c72cbb44a988c40e98 100644
GIT binary patch
delta 318638
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