From bf304f08fc44de2cf8572565748de04a9261a310 Mon Sep 17 00:00:00 2001 From: FrankZamora Date: Fri, 5 Dec 2025 14:44:50 -0600 Subject: [PATCH] fix(css): centrar verticalmente contenido del hero section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- .../Hero/Infrastructure/Ui/HeroRenderer.php | 3 + openspec/specs/arquitectura-limpia/spec.md | 215 ++++++++++ openspec/specs/estandares-codigo/spec.md | 350 +++++++++++++++ openspec/specs/flujo-componentes/spec.md | 406 ++++++++++++++++++ openspec/specs/patrones-wordpress/spec.md | 255 +++++++++++ 5 files changed, 1229 insertions(+) create mode 100644 openspec/specs/arquitectura-limpia/spec.md create mode 100644 openspec/specs/estandares-codigo/spec.md create mode 100644 openspec/specs/flujo-componentes/spec.md create mode 100644 openspec/specs/patrones-wordpress/spec.md diff --git a/Public/Hero/Infrastructure/Ui/HeroRenderer.php b/Public/Hero/Infrastructure/Ui/HeroRenderer.php index 39b77341..8e697c71 100644 --- a/Public/Hero/Infrastructure/Ui/HeroRenderer.php +++ b/Public/Hero/Infrastructure/Ui/HeroRenderer.php @@ -133,6 +133,9 @@ final class HeroRenderer implements RendererInterface 'padding' => "{$paddingVertical} 0", 'margin-bottom' => $marginBottom, 'min-height' => $minHeight, + 'display' => 'flex', + 'align-items' => 'center', + 'justify-content' => 'center', ]); $cssRules[] = $this->cssGenerator->generate('.hero-section__title', [ diff --git a/openspec/specs/arquitectura-limpia/spec.md b/openspec/specs/arquitectura-limpia/spec.md new file mode 100644 index 00000000..8281911f --- /dev/null +++ b/openspec/specs/arquitectura-limpia/spec.md @@ -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 diff --git a/openspec/specs/estandares-codigo/spec.md b/openspec/specs/estandares-codigo/spec.md new file mode 100644 index 00000000..8383e40b --- /dev/null +++ b/openspec/specs/estandares-codigo/spec.md @@ -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 diff --git a/openspec/specs/flujo-componentes/spec.md b/openspec/specs/flujo-componentes/spec.md new file mode 100644 index 00000000..0d8152c8 --- /dev/null +++ b/openspec/specs/flujo-componentes/spec.md @@ -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 diff --git a/openspec/specs/patrones-wordpress/spec.md b/openspec/specs/patrones-wordpress/spec.md new file mode 100644 index 00000000..db818446 --- /dev/null +++ b/openspec/specs/patrones-wordpress/spec.md @@ -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