Files
feadulta/docs/plan-buscador-typesense.md
rafa 5055e92143 Rescatar 10 docs/ del main local que nunca llegaron a Gitea (issue #194)
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>
2026-08-05 08:39:06 -04:00

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)

  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: cloudflaredsearch.feadulta.comlocalhost: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.