docs(#8): plan de implementación del buscador Typesense (fase 2)

Plan ejecutable (para Sonnet) de la fase 2: arquitectura, schema, indexador,
UI InstantSearch con faceta de autor, seguridad de claves y verificación.
La decisión de dónde corre Typesense en producción queda pendiente; todo lo
demás se puede construir y validar en local.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-27 11:30:34 -04:00
parent 63e0057fd5
commit 493fd4d835
+88
View File
@@ -0,0 +1,88 @@
# Plan de implementación — Buscador con Typesense (feadulta #8, fase 2)
> **Estado:** plan para ejecutar (pensado para que lo ejecute un agente Sonnet).
> **Fase 1 (MVP nativo) ya está en producción** — ver `feadulta-buscador-8` / issue #8:
> barra de búsqueda visible en móvil (`mu-plugins/fea-search.php`) + resultados en
> rejilla (`scripts/set_search_template.php`). Esta fase 2 sustituye el **motor** por
> Typesense manteniendo/мejorando esa UI, y añade **búsqueda por autor** (faceta).
>
> **DECISIÓN PENDIENTE (Rafa) — dónde corre Typesense en producción.** Todo lo demás
> se puede construir y validar en **local** sin esa decisión (Typesense en Docker local).
> Opciones de despliegue público (decidir luego): (a) PC + Cloudflare Tunnel
> `search.feadulta.com` (coste 0, atado al PC encendido, fallback al buscador nativo);
> (b) VPS pequeño dedicado ~4-6€/mes (fiable); (c) Typesense Cloud (gestionado).
> El hosting actual (cPanel compartido, sin Docker/systemd/root) **no sirve** para el motor.
## Decisiones ya tomadas
- **Integración:** Custom InstantSearch (indexador propio + UI InstantSearch.js), NO plugin.
- **Motor:** Typesense self-host en Docker.
- **Fallback:** si Typesense no responde, mantener el buscador nativo (`/?s=`) ya desplegado.
## Arquitectura
```
Navegador del usuario
└── InstantSearch.js (typesense-instantsearch-adapter) ── HTTPS ──► Typesense
(página /buscar en WP, search-only API key) (Docker)
WP (wp-nuevo) ── indexador (wp-cli/PHP) admin API key ──────────────────────┘
└── hook publish_post / cron: reindexa incremental
```
## Pasos (ejecutables por Sonnet)
### A. Typesense local de desarrollo (no depende de la decisión de infra)
1. Añadir servicio `typesense` a `docker-compose.yml` (imagen `typesense/typesense:27.x`),
volumen de datos, `--api-key` admin de desarrollo, puerto 8108 **solo en localhost**.
2. Levantar y verificar salud: `GET http://localhost:8108/health``{"ok":true}`.
### B. Schema de la colección `feadulta_posts`
Campos: `id`(post_id), `title`, `content` (texto plano, sin HTML), `excerpt`,
`author_id`(int32, facet), `author_name`(string, facet), `date`(int64, sort),
`url`, `lang`(string, facet: es/en/fr/it/pt), `categories`(string[], facet),
`thumbnail`(opcional). `default_sorting_field`: `date`.
### C. Indexador (`scripts/typesense_index.php`, wp-cli `wp eval-file`)
1. Recorre posts `publish` (`post`), excluye los template/feedback CPT.
2. Por cada post construye el documento (content = `wp_strip_all_tags`, author_name =
`display_name` del `post_author`, lang vía Polylang `pll_get_post_language`,
categories por slugs). Sube en **lotes** (import JSONL, action=upsert).
3. Idempotente, reanudable, con `--since` para incremental. ~24.778 posts.
4. Reindexado en caliente: hook `publish_post`/`save_post` → upsert de ese documento;
`before_delete_post` → delete. (Encolar para no penalizar el guardado.)
### D. UI InstantSearch (sustituye/mejora la página de resultados)
1. Página `/buscar` (o el propio template `search`) con InstantSearch.js +
`typesense-instantsearch-adapter`, apuntando a la URL pública de Typesense y la
**search-only** key (nunca la admin) — ambas configurables (constantes en un
mu-plugin `fea-search-typesense.php`, vacías hasta decidir la infra → fallback nativo).
2. Widgets: searchbox, hits (tarjetas con la estética actual `fea-archive-card`),
**refinement por autor** (faceta `author_name`), por idioma y por categoría,
paginación. Resaltado de coincidencias.
3. Multiidioma: filtrar `lang` = idioma actual por defecto; textos de UI por idioma.
4. Mantener la barra móvil de fase 1 como entrada; en desktop, integrar con el buscador
del menú.
### E. Seguridad de claves
- **Admin API key**: solo en el servidor (indexador), nunca en el front.
- **Search-only key**: restringida a la colección, embebida en el front (es segura por diseño).
- CORS de Typesense limitado al dominio del sitio.
### F. Exposición pública (BLOQUEADO por la decisión de infra)
- Opción PC+Tunnel: `cloudflared``search.feadulta.com``localhost:8108`.
- Opción VPS: Typesense en el VPS + Caddy/HTTPS en `search.feadulta.com`.
- Opción Cloud: usar el endpoint y keys que da Typesense Cloud.
- En los tres casos, la UI solo necesita la **URL pública + search-only key**.
## Verificación
- Local: `/health` ok; `typesense_index.php` indexa N docs; la página `/buscar` devuelve
resultados relevantes y la faceta de autor filtra (probar «González Amaro», «Pagola»).
- Comparar relevancia vs buscador nativo en consultas reales del feedback
(«reflexiones», búsqueda por autor).
- Prod: tras exponer el motor, repetir desde un navegador (Cloudflare bloquea headless).
## Riesgos / notas
- **Disponibilidad** si corre en el PC: caídas → debe degradar al buscador nativo, no a error.
- **RAM**: Typesense mantiene el índice en memoria; 24.778 posts de texto entran de sobra
en <1 GB, pero dimensionar el host en consecuencia.
- **Reindexado masivo inicial** puede tardar; hacerlo por lotes y fuera de hora punta.
- No exponer nunca la admin key; CORS restringido.