Identidad visual propia (ver docs-portal/docs/decisiones/0007-identidad-visual-propia.md):
paleta terracota/espresso/pino/crema/carbon reemplaza los tokens
--color-ari-cyan/magenta/yellow/blue (confirmado sin uso en ningun
componente antes de tocarlos). Fraunces + Inter cargadas via
next/font/google (antes "Inter" era solo un fallback de CSS sin
garantia real de carga).
Cambio minimo a proposito: nueva variant "primary" en button.tsx sin
tocar la clase base compartida (radio, ring de foco quedan igual para
el resto del sitio), aplicada como smoke test unico en el CTA y el
precio de ProductCard. El resto de la propagacion (header, footer,
badges, home, product detail) queda para las Sub-fases 2-5, cada una
con su propio gate.
Validado con `docker build --target builder` (npm ci + next build con
typecheck completo) -- compila limpio.
Fase 3b (ultima) de ADR 0006 Etapa 2: los conteos de categoria/marca/edad
del sidebar de /catalog dejan de ser un snapshot client-side fijo. Ahora
se refetchean en vivo contra /api/search en cada cambio de filtro (query
debounced 300ms), tres llamadas paralelas -- una por dimension, cada una
omitiendo su propio filtro para preservar el patron Amazon de "cuantos
resultados habria si eligiera este otro valor".
- catalog-client.tsx: useMemo client-side originales pasan a ser fallback
(mock/shopify sin searchWithFacets, o cuando la categoria activa es un
grupo raiz sintetico que Meilisearch no puede filtrar).
- ProductFilters gana `limit` opcional; /api/search y el provider medusa
lo reenvian -- las llamadas de solo-conteo piden limit=0 para no
rehidratar precios de productos que no se van a mostrar.
PredictiveSearch pasa de filtrar en memoria el arreglo completo de
productos (prop products, substring match) a un fetch debounced
(250ms, con AbortController) contra la nueva ruta /api/search --
mismo componente visual, solo cambia de donde salen los datos, tal
como pide el ADR 0006 seccion 5.
/api/search (nueva, server-side) es el puente same-origin: el
componente es cliente y no puede pegarle directo al provider
server-side (MEDUSA_BACKEND_URL es DNS interno del cluster, no
resuelve desde el navegador).
CatalogProvider gana un metodo OPCIONAL searchWithFacets? (no cambia
la firma de getProducts/searchProducts) -- mock.ts y shopify.ts
compilan sin tocarlos, siguen sin implementarlo. medusa.ts lo
implementa contra /store/search (Fase 2), reutilizando mapProduct()
ya que la ruta devuelve el mismo shape de producto que /store/products.
searchProducts tambien se repunta a /store/search, dejando de usar el
?q= + re-filtro client-side de fetchProducts/matchesFilters para busqueda
(que sigue sirviendo para navegacion sin busqueda, sin cambios).
Navbar deja de pasarle products a PredictiveSearch (ya no los necesita)
pero los sigue recibiendo el mismo -- collections todavia se deriva de
ahi.
Limpieza: borrado patches/frontend-medusa-env.yaml, confirmado
huerfano (ningun kustomization lo referencia; el patch que si esta
vivo es frontend/patches/deployment.yaml).
Validado: build completo de Docker (target builder) -- npm ci,
next build con typecheck, /api/search aparece en la tabla de rutas
generada. Cero errores nuevos (los warnings de ESLint son
preexistentes en catalog-client.tsx, no tocado en esta fase).
ADR 0005 seccion 3 (patron Amazon), primer item de "Filtros facetados
en sidebar con breadcrumb de categoria":
- Breadcrumb (Inicio > raiz > hija) armado caminando parentId sobre la
jerarquia real de categorias (misma que ya consume el mega-menu de
navbar.tsx), no un dato nuevo -- CatalogClient ahora recibe el
arreglo `categories: Category[]` completo ademas del
`categoryGroups` ya existente
- Conteo por valor en cada filtro de la sidebar (Categoria/Marca/Edad),
ej. "Marca (12)": se calcula client-side sobre los productos que ya
pasan el resto de filtros activos, cada dimension excluyendose a si
misma (patron faceted-count estandar). Sin Meilisearch por ahora,
como preveia el ADR ("server-side simple por ahora")
Filtrado existente refactorizado a funciones matchesX() puras y
reutilizadas tanto por `filtered` como por los conteos, sin cambiar el
comportamiento de filtrado ya validado.
Bug preexistente (no introducido en esta sesion, solo expuesto): "/" se
prerenderizaba en build time dentro del Dockerfile, donde
HEADLESS_PROVIDER/MEDUSA_* no existen todavia (solo se inyectan en runtime
via el Deployment de k8s) -- el provider caia a "mock" y ese HTML quedaba
cacheado 1 año (confirmado en vivo: x-nextjs-prerender:1,
Cache-Control: s-maxage=31536000, x-nextjs-cache:HIT). El carrusel de
"Novedades" del home ya mostraba productos mock desde antes; recien se
noto con el nav data-driven de la sub-fase 2 porque las categorias mock
("Figuras"/"Peluches"/"Mochilas") son obviamente distintas a las reales.
/catalog y /product/[slug] no sufren esto porque ya son dinamicos
(searchParams / params fuerzan SSR).
export const dynamic = "force-dynamic" en app/page.tsx y app/layout.tsx
(el layout comparte el fetch del Navbar con TODAS las rutas -- forzarlo
ahi tambien protege contra que una pagina futura reintroduzca el mismo
bug). Decision del usuario: priorizar datos reales sobre el cacheo
estatico de 1 año.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_013dunTcReWMKhWgCPkvAVHD
Sub-fase 2 de Etapa 2 (ADR 0005 seccion 6). Navbar y CategoryTiles usaban
arrays hardcodeados (Figuras/Peluches/Mochilas/Marvel) que ya no coinciden
con los nombres reales de categoria en Medusa desde que se elimino
legacyProductMeta (PR #29) -- todos esos links de navegacion quedaron
rotos silenciosamente (0 productos al filtrar).
- lib/headless: nuevo tipo Category + metodo getCategories() en
CatalogProvider (medusa via /store/product-categories, mock deriva de
su catalogo plano, shopify sin implementar como el resto de sus metodos).
- Navbar: arbol real de categorias (6 raices/21 nodos), dropdown de
hijos por raiz en desktop, lista anidada en el sheet movil. Colecciones
del sheet ahora se derivan de los productos reales en vez de un array
hardcodeado con 2 nombres obsoletos (Marvel/Frozen vs. los reales
Universo Marvel/Reino de Frozen).
- CategoryTiles: tiles de home por categoria raiz real; imagen solo donde
ya existe asset, gradiente honesto donde no (no hay fotografia para las
6 raices todavia, deuda explicita del ADR).
- catalog-client/catalog page: cuando el query param `category` es una
raiz con hijos, se expande a los nombres reales de sus hijos para que
el filtro (igualdad exacta de producto.category) siga funcionando --
sin esto, tiles/nav apuntando a una raiz mostrarian 0 productos porque
ningun producto tiene la raiz asignada directamente.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_013dunTcReWMKhWgCPkvAVHD
Antes el precio actualizado en Medusa tardaba hasta ~60s (o más, con
varias réplicas del frontend sin cache handler compartido) en verse en
el front, por el revalidate:60 del fetch a /store/products.
Ahora:
- Nueva ruta app/api/revalidate en el storefront que llama a
revalidateTag("medusa-products") al recibir un POST autenticado con
el header x-revalidate-secret.
- Nuevo subscriber en el backend Medusa (product.updated,
product-variant.updated/created/deleted) que llama a esa ruta usando
STOREFRONT_URL (ya existe en commerce-config) y un REVALIDATE_SECRET
compartido entre ambos servicios.
- secrets.template.yaml documenta la nueva clave REVALIDATE_SECRET en
commerce-secrets y commerce-storefront (mismo valor en ambos).
Requiere reaplicar commerce-secrets y commerce-storefront con el script
actualizado en el repo scripts (fix/revalidate-secret-scripts) para que
el REVALIDATE_SECRET exista en el cluster.
Product detail pages were generateStaticParams'd at Docker build time,
where MEDUSA_* env vars aren't set, so the static snapshot baked in the
mock catalog (price: null for all products). With revalidate=60 and no
shared ISR cache handler across the 2 frontend replicas, each pod healed
its own cache independently on next visit past staleness — so a product
could show "Consultar precio" on one pod and the real price on the other,
while the fully-dynamic catalog listing always hit Medusa fresh. Verified
against the live Medusa API that pricing/region data itself was correct
for the reported failing products.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01DXqBoNfYQNwFg65mbx2FWM
generateStaticParams usa el catálogo mock en build time porque
HEADLESS_PROVIDER y MEDUSA_* no existen como build args del Dockerfile.
Sin un revalidate explícito, esa ruta queda estática para siempre con
price:null. El listado no sufre esto porque su ruta es dinámica por
searchParams.