fix(css): centrar verticalmente contenido del hero section
Agrega propiedades flexbox al contenedor .hero-section para que el contenido (título y badges) se muestre centrado verticalmente cuando no hay badges de categorías. Cambios: - display: flex - align-items: center - justify-content: center También incluye specs OpenSpec para arquitectura del tema. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -133,6 +133,9 @@ final class HeroRenderer implements RendererInterface
|
|||||||
'padding' => "{$paddingVertical} 0",
|
'padding' => "{$paddingVertical} 0",
|
||||||
'margin-bottom' => $marginBottom,
|
'margin-bottom' => $marginBottom,
|
||||||
'min-height' => $minHeight,
|
'min-height' => $minHeight,
|
||||||
|
'display' => 'flex',
|
||||||
|
'align-items' => 'center',
|
||||||
|
'justify-content' => 'center',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$cssRules[] = $this->cssGenerator->generate('.hero-section__title', [
|
$cssRules[] = $this->cssGenerator->generate('.hero-section__title', [
|
||||||
|
|||||||
215
openspec/specs/arquitectura-limpia/spec.md
Normal file
215
openspec/specs/arquitectura-limpia/spec.md
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
# Especificacion de Arquitectura Limpia
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
|
||||||
|
Define la implementacion de Clean Architecture para ROITheme, un tema WordPress que sigue principios de Domain-Driven Design con separacion fisica de contextos delimitados (Admin, Public, Shared).
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
### Requirement: Separacion Fisica de Contextos
|
||||||
|
|
||||||
|
The system MUST organize code into three physically delimited contexts: Admin/, Public/, and Shared/.
|
||||||
|
|
||||||
|
#### Scenario: Codigo pertenece al contexto de administracion
|
||||||
|
- **WHEN** el codigo maneja operaciones CRUD, configuracion o funcionalidad del panel admin
|
||||||
|
- **THEN** el codigo DEBE colocarse en el directorio `Admin/`
|
||||||
|
- **AND** el codigo NO DEBE importar del directorio `Public/`
|
||||||
|
|
||||||
|
#### Scenario: Codigo pertenece al contexto publico/frontend
|
||||||
|
- **WHEN** el codigo maneja renderizado, visualizacion o presentacion frontend
|
||||||
|
- **THEN** el codigo DEBE colocarse en el directorio `Public/`
|
||||||
|
- **AND** el codigo NO DEBE importar del directorio `Admin/`
|
||||||
|
|
||||||
|
#### Scenario: Codigo es compartido entre contextos
|
||||||
|
- **WHEN** el codigo es usado por AMBOS contextos Admin/ y Public/
|
||||||
|
- **THEN** el codigo DEBE colocarse en el directorio `Shared/` raiz
|
||||||
|
- **AND** tanto Admin/ como Public/ PUEDEN importar de Shared/
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Organizacion Granular de Codigo Compartido
|
||||||
|
|
||||||
|
The system MUST implement three levels of shared code to avoid mixing context-specific shared code.
|
||||||
|
|
||||||
|
#### Scenario: Codigo compartido solo dentro del contexto Admin
|
||||||
|
- **WHEN** el codigo es reutilizado por multiples modulos Admin pero NO por Public
|
||||||
|
- **THEN** el codigo DEBE colocarse en el directorio `Admin/Shared/`
|
||||||
|
- **AND** los modulos de Public/ NO DEBEN importar de `Admin/Shared/`
|
||||||
|
|
||||||
|
#### Scenario: Codigo compartido solo dentro del contexto Public
|
||||||
|
- **WHEN** el codigo es reutilizado por multiples modulos Public pero NO por Admin
|
||||||
|
- **THEN** el codigo DEBE colocarse en el directorio `Public/Shared/`
|
||||||
|
- **AND** los modulos de Admin/ NO DEBEN importar de `Public/Shared/`
|
||||||
|
|
||||||
|
#### Scenario: Codigo compartido entre ambos contextos
|
||||||
|
- **WHEN** el codigo es reutilizado por AMBOS modulos Admin/ y Public/
|
||||||
|
- **THEN** el codigo DEBE colocarse en el directorio `Shared/` raiz
|
||||||
|
- **AND** esto incluye ValueObjects, Exceptions y Contracts base
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Cada Contexto Sigue las Capas de Clean Architecture
|
||||||
|
|
||||||
|
Each context (Admin/, Public/, Shared/) MUST internally implement the three Clean Architecture layers: Domain, Application, Infrastructure.
|
||||||
|
|
||||||
|
#### Scenario: Estructura de modulo dentro del contexto Admin
|
||||||
|
- **GIVEN** un componente llamado "Navbar" en el contexto Admin
|
||||||
|
- **WHEN** el modulo es creado
|
||||||
|
- **THEN** la estructura DEBE ser: Admin/Navbar/ con subcarpetas Domain/, Application/, Infrastructure/
|
||||||
|
|
||||||
|
#### Scenario: Estructura de modulo dentro del contexto Public
|
||||||
|
- **GIVEN** un componente llamado "Navbar" en el contexto Public
|
||||||
|
- **WHEN** el modulo es creado
|
||||||
|
- **THEN** la estructura DEBE ser: Public/Navbar/ con subcarpetas Domain/, Application/, Infrastructure/
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Cumplimiento de Direccion de Dependencias
|
||||||
|
|
||||||
|
The system MUST enforce that dependencies flow ONLY from outer layers to inner layers.
|
||||||
|
|
||||||
|
#### Scenario: Infrastructure depende de Application y Domain
|
||||||
|
- **WHEN** el codigo esta en la capa Infrastructure
|
||||||
|
- **THEN** PUEDE importar de la capa Application
|
||||||
|
- **AND** PUEDE importar de la capa Domain
|
||||||
|
|
||||||
|
#### Scenario: Application depende solo de Domain
|
||||||
|
- **WHEN** el codigo esta en la capa Application
|
||||||
|
- **THEN** PUEDE importar de la capa Domain
|
||||||
|
- **AND** NO DEBE importar de la capa Infrastructure
|
||||||
|
|
||||||
|
#### Scenario: Domain no tiene dependencias externas
|
||||||
|
- **WHEN** el codigo esta en la capa Domain
|
||||||
|
- **THEN** NO DEBE importar de la capa Application
|
||||||
|
- **AND** NO DEBE importar de la capa Infrastructure
|
||||||
|
- **AND** NO DEBE importar funciones o globales de WordPress
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: La Capa Domain Contiene Solo Logica de Negocio Pura
|
||||||
|
|
||||||
|
The Domain layer MUST contain only pure business logic without framework dependencies.
|
||||||
|
|
||||||
|
#### Scenario: Validacion de contenido de capa Domain
|
||||||
|
- **WHEN** el codigo se coloca en la capa Domain
|
||||||
|
- **THEN** PUEDE contener Entities, Value Objects, Domain Services, Interfaces, Exceptions
|
||||||
|
- **AND** NO DEBE contener global $wpdb, $_POST, $_GET, $_SESSION, add_action, add_filter, HTML, CSS, JavaScript
|
||||||
|
|
||||||
|
#### Scenario: Implementacion de entidad Domain
|
||||||
|
- **GIVEN** una entidad Domain como NavbarConfiguration
|
||||||
|
- **WHEN** la entidad es implementada
|
||||||
|
- **THEN** DEBE contener reglas de negocio y validacion
|
||||||
|
- **AND** NO DEBE contener logica de persistencia
|
||||||
|
- **AND** NO DEBE referenciar APIs de WordPress
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: La Capa Application Orquesta Domain
|
||||||
|
|
||||||
|
The Application layer MUST orchestrate domain entities without containing business logic.
|
||||||
|
|
||||||
|
#### Scenario: Implementacion de Use Case
|
||||||
|
- **WHEN** un Use Case es implementado
|
||||||
|
- **THEN** DEBE coordinar entidades y servicios de domain
|
||||||
|
- **AND** DEBE depender de interfaces, NO de implementaciones concretas
|
||||||
|
- **AND** NO DEBE contener reglas de validacion de negocio
|
||||||
|
|
||||||
|
#### Scenario: Uso de DTOs para transferencia de datos
|
||||||
|
- **WHEN** los datos cruzan limites entre capas
|
||||||
|
- **THEN** se DEBEN usar DTOs (Data Transfer Objects)
|
||||||
|
- **AND** los DTOs DEBEN ser contenedores de datos simples sin logica de negocio
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Infrastructure Implementa Interfaces
|
||||||
|
|
||||||
|
The Infrastructure layer MUST implement interfaces defined in Domain/Application layers.
|
||||||
|
|
||||||
|
#### Scenario: Implementacion de Repository
|
||||||
|
- **GIVEN** una RepositoryInterface definida en Domain
|
||||||
|
- **WHEN** el repository es implementado
|
||||||
|
- **THEN** DEBE colocarse en Infrastructure/Persistence/
|
||||||
|
- **AND** DEBE implementar la interface de Domain
|
||||||
|
- **AND** PUEDE usar global $wpdb o APIs de WordPress
|
||||||
|
|
||||||
|
#### Scenario: Integracion con WordPress
|
||||||
|
- **WHEN** se necesita codigo especifico de WordPress
|
||||||
|
- **THEN** DEBE colocarse en la capa Infrastructure
|
||||||
|
- **AND** NO DEBE filtrarse a las capas Domain o Application
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Los Modulos Son Autocontenidos e Independientes
|
||||||
|
|
||||||
|
Each module (Navbar, Footer, Toolbar, etc.) MUST be self-contained and independent from other modules.
|
||||||
|
|
||||||
|
#### Scenario: Aislamiento de modulos
|
||||||
|
- **WHEN** un modulo como Admin/Navbar/ es implementado
|
||||||
|
- **THEN** NO DEBE importar de Admin/Footer/
|
||||||
|
- **AND** NO DEBE importar de Admin/Toolbar/
|
||||||
|
- **AND** SOLO PUEDE importar de Shared/
|
||||||
|
|
||||||
|
#### Scenario: Eliminacion de modulos
|
||||||
|
- **WHEN** un modulo necesita ser eliminado
|
||||||
|
- **THEN** borrar la carpeta del modulo NO DEBE romper otros modulos
|
||||||
|
- **AND** no se DEBERIAN requerir cambios de codigo en otros modulos
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Admin y Public Son Bounded Contexts Separados
|
||||||
|
|
||||||
|
Admin/ and Public/ MUST be treated as separate bounded contexts because they have different responsibilities.
|
||||||
|
|
||||||
|
#### Scenario: Responsabilidad del contexto Admin
|
||||||
|
- **WHEN** el codigo maneja administracion de componentes
|
||||||
|
- **THEN** la entidad Domain se enfoca en configuracion, validacion, estados draft/published
|
||||||
|
- **AND** los Use Cases se enfocan en operaciones Save, Update, Delete, Get
|
||||||
|
|
||||||
|
#### Scenario: Responsabilidad del contexto Public
|
||||||
|
- **WHEN** el codigo maneja renderizado de componentes
|
||||||
|
- **THEN** la entidad Domain se enfoca en estado activo, caching, filtrado por permisos
|
||||||
|
- **AND** los Use Cases se enfocan en operaciones GetActive, Render, Cache
|
||||||
|
|
||||||
|
#### Scenario: No hay duplicacion de domain
|
||||||
|
- **WHEN** Admin/Navbar/Domain/ y Public/Navbar/Domain/ ambos existen
|
||||||
|
- **THEN** NO son duplicados sino bounded contexts especializados
|
||||||
|
- **AND** Admin se enfoca en configuracion/gestion
|
||||||
|
- **AND** Public se enfoca en renderizado/visualizacion
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Validacion de Arquitectura Antes de Commit
|
||||||
|
|
||||||
|
The system MUST validate architectural compliance before committing code.
|
||||||
|
|
||||||
|
#### Scenario: Validacion de capa Domain
|
||||||
|
- **WHEN** se valida codigo de la capa Domain
|
||||||
|
- **THEN** grep por global $wpdb DEBE retornar vacio
|
||||||
|
- **AND** grep por add_action DEBE retornar vacio
|
||||||
|
- **AND** grep por $_POST DEBE retornar vacio
|
||||||
|
|
||||||
|
#### Scenario: Validacion de dependencias de modulos
|
||||||
|
- **WHEN** se validan dependencias entre modulos
|
||||||
|
- **THEN** imports de Admin/Navbar/ desde Admin/Footer/ NO DEBEN existir
|
||||||
|
- **AND** imports de Public/Navbar/ desde Public/Footer/ NO DEBEN existir
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Realizacion de Beneficios de la Arquitectura
|
||||||
|
|
||||||
|
The architecture MUST provide measurable benefits.
|
||||||
|
|
||||||
|
#### Scenario: Asignacion granular de trabajo
|
||||||
|
- **WHEN** un desarrollador es asignado a trabajar en Admin/Navbar/
|
||||||
|
- **THEN** puede acceder SOLO a esa carpeta
|
||||||
|
- **AND** no puede ver ni modificar Public/ u otros modulos de Admin/
|
||||||
|
|
||||||
|
#### Scenario: Eliminacion facil de modulos
|
||||||
|
- **WHEN** un componente ya no es necesario
|
||||||
|
- **THEN** eliminarlo requiere solo borrar la carpeta
|
||||||
|
- **AND** no se necesitan otras modificaciones de codigo
|
||||||
|
|
||||||
|
#### Scenario: Codigo compartido consistente
|
||||||
|
- **WHEN** se encuentra un bug en un ValueObject compartido
|
||||||
|
- **THEN** arreglarlo en Shared/Domain/ValueObjects/ lo arregla para TODOS los modulos
|
||||||
|
- **AND** no se necesita actualizar codigo duplicado
|
||||||
350
openspec/specs/estandares-codigo/spec.md
Normal file
350
openspec/specs/estandares-codigo/spec.md
Normal file
@@ -0,0 +1,350 @@
|
|||||||
|
# Especificacion de Estandares de Codigo
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
|
||||||
|
Define los principios SOLID, estandares de POO (Programacion Orientada a Objetos) y estandares generales de codigo que DEBEN seguirse en el desarrollo de ROITheme.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
### Requirement: Principio de Responsabilidad Unica (SRP)
|
||||||
|
|
||||||
|
Each class MUST have exactly one reason to change and one responsibility.
|
||||||
|
|
||||||
|
#### Scenario: Responsabilidad de clase Use Case
|
||||||
|
- **WHEN** se crea una clase Use Case
|
||||||
|
- **THEN** DEBE manejar exactamente UNA operacion (Save, Get, Delete, etc.)
|
||||||
|
- **AND** NO DEBE combinar multiples operaciones en una clase
|
||||||
|
|
||||||
|
#### Scenario: Validacion de tamano de clase
|
||||||
|
- **WHEN** se crea un archivo de clase
|
||||||
|
- **THEN** DEBERIA tener menos de 300 lineas
|
||||||
|
- **AND** DEBERIA tener maximo 3-5 metodos privados
|
||||||
|
- **AND** el nombre de la clase DEBE describir su unica responsabilidad
|
||||||
|
|
||||||
|
#### Scenario: Violacion de SRP
|
||||||
|
- **WHEN** una clase contiene save(), get(), delete(), validate(), sendEmail()
|
||||||
|
- **THEN** DEBE dividirse en clases Use Case separadas
|
||||||
|
- **AND** cada clase maneja solo una operacion
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Principio Abierto/Cerrado (OCP)
|
||||||
|
|
||||||
|
Classes MUST be open for extension but closed for modification.
|
||||||
|
|
||||||
|
#### Scenario: Agregar nuevo tipo de componente
|
||||||
|
- **WHEN** se necesita un nuevo tipo de componente
|
||||||
|
- **THEN** se DEBE crear una nueva subclase
|
||||||
|
- **AND** la clase BaseComponent existente NO DEBE modificarse
|
||||||
|
- **AND** NO se DEBERIAN agregar cadenas if/elseif para nuevos tipos
|
||||||
|
|
||||||
|
#### Scenario: Extender funcionalidad base
|
||||||
|
- **GIVEN** que existe una clase abstracta BaseComponent
|
||||||
|
- **WHEN** se necesita comportamiento especializado
|
||||||
|
- **THEN** se DEBE usar herencia para extender
|
||||||
|
- **AND** la clase base DEBE permanecer sin cambios
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Principio de Sustitucion de Liskov (LSP)
|
||||||
|
|
||||||
|
Subclasses MUST be substitutable for their base classes without breaking functionality.
|
||||||
|
|
||||||
|
#### Scenario: Uso polimorfico
|
||||||
|
- **GIVEN** una funcion que acepta parametro BaseComponent
|
||||||
|
- **WHEN** cualquier subclase es pasada
|
||||||
|
- **THEN** la funcion DEBE funcionar correctamente
|
||||||
|
- **AND** NO se DEBERIAN lanzar excepciones inesperadas
|
||||||
|
|
||||||
|
#### Scenario: Cumplimiento de contrato
|
||||||
|
- **WHEN** una subclase sobrescribe un metodo padre
|
||||||
|
- **THEN** DEBE respetar el contrato del metodo original
|
||||||
|
- **AND** las precondiciones NO DEBEN ser mas restrictivas
|
||||||
|
- **AND** las postcondiciones NO DEBEN ser mas permisivas
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Principio de Segregacion de Interfaces (ISP)
|
||||||
|
|
||||||
|
Interfaces MUST be small and specific, not large and general.
|
||||||
|
|
||||||
|
#### Scenario: Validacion de tamano de interface
|
||||||
|
- **WHEN** se define una interface
|
||||||
|
- **THEN** DEBE tener maximo 3-5 metodos
|
||||||
|
- **AND** cada metodo DEBE relacionarse con la misma capacidad
|
||||||
|
|
||||||
|
#### Scenario: Evitar interfaces gordas
|
||||||
|
- **WHEN** existen multiples capacidades no relacionadas
|
||||||
|
- **THEN** se DEBEN crear interfaces separadas
|
||||||
|
- **AND** las clases implementan solo las interfaces que usan
|
||||||
|
- **AND** NO se permiten metodos dummy "No implementado"
|
||||||
|
|
||||||
|
#### Scenario: Diseno correcto de interface
|
||||||
|
- **WHEN** se necesita funcionalidad de cache
|
||||||
|
- **THEN** se DEBE usar CacheInterface con get(), set(), delete()
|
||||||
|
- **AND** ValidatorInterface con validate() es separada
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Principio de Inversion de Dependencias (DIP)
|
||||||
|
|
||||||
|
High-level modules MUST depend on abstractions, not concrete implementations.
|
||||||
|
|
||||||
|
#### Scenario: Inyeccion por constructor con interfaces
|
||||||
|
- **WHEN** una clase necesita dependencias
|
||||||
|
- **THEN** el constructor DEBE recibir interfaces, NO clases concretas
|
||||||
|
- **AND** NO debe haber new ClaseConcreta() dentro del cuerpo de la clase
|
||||||
|
|
||||||
|
#### Scenario: Cableado del Contenedor DI
|
||||||
|
- **WHEN** se necesitan implementaciones concretas
|
||||||
|
- **THEN** el DIContainer DEBE manejar el cableado
|
||||||
|
- **AND** las clases permanecen desacopladas de las implementaciones
|
||||||
|
|
||||||
|
#### Scenario: Dependencia incorrecta
|
||||||
|
- **WHEN** el constructor hace this->repo = new WordPressNavbarRepository()
|
||||||
|
- **THEN** esto DEBE refactorizarse para recibir NavbarRepositoryInterface
|
||||||
|
- **AND** el DIContainer proporciona la implementacion concreta
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Encapsulacion de Propiedades
|
||||||
|
|
||||||
|
Class properties MUST be encapsulated with controlled access.
|
||||||
|
|
||||||
|
#### Scenario: Visibilidad de propiedades
|
||||||
|
- **WHEN** se define una propiedad de clase
|
||||||
|
- **THEN** DEBE ser private o protected
|
||||||
|
- **AND** el acceso DEBE ser via metodos getter
|
||||||
|
- **AND** la mutacion DEBE ser via metodos setter o metodos de negocio
|
||||||
|
|
||||||
|
#### Scenario: Encapsulacion de Value Object
|
||||||
|
- **GIVEN** un ValueObject como ComponentName
|
||||||
|
- **WHEN** es construido
|
||||||
|
- **THEN** la validacion DEBE ocurrir en el constructor
|
||||||
|
- **AND** el valor DEBE ser inmutable despues de la construccion
|
||||||
|
- **AND** los detalles internos NO DEBEN exponerse
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Guias de Herencia
|
||||||
|
|
||||||
|
Inheritance MUST be used appropriately with limited depth.
|
||||||
|
|
||||||
|
#### Scenario: Limite de profundidad de herencia
|
||||||
|
- **WHEN** se usa herencia
|
||||||
|
- **THEN** la profundidad maxima DEBE ser 2-3 niveles
|
||||||
|
- **AND** las cadenas de herencia profundas DEBEN evitarse
|
||||||
|
|
||||||
|
#### Scenario: Comportamiento comun en clase base
|
||||||
|
- **WHEN** multiples clases comparten comportamiento comun
|
||||||
|
- **THEN** se DEBERIA crear una clase base abstracta
|
||||||
|
- **AND** las subclases especializan con comportamiento adicional
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Polimorfismo Correcto
|
||||||
|
|
||||||
|
Methods MUST accept base types or interfaces to enable polymorphism.
|
||||||
|
|
||||||
|
#### Scenario: Tipos de parametros de metodo
|
||||||
|
- **WHEN** un metodo acepta parametro de componente
|
||||||
|
- **THEN** el type hint DEBERIA ser BaseComponent o ComponentInterface
|
||||||
|
- **AND** cualquier subclase/implementacion DEBE funcionar correctamente
|
||||||
|
|
||||||
|
#### Scenario: Polimorfismo de repository
|
||||||
|
- **WHEN** un Use Case usa un repository
|
||||||
|
- **THEN** DEBE aceptar RepositoryInterface
|
||||||
|
- **AND** WordPressRepository y MockRepository funcionan transparentemente
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Estandares PHP Estrictos
|
||||||
|
|
||||||
|
All PHP code MUST follow strict type safety and naming conventions.
|
||||||
|
|
||||||
|
#### Scenario: Declaracion de tipos estrictos
|
||||||
|
- **WHEN** se crea un archivo PHP
|
||||||
|
- **THEN** DEBE comenzar con declare(strict_types=1)
|
||||||
|
- **AND** los tipos de retorno DEBEN declararse
|
||||||
|
- **AND** los tipos de parametros DEBEN declararse
|
||||||
|
|
||||||
|
#### Scenario: Convencion de namespace
|
||||||
|
- **WHEN** se crea una clase
|
||||||
|
- **THEN** el namespace DEBE seguir ROITheme\[Contexto]\[Componente]\[Capa]
|
||||||
|
- **AND** DEBE soportar autoloading PSR-4
|
||||||
|
|
||||||
|
#### Scenario: Declaracion de clase
|
||||||
|
- **WHEN** se crea una clase
|
||||||
|
- **THEN** DEBERIA ser final por defecto
|
||||||
|
- **AND** solo hacerla no-final cuando se pretende herencia
|
||||||
|
- **AND** el nombre de clase DEBE ser PascalCase
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Modularidad del Codigo
|
||||||
|
|
||||||
|
Code MUST be organized into independent and cohesive modules.
|
||||||
|
|
||||||
|
#### Scenario: Independencia de modulos
|
||||||
|
- **WHEN** se crea un modulo
|
||||||
|
- **THEN** DEBE ser autocontenido
|
||||||
|
- **AND** NO DEBE depender de otros modulos (solo de Shared/)
|
||||||
|
- **AND** eliminarlo NO DEBE romper otros modulos
|
||||||
|
|
||||||
|
#### Scenario: Alta cohesion
|
||||||
|
- **WHEN** el codigo se coloca en un modulo
|
||||||
|
- **THEN** todo el codigo DEBE relacionarse con el proposito de ese modulo
|
||||||
|
- **AND** el codigo no relacionado DEBE estar en Shared/ u otro modulo
|
||||||
|
|
||||||
|
#### Scenario: Bajo acoplamiento
|
||||||
|
- **WHEN** los modulos interactuan
|
||||||
|
- **THEN** DEBEN comunicarse a traves de interfaces de Shared/
|
||||||
|
- **AND** las dependencias directas entre modulos estan prohibidas
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: DRY - No Te Repitas
|
||||||
|
|
||||||
|
Code duplication MUST be eliminated through appropriate abstraction.
|
||||||
|
|
||||||
|
#### Scenario: Ubicacion de codigo compartido
|
||||||
|
- **WHEN** el codigo es usado por multiples modulos
|
||||||
|
- **THEN** DEBE moverse al nivel apropiado de Shared/
|
||||||
|
- **AND** los modulos DEBEN importar de Shared/
|
||||||
|
|
||||||
|
#### Scenario: Deteccion de duplicacion
|
||||||
|
- **WHEN** existe codigo similar en 2+ lugares
|
||||||
|
- **THEN** DEBE refactorizarse a Shared/
|
||||||
|
- **AND** las ubicaciones originales importan de Shared/
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: KISS - Mantenlo Simple
|
||||||
|
|
||||||
|
Solutions MUST be simple and avoid over-engineering.
|
||||||
|
|
||||||
|
#### Scenario: Uso de patrones
|
||||||
|
- **WHEN** se considera un patron de diseno
|
||||||
|
- **THEN** DEBE resolver un problema real
|
||||||
|
- **AND** se DEBEN preferir soluciones mas simples
|
||||||
|
- **AND** la abstraccion excesiva DEBE evitarse
|
||||||
|
|
||||||
|
#### Scenario: Claridad del codigo
|
||||||
|
- **WHEN** se escribe codigo
|
||||||
|
- **THEN** DEBERIA ser auto-documentado
|
||||||
|
- **AND** los comentarios DEBERIAN ser innecesarios para entender
|
||||||
|
- **AND** la logica compleja DEBERIA extraerse a metodos bien nombrados
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Separacion de Responsabilidades por Capa
|
||||||
|
|
||||||
|
Each layer MUST have distinct responsibilities.
|
||||||
|
|
||||||
|
#### Scenario: Responsabilidades por capa
|
||||||
|
- **WHEN** se escribe codigo
|
||||||
|
- **THEN** Domain contiene logica de negocio
|
||||||
|
- **AND** Application contiene orquestacion
|
||||||
|
- **AND** Infrastructure contiene implementacion tecnica
|
||||||
|
- **AND** UI contiene solo presentacion
|
||||||
|
|
||||||
|
#### Scenario: Validacion de responsabilidades cruzadas
|
||||||
|
- **WHEN** se valida ubicacion de codigo
|
||||||
|
- **THEN** SQL NO DEBE estar en Domain/Application
|
||||||
|
- **AND** HTML NO DEBE estar en Domain/Application
|
||||||
|
- **AND** logica de negocio NO DEBE estar en Infrastructure
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Limites de Tamano de Archivo
|
||||||
|
|
||||||
|
Files MUST be kept small and focused.
|
||||||
|
|
||||||
|
#### Scenario: Tamano de archivo de clase
|
||||||
|
- **WHEN** se crea un archivo de clase
|
||||||
|
- **THEN** DEBERIA tener menos de 300 lineas
|
||||||
|
- **AND** si es mas grande, DEBERIA dividirse en clases mas pequenas
|
||||||
|
|
||||||
|
#### Scenario: Tamano de metodo
|
||||||
|
- **WHEN** se escribe un metodo
|
||||||
|
- **THEN** DEBERIA tener menos de 30 lineas
|
||||||
|
- **AND** metodos complejos DEBERIAN extraerse a metodos auxiliares
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Convenciones de Nomenclatura
|
||||||
|
|
||||||
|
Names MUST be clear, descriptive, and follow conventions.
|
||||||
|
|
||||||
|
#### Scenario: Nomenclatura de clases
|
||||||
|
- **WHEN** se nombra una clase
|
||||||
|
- **THEN** el nombre DEBE describir su unica responsabilidad
|
||||||
|
- **AND** las clases Use Case DEBEN nombrarse [Accion][Entidad]UseCase
|
||||||
|
- **AND** las clases Repository DEBEN nombrarse [Implementacion][Entidad]Repository
|
||||||
|
|
||||||
|
#### Scenario: Nomenclatura de metodos
|
||||||
|
- **WHEN** se nombra un metodo
|
||||||
|
- **THEN** DEBE describir lo que hace el metodo
|
||||||
|
- **AND** DEBERIA comenzar con un verbo
|
||||||
|
- **AND** metodos booleanos DEBERIAN comenzar con is/has/can
|
||||||
|
|
||||||
|
#### Scenario: Nomenclatura de variables
|
||||||
|
- **WHEN** se nombra una variable
|
||||||
|
- **THEN** DEBE ser descriptiva
|
||||||
|
- **AND** las abreviaturas DEBEN evitarse
|
||||||
|
- **AND** nombres de una letra solo para contadores de bucle
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Validacion Pre-Commit
|
||||||
|
|
||||||
|
Code MUST pass validation before commit.
|
||||||
|
|
||||||
|
#### Scenario: Verificacion de cumplimiento SOLID
|
||||||
|
- **WHEN** el codigo esta listo para commit
|
||||||
|
- **THEN** SRP cada clase tiene una responsabilidad
|
||||||
|
- **AND** OCP nuevas caracteristicas via extension, no modificacion
|
||||||
|
- **AND** LSP las subclases son sustituibles
|
||||||
|
- **AND** ISP las interfaces son pequenas 3-5 metodos
|
||||||
|
- **AND** DIP el constructor recibe interfaces
|
||||||
|
|
||||||
|
#### Scenario: Verificacion de cumplimiento POO
|
||||||
|
- **WHEN** el codigo esta listo para commit
|
||||||
|
- **THEN** las propiedades son private/protected
|
||||||
|
- **AND** la profundidad de herencia es max 2-3 niveles
|
||||||
|
- **AND** el polimorfismo esta implementado correctamente
|
||||||
|
- **AND** la abstraccion oculta complejidad
|
||||||
|
|
||||||
|
#### Scenario: Verificacion de calidad
|
||||||
|
- **WHEN** el codigo esta listo para commit
|
||||||
|
- **THEN** los archivos tienen menos de 300 lineas
|
||||||
|
- **AND** los nombres son claros y descriptivos
|
||||||
|
- **AND** no existe duplicacion de codigo
|
||||||
|
- **AND** no hay sobre-ingenieria presente
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Escaping Obligatorio en Output HTML
|
||||||
|
|
||||||
|
All HTML output MUST use WordPress escaping functions for security.
|
||||||
|
|
||||||
|
#### Scenario: Escaping de textos
|
||||||
|
- **WHEN** se genera output de texto en HTML
|
||||||
|
- **THEN** DEBE usar esc_html() para contenido de texto
|
||||||
|
|
||||||
|
#### Scenario: Escaping de atributos
|
||||||
|
- **WHEN** se genera un atributo HTML
|
||||||
|
- **THEN** DEBE usar esc_attr() para valores de atributos
|
||||||
|
|
||||||
|
#### Scenario: Escaping de URLs
|
||||||
|
- **WHEN** se genera una URL en href o src
|
||||||
|
- **THEN** DEBE usar esc_url() para URLs
|
||||||
|
|
||||||
|
#### Scenario: Escaping de textareas
|
||||||
|
- **WHEN** se genera contenido para textarea
|
||||||
|
- **THEN** DEBE usar esc_textarea() para el valor
|
||||||
|
|
||||||
|
#### Scenario: Prohibicion de output sin escaping
|
||||||
|
- **WHEN** se revisa codigo de Renderer o FormBuilder
|
||||||
|
- **THEN** NO DEBE existir echo o print de variables sin escaping
|
||||||
|
- **AND** NO DEBE existir interpolacion directa de variables en HTML
|
||||||
406
openspec/specs/flujo-componentes/spec.md
Normal file
406
openspec/specs/flujo-componentes/spec.md
Normal file
@@ -0,0 +1,406 @@
|
|||||||
|
# Especificacion de Flujo de Componentes
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
|
||||||
|
Define el flujo de trabajo de 5 fases para crear componentes en ROITheme, incluyendo convenciones de nomenclatura, estructura de archivos y validacion.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
### Requirement: Nomenclatura NO NEGOCIABLE
|
||||||
|
|
||||||
|
The system MUST follow strict naming conventions that are NON-NEGOTIABLE.
|
||||||
|
|
||||||
|
#### Scenario: Nomenclatura de component_name en JSON y BD
|
||||||
|
- **WHEN** se define el nombre del componente en JSON o base de datos
|
||||||
|
- **THEN** DEBE usar kebab-case
|
||||||
|
- **AND** ejemplo: featured-image, hero-section, top-bar
|
||||||
|
|
||||||
|
#### Scenario: Nomenclatura de archivo schema JSON
|
||||||
|
- **WHEN** se crea un archivo de schema JSON
|
||||||
|
- **THEN** el nombre DEBE ser kebab-case
|
||||||
|
- **AND** ejemplo: featured-image.json, hero-section.json
|
||||||
|
|
||||||
|
#### Scenario: Nomenclatura de carpeta de modulo
|
||||||
|
- **WHEN** se crea la carpeta del modulo
|
||||||
|
- **THEN** DEBE usar PascalCase
|
||||||
|
- **AND** ejemplo: FeaturedImage/, HeroSection/, TopBar/
|
||||||
|
|
||||||
|
#### Scenario: Nomenclatura de namespace PHP
|
||||||
|
- **WHEN** se define el namespace PHP
|
||||||
|
- **THEN** DEBE usar PascalCase
|
||||||
|
- **AND** patron: ROITheme\[Contexto]\[Componente]\[Capa]
|
||||||
|
|
||||||
|
#### Scenario: Nomenclatura de clases Renderer y FormBuilder
|
||||||
|
- **WHEN** se nombran las clases Renderer o FormBuilder
|
||||||
|
- **THEN** DEBEN usar PascalCase
|
||||||
|
- **AND** ejemplo: FeaturedImageRenderer, HeroSectionFormBuilder
|
||||||
|
|
||||||
|
#### Scenario: Conversion kebab-case a PascalCase
|
||||||
|
- **WHEN** se convierte de kebab-case a PascalCase
|
||||||
|
- **THEN** se eliminan los guiones
|
||||||
|
- **AND** se capitaliza cada palabra
|
||||||
|
- **AND** ejemplo: featured-image se convierte en FeaturedImage
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Fase 1 - Creacion de Schema JSON
|
||||||
|
|
||||||
|
The first step MUST be creating the component JSON schema.
|
||||||
|
|
||||||
|
#### Scenario: Ubicacion del schema
|
||||||
|
- **WHEN** se crea un schema JSON
|
||||||
|
- **THEN** DEBE colocarse en Schemas/[nombre-en-kebab-case].json
|
||||||
|
- **AND** ejemplo: Schemas/featured-image.json
|
||||||
|
|
||||||
|
#### Scenario: Campo component_name en schema
|
||||||
|
- **WHEN** se define component_name en el schema
|
||||||
|
- **THEN** DEBE usar kebab-case
|
||||||
|
- **AND** ejemplo: component_name con valor featured-image
|
||||||
|
|
||||||
|
#### Scenario: Fuente del schema
|
||||||
|
- **WHEN** se extrae informacion para el schema
|
||||||
|
- **THEN** DEBE basarse en _planeacion/roi-theme/roi-theme-template/index.html
|
||||||
|
- **AND** DEBEN extraerse TODOS los campos CSS y textos del HTML
|
||||||
|
|
||||||
|
#### Scenario: Campos obligatorios de visibilidad
|
||||||
|
- **WHEN** se crea un schema
|
||||||
|
- **THEN** DEBE incluir is_enabled como boolean
|
||||||
|
- **AND** DEBE incluir show_on_desktop como boolean
|
||||||
|
- **AND** DEBE incluir show_on_mobile como boolean
|
||||||
|
|
||||||
|
#### Scenario: Grupos JSON estandar con priorities
|
||||||
|
- **WHEN** se estructura un schema JSON
|
||||||
|
- **THEN** DEBE organizar campos en los 12 grupos estandar con priorities fijas
|
||||||
|
- **AND** VISIBILITY DEBE tener priority 10
|
||||||
|
- **AND** CONTENT DEBE tener priority 20
|
||||||
|
- **AND** TYPOGRAPHY DEBE tener priority 30
|
||||||
|
- **AND** COLORS DEBE tener priority 40
|
||||||
|
- **AND** SPACING DEBE tener priority 50
|
||||||
|
- **AND** VISUAL_EFFECTS DEBE tener priority 60
|
||||||
|
- **AND** BEHAVIOR DEBE tener priority 70
|
||||||
|
- **AND** LAYOUT DEBE tener priority 80
|
||||||
|
- **AND** LINKS, ICONS, MEDIA, FORMS DEBEN tener priority 90
|
||||||
|
|
||||||
|
#### Scenario: Tipos de campo validos en schema
|
||||||
|
- **WHEN** se define un campo en el schema JSON
|
||||||
|
- **THEN** el type DEBE ser uno de: boolean, text, textarea, url, select, color
|
||||||
|
- **AND** si type es select DEBE incluir array de options
|
||||||
|
- **AND** si type es boolean el default DEBE ser true o false
|
||||||
|
- **AND** si type es color el default DEBE ser formato hexadecimal (#RRGGBB)
|
||||||
|
|
||||||
|
#### Scenario: Campo heading_level para semantica HTML
|
||||||
|
- **WHEN** un componente tiene titulo principal
|
||||||
|
- **THEN** el grupo TYPOGRAPHY DEBE incluir campo heading_level
|
||||||
|
- **AND** heading_level DEBE ser tipo select con options h1, h2, h3, h4, h5, h6
|
||||||
|
- **AND** heading_level es critico para jerarquia semantica y SEO
|
||||||
|
|
||||||
|
#### Scenario: Campos de accesibilidad en MEDIA
|
||||||
|
- **WHEN** un componente tiene imagenes
|
||||||
|
- **THEN** el grupo MEDIA DEBE incluir campo image_alt
|
||||||
|
- **AND** image_alt es obligatorio para accesibilidad (WCAG)
|
||||||
|
- **WHEN** la imagen puede compartirse en redes sociales
|
||||||
|
- **THEN** DEBE incluir campo is_og_image como boolean
|
||||||
|
|
||||||
|
#### Scenario: Campos tipicos del grupo BEHAVIOR
|
||||||
|
- **WHEN** un componente tiene comportamiento interactivo
|
||||||
|
- **THEN** el grupo BEHAVIOR puede incluir is_sticky, sticky_offset, collapse_on_mobile
|
||||||
|
- **AND** para Table of Contents puede incluir generate_jump_links, enable_scrollspy
|
||||||
|
- **AND** para animaciones puede incluir animation_type
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Fase 2 - Sincronizacion JSON a BD
|
||||||
|
|
||||||
|
The second step MUST synchronize the JSON schema with the database.
|
||||||
|
|
||||||
|
#### Scenario: Comando de sincronizacion
|
||||||
|
- **WHEN** se necesita sincronizar un componente
|
||||||
|
- **THEN** ejecutar wp roi-theme sync-component [nombre]
|
||||||
|
- **AND** ejemplo: wp roi-theme sync-component featured-image
|
||||||
|
|
||||||
|
#### Scenario: Tabla destino
|
||||||
|
- **WHEN** se sincroniza
|
||||||
|
- **THEN** los datos van a la tabla wp_roi_theme_component_settings
|
||||||
|
|
||||||
|
#### Scenario: Preservacion de valores
|
||||||
|
- **WHEN** se sincroniza un schema actualizado
|
||||||
|
- **THEN** los valores existentes del usuario DEBEN preservarse
|
||||||
|
- **AND** solo se agregan campos nuevos
|
||||||
|
|
||||||
|
#### Scenario: Conversion de valores para almacenamiento
|
||||||
|
- **WHEN** se sincroniza un campo a BD
|
||||||
|
- **THEN** arrays y objects DEBEN convertirse con json_encode()
|
||||||
|
- **AND** booleans DEBEN convertirse a '1' o '0'
|
||||||
|
- **AND** otros tipos DEBEN convertirse a string con cast
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Fase 3 - Creacion del Renderer
|
||||||
|
|
||||||
|
The third step MUST create the Renderer that converts DB data to HTML + CSS.
|
||||||
|
|
||||||
|
#### Scenario: Ubicacion del Renderer
|
||||||
|
- **WHEN** se crea un Renderer
|
||||||
|
- **THEN** DEBE colocarse en Public/[PascalCase]/Infrastructure/Ui/[PascalCase]Renderer.php
|
||||||
|
- **AND** ejemplo: Public/FeaturedImage/Infrastructure/Ui/FeaturedImageRenderer.php
|
||||||
|
|
||||||
|
#### Scenario: Inyeccion de CSSGeneratorInterface
|
||||||
|
- **WHEN** se implementa un Renderer
|
||||||
|
- **THEN** DEBE inyectar CSSGeneratorInterface via constructor
|
||||||
|
- **AND** NO DEBE tener CSS hardcodeado
|
||||||
|
|
||||||
|
#### Scenario: Generacion de CSS
|
||||||
|
- **WHEN** se genera CSS en el Renderer
|
||||||
|
- **THEN** DEBE usar $this->cssGenerator->generate()
|
||||||
|
- **AND** CERO CSS hardcodeado en el codigo PHP
|
||||||
|
|
||||||
|
#### Scenario: Validacion de visibilidad
|
||||||
|
- **WHEN** el Renderer procesa un componente
|
||||||
|
- **THEN** DEBE validar is_enabled, show_on_desktop, show_on_mobile
|
||||||
|
- **AND** NO renderizar si no cumple condiciones de visibilidad
|
||||||
|
|
||||||
|
#### Scenario: Clases responsive Bootstrap para visibilidad
|
||||||
|
- **WHEN** el Renderer genera HTML para show_on_desktop y show_on_mobile
|
||||||
|
- **THEN** DEBE usar clases Bootstrap d-none, d-lg-block, d-lg-none
|
||||||
|
- **AND** NO DEBE usar CSS custom para visibilidad responsive
|
||||||
|
- **AND** el breakpoint principal es lg (992px)
|
||||||
|
|
||||||
|
#### Scenario: Tabla de decision para visibilidad responsive
|
||||||
|
- **GIVEN** campos show_on_desktop y show_on_mobile del componente
|
||||||
|
- **WHEN** show_on_desktop es false AND show_on_mobile es true
|
||||||
|
- **THEN** aplicar clase d-lg-none (solo visible en mobile)
|
||||||
|
- **WHEN** show_on_desktop es true AND show_on_mobile es false
|
||||||
|
- **THEN** aplicar clases d-none d-lg-block (solo visible en desktop)
|
||||||
|
- **WHEN** show_on_desktop es false AND show_on_mobile es false
|
||||||
|
- **THEN** NO renderizar componente y retornar string vacio
|
||||||
|
- **WHEN** show_on_desktop es true AND show_on_mobile es true
|
||||||
|
- **THEN** NO aplicar clases de visibilidad (visible en ambos)
|
||||||
|
|
||||||
|
#### Scenario: Metodo supports
|
||||||
|
- **WHEN** se implementa el metodo supports()
|
||||||
|
- **THEN** DEBE retornar el nombre en kebab-case
|
||||||
|
- **AND** ejemplo: return 'featured-image'
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Contrato de CSSGeneratorInterface
|
||||||
|
|
||||||
|
The CSS generation service MUST follow a specific contract defined in Shared.
|
||||||
|
|
||||||
|
#### Scenario: Ubicacion de CSSGeneratorInterface
|
||||||
|
- **WHEN** se necesita la interface de generacion CSS
|
||||||
|
- **THEN** DEBE estar en Shared/Domain/Contracts/CSSGeneratorInterface.php
|
||||||
|
|
||||||
|
#### Scenario: Firma del metodo generate
|
||||||
|
- **WHEN** se implementa CSSGeneratorInterface
|
||||||
|
- **THEN** DEBE tener metodo generate(string $selector, array $styles): string
|
||||||
|
- **AND** $selector es el selector CSS (ej: '.navbar')
|
||||||
|
- **AND** $styles es array asociativo de propiedades CSS
|
||||||
|
- **AND** retorna string CSS formateado
|
||||||
|
|
||||||
|
#### Scenario: Conversion de propiedades CSS
|
||||||
|
- **WHEN** CSSGeneratorService procesa array de estilos
|
||||||
|
- **THEN** DEBE convertir snake_case a kebab-case
|
||||||
|
- **AND** ejemplo: background_color se convierte en background-color
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Fase 4 - Creacion del FormBuilder
|
||||||
|
|
||||||
|
The fourth step MUST create the FormBuilder for the admin panel.
|
||||||
|
|
||||||
|
#### Scenario: Ubicacion del FormBuilder
|
||||||
|
- **WHEN** se crea un FormBuilder
|
||||||
|
- **THEN** DEBE colocarse en Admin/[PascalCase]/Infrastructure/Ui/[PascalCase]FormBuilder.php
|
||||||
|
- **AND** ejemplo: Admin/FeaturedImage/Infrastructure/Ui/FeaturedImageFormBuilder.php
|
||||||
|
|
||||||
|
#### Scenario: Inyeccion de AdminDashboardRenderer
|
||||||
|
- **WHEN** se implementa un FormBuilder
|
||||||
|
- **THEN** DEBE inyectar AdminDashboardRenderer
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Contrato de AdminDashboardRenderer
|
||||||
|
|
||||||
|
The admin panel rendering service MUST follow a specific contract.
|
||||||
|
|
||||||
|
#### Scenario: Ubicacion de AdminDashboardRenderer
|
||||||
|
- **WHEN** se necesita el renderer del panel admin
|
||||||
|
- **THEN** DEBE estar en Admin/Shared/Infrastructure/Ui/AdminDashboardRenderer.php
|
||||||
|
|
||||||
|
#### Scenario: Responsabilidad de AdminDashboardRenderer
|
||||||
|
- **WHEN** se usa AdminDashboardRenderer
|
||||||
|
- **THEN** DEBE generar el HTML de controles de formulario
|
||||||
|
- **AND** DEBE aplicar el Design System del admin (gradiente, bordes)
|
||||||
|
- **AND** DEBE usar Bootstrap 5 form controls
|
||||||
|
|
||||||
|
#### Scenario: Design System del admin
|
||||||
|
- **WHEN** se implementa la UI del admin
|
||||||
|
- **THEN** DEBE usar gradiente #0E2337 a #1e3a5f
|
||||||
|
- **AND** borde naranja #FF8600
|
||||||
|
- **AND** Bootstrap 5 form controls
|
||||||
|
|
||||||
|
#### Scenario: Registro en getComponents
|
||||||
|
- **WHEN** se registra el FormBuilder
|
||||||
|
- **THEN** DEBE registrarse en getComponents() con ID en kebab-case
|
||||||
|
- **AND** ejemplo: 'featured-image'
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Fase 5 - Validacion de Arquitectura
|
||||||
|
|
||||||
|
The fifth and final step MUST validate the component architecture.
|
||||||
|
|
||||||
|
#### Scenario: Comando de validacion
|
||||||
|
- **WHEN** se necesita validar un componente
|
||||||
|
- **THEN** ejecutar php Shared/Infrastructure/Scripts/validate-architecture.php [nombre]
|
||||||
|
- **AND** ejemplo: php Shared/Infrastructure/Scripts/validate-architecture.php featured-image
|
||||||
|
|
||||||
|
#### Scenario: Elementos validados
|
||||||
|
- **WHEN** se ejecuta la validacion
|
||||||
|
- **THEN** DEBE validar estructura de carpetas
|
||||||
|
- **AND** DEBE validar schema JSON
|
||||||
|
- **AND** DEBE validar datos en BD
|
||||||
|
- **AND** DEBE validar Renderer
|
||||||
|
- **AND** DEBE validar FormBuilder
|
||||||
|
- **AND** DEBE validar cumplimiento SOLID
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Estructura de Archivos por Componente
|
||||||
|
|
||||||
|
A complete component MUST have a specific file structure.
|
||||||
|
|
||||||
|
#### Scenario: Estructura de componente en Public
|
||||||
|
- **GIVEN** un componente FeaturedImage en Public
|
||||||
|
- **WHEN** esta completo
|
||||||
|
- **THEN** DEBE existir Public/FeaturedImage/Infrastructure/Ui/FeaturedImageRenderer.php
|
||||||
|
|
||||||
|
#### Scenario: Estructura de componente en Admin
|
||||||
|
- **GIVEN** un componente FeaturedImage en Admin
|
||||||
|
- **WHEN** esta completo
|
||||||
|
- **THEN** DEBE existir Admin/FeaturedImage/Infrastructure/Ui/FeaturedImageFormBuilder.php
|
||||||
|
|
||||||
|
#### Scenario: Archivo schema
|
||||||
|
- **GIVEN** un componente FeaturedImage
|
||||||
|
- **WHEN** se necesita el schema
|
||||||
|
- **THEN** DEBE existir en Schemas/featured-image.json
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Variables CSS del Tema
|
||||||
|
|
||||||
|
Code MUST use the theme CSS variables.
|
||||||
|
|
||||||
|
#### Scenario: Variables de color disponibles
|
||||||
|
- **WHEN** se necesitan colores
|
||||||
|
- **THEN** DEBEN usarse las variables como --color-navy-dark y --color-orange-primary
|
||||||
|
|
||||||
|
#### Scenario: Prohibicion de CSS hardcodeado
|
||||||
|
- **WHEN** se genera CSS
|
||||||
|
- **THEN** NO DEBE haber colores hardcodeados en PHP
|
||||||
|
- **AND** DEBE usarse CSSGeneratorService
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Reglas NO Negociables del Flujo
|
||||||
|
|
||||||
|
These rules MUST always be followed, without exceptions.
|
||||||
|
|
||||||
|
#### Scenario: Creacion de archivos
|
||||||
|
- **WHEN** se van a crear archivos para un componente
|
||||||
|
- **THEN** DEBE leerse primero el template HTML
|
||||||
|
- **AND** NO crear archivos sin esa referencia
|
||||||
|
|
||||||
|
#### Scenario: Campos de visibilidad
|
||||||
|
- **WHEN** se crea un schema
|
||||||
|
- **THEN** NO DEBE omitirse ninguno de los 3 campos obligatorios de visibilidad
|
||||||
|
|
||||||
|
#### Scenario: CSS en Renderers
|
||||||
|
- **WHEN** se implementa un Renderer
|
||||||
|
- **THEN** NO DEBE haber CSS inline
|
||||||
|
- **AND** todo via CSSGeneratorService
|
||||||
|
|
||||||
|
#### Scenario: Instanciacion de servicios
|
||||||
|
- **WHEN** se necesita un servicio
|
||||||
|
- **THEN** NO instanciar directamente con new Service()
|
||||||
|
- **AND** DEBE usarse Inyeccion de Dependencias
|
||||||
|
|
||||||
|
#### Scenario: Modificacion de campos en BD
|
||||||
|
- **WHEN** se necesita modificar campos
|
||||||
|
- **THEN** NO modificar campos en BD manualmente
|
||||||
|
- **AND** modificar el schema JSON y sincronizar
|
||||||
|
|
||||||
|
#### Scenario: Validacion de arquitectura
|
||||||
|
- **WHEN** se completa un componente
|
||||||
|
- **THEN** NO saltarse la validacion de arquitectura
|
||||||
|
- **AND** ejecutar validate-architecture.php
|
||||||
|
|
||||||
|
#### Scenario: Fases completas
|
||||||
|
- **WHEN** se crea un componente
|
||||||
|
- **THEN** NO crear componentes sin completar las 5 fases
|
||||||
|
- **AND** cada fase es obligatoria
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Comandos WP-CLI
|
||||||
|
|
||||||
|
WP-CLI commands MUST be executed with the correct configuration.
|
||||||
|
|
||||||
|
#### Scenario: Ubicacion de WP-CLI
|
||||||
|
- **WHEN** se necesita ejecutar WP-CLI
|
||||||
|
- **THEN** usar C:\xampp\php_8.0.30_backup\wp-cli.phar
|
||||||
|
|
||||||
|
#### Scenario: Sincronizar un componente
|
||||||
|
- **WHEN** se sincroniza un componente especifico
|
||||||
|
- **THEN** ejecutar powershell -Command "php 'C:\xampp\php_8.0.30_backup\wp-cli.phar' roi-theme sync-component [nombre]"
|
||||||
|
|
||||||
|
#### Scenario: Sincronizar todos los componentes
|
||||||
|
- **WHEN** se sincroniza todo
|
||||||
|
- **THEN** ejecutar powershell -Command "php 'C:\xampp\php_8.0.30_backup\wp-cli.phar' roi-theme sync-all-components"
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Flujo de 5 Fases Secuencial
|
||||||
|
|
||||||
|
Component creation MUST follow the exact sequence.
|
||||||
|
|
||||||
|
#### Scenario: Flujo completo de 5 fases
|
||||||
|
- **WHEN** se crea un nuevo componente
|
||||||
|
- **THEN** Fase 1 es crear Schema JSON en Schemas/[nombre].json
|
||||||
|
- **AND** Fase 2 es sincronizar con wp roi-theme sync-component [nombre]
|
||||||
|
- **AND** Fase 3 es crear Renderer en Public/[Nombre]/Infrastructure/Ui/[Nombre]Renderer.php
|
||||||
|
- **AND** Fase 4 es crear FormBuilder en Admin/[Nombre]/Infrastructure/Ui/[Nombre]FormBuilder.php
|
||||||
|
- **AND** Fase 5 es validar con validate-architecture.php [nombre]
|
||||||
|
|
||||||
|
#### Scenario: No saltar fases
|
||||||
|
- **WHEN** se desarrolla un componente
|
||||||
|
- **THEN** NO se DEBE saltar ninguna fase
|
||||||
|
- **AND** cada fase depende de la anterior
|
||||||
|
- **AND** la validacion final es obligatoria
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Checklist de Componente Completo
|
||||||
|
|
||||||
|
A component MUST pass the checklist to be considered complete.
|
||||||
|
|
||||||
|
#### Scenario: Checklist de archivos
|
||||||
|
- **WHEN** se verifica un componente
|
||||||
|
- **THEN** DEBE existir Schemas/[nombre-kebab].json
|
||||||
|
- **AND** DEBE existir Public/[NombrePascal]/Infrastructure/Ui/[NombrePascal]Renderer.php
|
||||||
|
- **AND** DEBE existir Admin/[NombrePascal]/Infrastructure/Ui/[NombrePascal]FormBuilder.php
|
||||||
|
|
||||||
|
#### Scenario: Checklist de codigo
|
||||||
|
- **WHEN** se verifica el codigo
|
||||||
|
- **THEN** schema tiene los 3 campos de visibilidad
|
||||||
|
- **AND** Renderer inyecta CSSGeneratorInterface
|
||||||
|
- **AND** Renderer no tiene CSS hardcodeado
|
||||||
|
- **AND** supports() retorna kebab-case
|
||||||
|
- **AND** FormBuilder registrado con ID kebab-case
|
||||||
|
- **AND** validacion de arquitectura pasa
|
||||||
|
|
||||||
|
#### Scenario: Checklist de BD
|
||||||
|
- **WHEN** se verifica la base de datos
|
||||||
|
- **THEN** datos sincronizados en wp_roi_theme_component_settings
|
||||||
|
- **AND** component_name en kebab-case
|
||||||
255
openspec/specs/patrones-wordpress/spec.md
Normal file
255
openspec/specs/patrones-wordpress/spec.md
Normal file
@@ -0,0 +1,255 @@
|
|||||||
|
# Especificacion de Patrones WordPress
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
|
||||||
|
Define como integrar WordPress con Clean Architecture en ROITheme. WordPress tiene caracteristicas propias que requieren patrones especificos para mantener la arquitectura limpia.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
### Requirement: Ubicacion de Hooks de WordPress
|
||||||
|
|
||||||
|
WordPress hooks (add_action, add_filter) MUST be located ONLY in Infrastructure.
|
||||||
|
|
||||||
|
#### Scenario: Hooks prohibidos en Domain
|
||||||
|
- **WHEN** el codigo esta en la capa Domain
|
||||||
|
- **THEN** NO DEBE contener add_action
|
||||||
|
- **AND** NO DEBE contener add_filter
|
||||||
|
- **AND** NO DEBE registrar callbacks de WordPress
|
||||||
|
|
||||||
|
#### Scenario: Hooks prohibidos en Application
|
||||||
|
- **WHEN** el codigo esta en la capa Application
|
||||||
|
- **THEN** NO DEBE contener add_action
|
||||||
|
- **AND** NO DEBE contener add_filter
|
||||||
|
|
||||||
|
#### Scenario: Ubicacion correcta de hooks
|
||||||
|
- **WHEN** se necesitan hooks de WordPress
|
||||||
|
- **THEN** DEBEN colocarse en Infrastructure/Wordpress/[Componente]HooksRegistrar.php
|
||||||
|
- **AND** los hooks DEBEN delegar a Use Cases
|
||||||
|
- **AND** los hooks NO DEBEN contener logica de negocio
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Encapsulacion de wpdb
|
||||||
|
|
||||||
|
Access to global $wpdb MUST be encapsulated in Infrastructure repositories.
|
||||||
|
|
||||||
|
#### Scenario: wpdb prohibido en Domain
|
||||||
|
- **WHEN** el codigo esta en la capa Domain
|
||||||
|
- **THEN** NO DEBE contener global $wpdb
|
||||||
|
- **AND** NO DEBE hacer consultas directas a base de datos
|
||||||
|
|
||||||
|
#### Scenario: wpdb prohibido en Application
|
||||||
|
- **WHEN** el codigo esta en la capa Application
|
||||||
|
- **THEN** NO DEBE contener global $wpdb
|
||||||
|
- **AND** DEBE usar interfaces de repository
|
||||||
|
|
||||||
|
#### Scenario: Ubicacion correcta de wpdb
|
||||||
|
- **WHEN** se necesita acceso a base de datos
|
||||||
|
- **THEN** DEBE usarse en Infrastructure/Persistence/WordPress[Componente]Repository.php
|
||||||
|
- **AND** el repository DEBE implementar una interface definida en Domain
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Ubicacion de wp_enqueue_scripts
|
||||||
|
|
||||||
|
Functions wp_enqueue_style and wp_enqueue_script MUST be located ONLY in Infrastructure.
|
||||||
|
|
||||||
|
#### Scenario: Enqueue prohibido en Domain
|
||||||
|
- **WHEN** el codigo esta en la capa Domain
|
||||||
|
- **THEN** NO DEBE contener wp_enqueue_style
|
||||||
|
- **AND** NO DEBE contener wp_enqueue_script
|
||||||
|
|
||||||
|
#### Scenario: Enqueue prohibido en Application
|
||||||
|
- **WHEN** el codigo esta en la capa Application
|
||||||
|
- **THEN** NO DEBE contener funciones de enqueue
|
||||||
|
- **AND** NO DEBE conocer detalles de assets
|
||||||
|
|
||||||
|
#### Scenario: Ubicacion correcta de enqueue
|
||||||
|
- **WHEN** se necesita cargar assets
|
||||||
|
- **THEN** DEBE colocarse en Infrastructure/Services/[Componente]AssetEnqueuer.php
|
||||||
|
- **AND** DEBE registrarse via hooks en Infrastructure
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Ubicacion de register_post_type
|
||||||
|
|
||||||
|
CPT and taxonomy registration MUST be located ONLY in Infrastructure.
|
||||||
|
|
||||||
|
#### Scenario: CPT no es concepto de Domain
|
||||||
|
- **WHEN** se considera donde registrar un Custom Post Type
|
||||||
|
- **THEN** NO DEBE ir en Domain porque no es concepto de negocio
|
||||||
|
- **AND** NO DEBE ir en Application
|
||||||
|
- **AND** ES un detalle de implementacion de WordPress
|
||||||
|
|
||||||
|
#### Scenario: Ubicacion correcta de CPT
|
||||||
|
- **WHEN** se necesita registrar un Custom Post Type
|
||||||
|
- **THEN** DEBE colocarse en Infrastructure/Wordpress/[Componente]CPTRegistrar.php
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Ubicacion de add_shortcode
|
||||||
|
|
||||||
|
Shortcodes MUST be located ONLY in Infrastructure and delegate to Use Cases.
|
||||||
|
|
||||||
|
#### Scenario: Shortcode prohibido en Domain y Application
|
||||||
|
- **WHEN** el codigo esta en Domain o Application
|
||||||
|
- **THEN** NO DEBE contener add_shortcode
|
||||||
|
|
||||||
|
#### Scenario: Ubicacion correcta de shortcode
|
||||||
|
- **WHEN** se necesita un shortcode
|
||||||
|
- **THEN** DEBE colocarse en Infrastructure/Wordpress/[Componente]ShortcodeRegistrar.php
|
||||||
|
- **AND** DEBE delegar la logica a un Use Case
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Ubicacion de Options API
|
||||||
|
|
||||||
|
WordPress Options API MUST be encapsulated in Infrastructure repositories.
|
||||||
|
|
||||||
|
#### Scenario: Options prohibidas en Domain y Application
|
||||||
|
- **WHEN** el codigo esta en Domain o Application
|
||||||
|
- **THEN** NO DEBE contener get_option
|
||||||
|
- **AND** NO DEBE contener update_option
|
||||||
|
- **AND** NO DEBE contener delete_option
|
||||||
|
|
||||||
|
#### Scenario: Ubicacion correcta de Options
|
||||||
|
- **WHEN** se necesita acceso a opciones de WordPress
|
||||||
|
- **THEN** DEBE colocarse en Infrastructure/Persistence/WordPressSettingsRepository.php
|
||||||
|
- **AND** DEBE implementar una interface de Application
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Evitar functions.php Gigante
|
||||||
|
|
||||||
|
The functions.php file MUST contain only bootstrap, not logic.
|
||||||
|
|
||||||
|
#### Scenario: functions.php correcto
|
||||||
|
- **WHEN** se implementa functions.php
|
||||||
|
- **THEN** DEBE contener solo Autoloader, Container DI y Bootstrap
|
||||||
|
- **AND** NO DEBE contener logica de negocio
|
||||||
|
- **AND** NO DEBE contener definiciones de funciones de negocio
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Evitar Logica en Templates
|
||||||
|
|
||||||
|
Templates MUST contain only rendering, not business logic.
|
||||||
|
|
||||||
|
#### Scenario: Template prohibido con logica
|
||||||
|
- **WHEN** un template de WordPress existe
|
||||||
|
- **THEN** NO DEBE contener global $wpdb
|
||||||
|
- **AND** NO DEBE contener validaciones de negocio
|
||||||
|
- **AND** NO DEBE contener consultas a base de datos
|
||||||
|
- **AND** NO DEBE contener cadenas if/elseif complejas
|
||||||
|
|
||||||
|
#### Scenario: Template correcto
|
||||||
|
- **WHEN** se crea un template
|
||||||
|
- **THEN** DEBE recibir un ViewModel preparado
|
||||||
|
- **AND** DEBE contener solo HTML con escaping
|
||||||
|
- **AND** DEBE usar esc_html(), esc_attr(), esc_url()
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Evitar wpdb Disperso
|
||||||
|
|
||||||
|
Usage of wpdb MUST NOT be scattered throughout the code.
|
||||||
|
|
||||||
|
#### Scenario: wpdb centralizado
|
||||||
|
- **WHEN** se necesita acceso a base de datos
|
||||||
|
- **THEN** DEBE usarse SOLO en repositories
|
||||||
|
- **AND** los repositories DEBEN estar en Infrastructure/Persistence/
|
||||||
|
- **AND** multiples archivos NO DEBEN tener global $wpdb
|
||||||
|
|
||||||
|
#### Scenario: Beneficios de centralizacion
|
||||||
|
- **WHEN** wpdb esta centralizado en repositories
|
||||||
|
- **THEN** cambiar la base de datos requiere modificar solo repositories
|
||||||
|
- **AND** el testing es posible via mocks de interface
|
||||||
|
- **AND** la logica de negocio permanece pura
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Evitar Variables Globales Masivas
|
||||||
|
|
||||||
|
Code MUST NOT use massive global variables.
|
||||||
|
|
||||||
|
#### Scenario: Globales prohibidas
|
||||||
|
- **WHEN** se escribe codigo
|
||||||
|
- **THEN** NO DEBE usar global $roi_config
|
||||||
|
- **AND** NO DEBE usar singletons dispersos
|
||||||
|
- **AND** NO DEBE crear estado global
|
||||||
|
|
||||||
|
#### Scenario: Solucion con Dependency Injection
|
||||||
|
- **WHEN** se necesitan dependencias compartidas
|
||||||
|
- **THEN** DEBE usarse un Container de Inyeccion de Dependencias
|
||||||
|
- **AND** las dependencias se inyectan via constructor
|
||||||
|
- **AND** no hay estado global
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Codigo Testeable
|
||||||
|
|
||||||
|
Code MUST be testable without WordPress installed.
|
||||||
|
|
||||||
|
#### Scenario: Domain testeable
|
||||||
|
- **WHEN** se escribe codigo de Domain
|
||||||
|
- **THEN** DEBE ser testeable sin base de datos
|
||||||
|
- **AND** DEBE ser testeable sin WordPress
|
||||||
|
- **AND** DEBE ser testeable sin UI
|
||||||
|
|
||||||
|
#### Scenario: Mocks via interfaces
|
||||||
|
- **WHEN** se escriben tests
|
||||||
|
- **THEN** las dependencias se mockean via interfaces
|
||||||
|
- **AND** los tests unitarios NO requieren setup complejo
|
||||||
|
- **AND** Domain puede probarse de forma aislada
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Arbol de Decisiones WordPress
|
||||||
|
|
||||||
|
WordPress code MUST be located according to code type.
|
||||||
|
|
||||||
|
#### Scenario: Determinar ubicacion de hooks
|
||||||
|
- **WHEN** el codigo es add_action o add_filter
|
||||||
|
- **THEN** va en Infrastructure/Wordpress/[Componente]HooksRegistrar.php
|
||||||
|
|
||||||
|
#### Scenario: Determinar ubicacion de wpdb
|
||||||
|
- **WHEN** el codigo usa global $wpdb
|
||||||
|
- **THEN** va en Infrastructure/Persistence/WordPress[Componente]Repository.php
|
||||||
|
|
||||||
|
#### Scenario: Determinar ubicacion de enqueue
|
||||||
|
- **WHEN** el codigo usa wp_enqueue_style o wp_enqueue_script
|
||||||
|
- **THEN** va en Infrastructure/Services/[Componente]AssetEnqueuer.php
|
||||||
|
|
||||||
|
#### Scenario: Determinar ubicacion de CPT
|
||||||
|
- **WHEN** el codigo usa register_post_type o register_taxonomy
|
||||||
|
- **THEN** va en Infrastructure/Wordpress/[Componente]CPTRegistrar.php
|
||||||
|
|
||||||
|
#### Scenario: Determinar ubicacion de shortcode
|
||||||
|
- **WHEN** el codigo usa add_shortcode
|
||||||
|
- **THEN** va en Infrastructure/Wordpress/[Componente]ShortcodeRegistrar.php
|
||||||
|
|
||||||
|
#### Scenario: Determinar ubicacion de options
|
||||||
|
- **WHEN** el codigo usa get_option o update_option
|
||||||
|
- **THEN** va en Infrastructure/Persistence/WordPressSettingsRepository.php
|
||||||
|
|
||||||
|
#### Scenario: Determinar ubicacion de nonces
|
||||||
|
- **WHEN** el codigo usa wp_nonce_field o check_admin_referer
|
||||||
|
- **THEN** va en Infrastructure/Api/Wordpress/[Componente]Controller.php
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Comandos de Validacion WordPress
|
||||||
|
|
||||||
|
Code MUST be validated with specific commands.
|
||||||
|
|
||||||
|
#### Scenario: Validar Domain sin WordPress
|
||||||
|
- **WHEN** se valida la capa Domain
|
||||||
|
- **THEN** grep por global $wpdb DEBE retornar vacio
|
||||||
|
- **AND** grep por add_action DEBE retornar vacio
|
||||||
|
- **AND** grep por $_POST DEBE retornar vacio
|
||||||
|
|
||||||
|
#### Scenario: Validar Application sin WordPress
|
||||||
|
- **WHEN** se valida la capa Application
|
||||||
|
- **THEN** grep por global $wpdb DEBE retornar vacio
|
||||||
|
- **AND** grep por add_action DEBE retornar vacio
|
||||||
|
- **AND** grep por wp_enqueue DEBE retornar vacio
|
||||||
Reference in New Issue
Block a user