docs(config): add cache-first-architecture specification
Define arquitectura cache-first para ROI-Theme: - Hook roi_theme_before_page_serve en template_redirect p=0 - Solo para páginas singulares y usuarios anónimos - Permite que plugins externos evalúen acceso antes de servir página - NO define DONOTCACHEPAGE (permite cache) Plan 1000.01 - Preparación para integración con IP View Limit. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
154
openspec/specs/cache-first-architecture/spec.md
Normal file
154
openspec/specs/cache-first-architecture/spec.md
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
# Especificacion de Arquitectura Cache-First
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
|
||||||
|
Define la arquitectura cache-first para ROITheme que permite que plugins de cache (W3TC, Redis, etc.) funcionen correctamente mientras plugins externos pueden evaluar condiciones ANTES de servir paginas.
|
||||||
|
|
||||||
|
Esta arquitectura:
|
||||||
|
- Permite que las paginas se sirvan desde cache siempre que sea posible
|
||||||
|
- Provee hooks para que plugins externos (rate limiters, access control, etc.) evaluen condiciones
|
||||||
|
- Desacopla el tema de plugins especificos de restriccion de acceso
|
||||||
|
- Es portable: cualquier sitio con roi-theme tiene esta capacidad
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
### Requirement: Hook de Pre-Evaluacion de Pagina
|
||||||
|
|
||||||
|
The system MUST provide a hook that fires BEFORE WordPress serves a page, allowing external plugins to evaluate conditions and potentially redirect.
|
||||||
|
|
||||||
|
#### Scenario: Plugin externo necesita evaluar acceso antes de servir pagina
|
||||||
|
- **GIVEN** un plugin de control de acceso (rate limiter, membership, etc.)
|
||||||
|
- **WHEN** un visitante solicita una pagina singular (post, page, CPT)
|
||||||
|
- **THEN** el tema DEBE disparar `do_action('roi_theme_before_page_serve', $post_id)`
|
||||||
|
- **AND** el hook DEBE ejecutarse en `template_redirect` con priority 0
|
||||||
|
- **AND** si el plugin llama `wp_safe_redirect()` y `exit`, la pagina NO se sirve
|
||||||
|
|
||||||
|
#### Scenario: Ningn plugin enganchado al hook
|
||||||
|
- **GIVEN** ningun plugin esta escuchando `roi_theme_before_page_serve`
|
||||||
|
- **WHEN** un visitante solicita una pagina
|
||||||
|
- **THEN** la pagina se sirve normalmente (con cache si disponible)
|
||||||
|
- **AND** no hay impacto en rendimiento
|
||||||
|
|
||||||
|
#### Scenario: Hook solo dispara en paginas singulares
|
||||||
|
- **GIVEN** el hook `roi_theme_before_page_serve`
|
||||||
|
- **WHEN** la solicitud es para archivo, home, search, feed, o admin
|
||||||
|
- **THEN** el hook NO DEBE dispararse
|
||||||
|
- **AND** la pagina se sirve sin evaluacion adicional
|
||||||
|
|
||||||
|
#### Scenario: Hook no dispara para usuarios logueados
|
||||||
|
- **GIVEN** un usuario autenticado (logged in)
|
||||||
|
- **WHEN** solicita cualquier pagina
|
||||||
|
- **THEN** el hook NO DEBE dispararse
|
||||||
|
- **AND** la pagina se sirve directamente sin evaluacion
|
||||||
|
- **BECAUSE** WordPress no cachea paginas para usuarios logueados (cookies de sesion)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Contexto Rico para Plugins Externos
|
||||||
|
|
||||||
|
The system MUST provide sufficient context for external plugins to make access decisions.
|
||||||
|
|
||||||
|
#### Scenario: Plugin necesita informacion del post
|
||||||
|
- **GIVEN** un plugin enganchado a `roi_theme_before_page_serve`
|
||||||
|
- **WHEN** el hook se dispara
|
||||||
|
- **THEN** el plugin recibe `$post_id` como parametro
|
||||||
|
- **AND** `get_queried_object()` retorna el objeto WP_Post completo
|
||||||
|
- **AND** `is_singular()`, `is_single()`, `is_page()` funcionan correctamente
|
||||||
|
|
||||||
|
#### Scenario: Plugin necesita informacion del visitante
|
||||||
|
- **GIVEN** un plugin enganchado a `roi_theme_before_page_serve`
|
||||||
|
- **WHEN** el hook se dispara
|
||||||
|
- **THEN** `is_user_logged_in()` esta disponible
|
||||||
|
- **AND** `$_SERVER['REMOTE_ADDR']` esta disponible
|
||||||
|
- **AND** headers HTTP estan disponibles via `$_SERVER`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: No Bloquear Cache
|
||||||
|
|
||||||
|
The system MUST NOT define DONOTCACHEPAGE or similar constants that prevent caching.
|
||||||
|
|
||||||
|
#### Scenario: Tema no interfiere con plugins de cache
|
||||||
|
- **GIVEN** el tema roi-theme instalado
|
||||||
|
- **WHEN** W3TC, WP Super Cache, o Redis Object Cache estan activos
|
||||||
|
- **THEN** el tema NO DEBE definir `DONOTCACHEPAGE`
|
||||||
|
- **AND** el tema NO DEBE definir `DONOTCACHEOBJECT`
|
||||||
|
- **AND** el tema NO DEBE enviar headers `Cache-Control: no-cache`
|
||||||
|
|
||||||
|
#### Scenario: Plugin externo decide bloquear cache
|
||||||
|
- **GIVEN** un plugin enganchado a `roi_theme_before_page_serve`
|
||||||
|
- **WHEN** el plugin necesita bloquear cache para una pagina especifica
|
||||||
|
- **THEN** es responsabilidad del PLUGIN definir `DONOTCACHEPAGE`
|
||||||
|
- **AND** el tema NO participa en esa decision
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Requirement: Ubicacion en Clean Architecture
|
||||||
|
|
||||||
|
The hook registration MUST follow ROITheme's Clean Architecture patterns.
|
||||||
|
|
||||||
|
#### Scenario: Hook registrado en Infrastructure
|
||||||
|
- **GIVEN** el sistema de hooks del tema
|
||||||
|
- **WHEN** el hook `roi_theme_before_page_serve` es registrado
|
||||||
|
- **THEN** el registro DEBE estar en `Shared/Infrastructure/Hooks/`
|
||||||
|
- **AND** DEBE seguir el patron de HooksRegistrar existente
|
||||||
|
|
||||||
|
#### Scenario: Servicio como punto de extension
|
||||||
|
- **GIVEN** la arquitectura del tema
|
||||||
|
- **WHEN** se necesita extender funcionalidad de pre-evaluacion
|
||||||
|
- **THEN** DEBE existir una interfaz en `Shared/Domain/Contracts/`
|
||||||
|
- **AND** la implementacion DEBE estar en `Shared/Infrastructure/Services/`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
### Hook Priority
|
||||||
|
|
||||||
|
```
|
||||||
|
template_redirect priority order:
|
||||||
|
├─ Priority 0: roi_theme_before_page_serve (tema dispara hook)
|
||||||
|
│ └─ Plugins externos se enganchan aqui
|
||||||
|
├─ Priority 1+: Otros plugins
|
||||||
|
└─ Priority 10 (default): WordPress template loading
|
||||||
|
```
|
||||||
|
|
||||||
|
### Ejemplo de Plugin Enganchado
|
||||||
|
|
||||||
|
```php
|
||||||
|
// En un plugin externo (ej: ip-rate-limiter)
|
||||||
|
add_action('roi_theme_before_page_serve', function(int $post_id) {
|
||||||
|
// Evaluar condicion (ej: limite de IP)
|
||||||
|
if ($this->is_limit_exceeded()) {
|
||||||
|
wp_safe_redirect('/suscripcion-vip/?reason=limit', 302);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
// Si no hay problema, simplemente retornar
|
||||||
|
// La pagina se servira (con cache si disponible)
|
||||||
|
}, 10);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Archivos a Crear
|
||||||
|
|
||||||
|
```
|
||||||
|
Shared/
|
||||||
|
├── Domain/
|
||||||
|
│ └── Contracts/
|
||||||
|
│ └── PageServeHookInterface.php # Interface del hook
|
||||||
|
└── Infrastructure/
|
||||||
|
└── Hooks/
|
||||||
|
└── CacheFirstHooksRegistrar.php # Registro del hook
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
1. El hook `roi_theme_before_page_serve` se dispara en `template_redirect` priority 0
|
||||||
|
2. Solo se dispara para `is_singular() === true`
|
||||||
|
3. NO se dispara para usuarios logueados (`is_user_logged_in() === true`)
|
||||||
|
4. Pasa `$post_id` como parametro al hook
|
||||||
|
5. No define DONOTCACHEPAGE ni headers anti-cache
|
||||||
|
6. Plugins externos pueden enganchar y hacer redirect/exit
|
||||||
|
7. Si ningun plugin engancha, no hay impacto en rendimiento
|
||||||
|
8. Sigue patrones de Clean Architecture del tema
|
||||||
Reference in New Issue
Block a user