main local y origin/main son dos historias sin ancestro comun (ver #194). Analisis del agente: de las 46 commits solo-en-local, el unico contenido que no esta ya reflejado en origin/main via el snapshot de julio (PR #179) son estos 10 ficheros de docs/ (guias, handoffs, planes, benchmark, revisiones de issues). Copiados tal cual desde main con "git show main:docs/X > docs/X". Redactada una password SSH y una password cPanel/FTP en texto plano que tenia handoff-carta-46956-2026-06-17.md (servidor CDMON antiguo) antes de subirlo -- ver .env, nunca en docs versionados. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
5.2 KiB
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)
- Añadir servicio
typesenseadocker-compose.yml(imagentypesense/typesense:27.x), volumen de datos,--api-keyadmin de desarrollo, puerto 8108 solo en localhost. - 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)
- Recorre posts
publish(post), excluye los template/feedback CPT. - Por cada post construye el documento (content =
wp_strip_all_tags, author_name =display_namedelpost_author, lang vía Polylangpll_get_post_language, categories por slugs). Sube en lotes (import JSONL, action=upsert). - Idempotente, reanudable, con
--sincepara incremental. ~24.778 posts. - 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)
- Página
/buscar(o el propio templatesearch) 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-pluginfea-search-typesense.php, vacías hasta decidir la infra → fallback nativo). - Widgets: searchbox, hits (tarjetas con la estética actual
fea-archive-card), refinement por autor (facetaauthor_name), por idioma y por categoría, paginación. Resaltado de coincidencias. - Multiidioma: filtrar
lang= idioma actual por defecto; textos de UI por idioma. - 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:
/healthok;typesense_index.phpindexa N docs; la página/buscardevuelve 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.