Files
apps-registry/workloads/docs-portal/docs/aprendizajes/notas-sueltas.md
devops 056a7fb76a docs(docs-portal): Fase 2 - contenido narrativo real de arquitectura/decisiones/aprendizajes
Reemplaza los placeholders "TODO (fase 2+)" por narrativa completa,
grounded en el codigo/manifiestos/incidentes reales del lab (no
generico):

- ADR 0001 (por que k3d) y ADR 0002 (por que Argo CD): pasan de
  template vacio a Contexto/Opciones/Decision/Consecuencias reales,
  apoyados en known-issues.md (blackhole MTU) y en la config real de
  ecommerce-app.yaml.
- vision-general.md: el "por que" de cada frontera de confianza del
  diagrama.
- gitops-flujo.md: ejemplo real con hashes de commit (Fase 3b de
  ADR 0006, v1.0.171 -> hotfix -> v1.0.172), selfHeal explicado con el
  syncPolicy real del repo.
- red-y-exposicion.md: diagrama de terminacion TLS real, por que todo
  va "proxied", patron de diagnostico "interno sano, publico roto".
- glosario.md: 9 terminos nuevos, cada uno con ejemplo real y
  verificado del repo (Namespace, ResourceQuota, LimitRange,
  NetworkPolicy, Deployment, Service, Ingress, StatefulSet, Init
  container).
- notas-sueltas.md: MinIO/S3, limites reales del subscriber
  revalidate-storefront.ts, que se automatizaria desde cero.

Validado con `docker build --target build` (mkdocs build --strict,
mismo paso que el pipeline real) -- cero links rotos, cero warnings.
2026-08-26 23:51:18 -05:00

4.8 KiB

Notas sueltas / aprendizajes

Esto es un scratchpad estructurado, no un playbook — sigue creciendo con notas cortas a medida que aparecen. Cada entrada está extraída de un incidente o hallazgo real ya documentado en otra parte del sitio, no es especulación.

Gotchas de Medusa v2

  • El Store API (/store/products, validado por StoreGetProductsParams, .strict()) no acepta currency_code ni country_code para resolver precios calculados — solo region_id explícito. Ver playbook de precios.
  • El campo thumbnail de un producto no se autocompleta a partir del array images — hay que setearlo explícito desde el Admin si el frontend lo usa como imagen hero en listados.

MinIO / S3 provider

  • Medusa sube imágenes de producto a MinIO (minio-svc:9000, bucket ari-products) usando el provider S3-compatible estándar — MinIO no sabe que no es AWS real, y Medusa tampoco necesita saberlo.
  • La URL pública que termina viendo el navegador no es la interna (minio-svc:9000): es S3_FILE_URL=https://media.cruzcloud.net/ari-products, un dominio propio proxied por NPM hacia el mismo MinIO. Esto tiene una consecuencia directa que ya rompió producción una vez: si media.cruzcloud.net deja de rutear bien (mismo patrón de forward_host roto que el resto del sitio), todas las imágenes de producto del storefront se caen aunque MinIO y Medusa estén perfectamente sanos — porque el navegador nunca habla con MinIO directo, solo con esa URL pública. Ver Red y exposición.

Subscriber revalidate-storefront.ts y sus límites

  • Escucha 6 eventos de Medusa (product.created/updated/deleted + los 3 equivalentes de product-variant) y por cada uno hace un único POST a ${STOREFRONT_URL}/api/revalidate con un header secreto (x-revalidate-secret) — esa ruta del frontend llama revalidateTag("medusa-products") de Next.js.
  • Se degrada solo, no tira el evento entero: si STOREFRONT_URL/REVALIDATE_SECRET no están configurados, o el fetch falla, solo loguea un warn y sigue — un fallo de red hacia el frontend nunca revierte ni bloquea la operación real en Medusa (crear/editar un producto). Mismo criterio de "degradar, no romper" que se repite en el resto del storefront (searchWithFacets opcional, /api/search cayendo a {} si Meilisearch no responde).
  • Límite real, todavía no un problema: no hay debounce ni deduplicación — si una operación dispara varios eventos juntos (ej. editar un producto con 3 variantes a la vez), son varios POST independientes al mismo endpoint. revalidateTag de Next.js es barato e idempotente, así que hoy no se nota, pero si el catálogo creciera mucho y las ediciones masivas se volvieran frecuentes, sería el primer lugar donde agregar algún tipo de agrupación.

Qué haría distinto si volviera a montar este lab desde cero

  • Fijar TUNNEL_TRANSPORT_PROTOCOL=http2 desde el día uno (ver ADR 0003) y ajustar el MTU de flannel.1 desde el primer deploy-lab.sh — ambos terminaron siendo incidentes reales (504 intermitente, blackhole cross-node) que en retrospectiva eran predecibles: red doméstica con NAT agresivo + Docker-in-Docker multi-nodo son una combinación conocida para tener problemas de MTU y de transporte UDP. Hoy los dos ya están automatizados (fix_flannel_mtu en deploy-lab.sh, la variable de entorno del túnel), pero se aprendieron reactivamente, no se anticiparon.
  • Usar git merge-base --is-ancestor para la promoción segura del CI desde el primer pipeline, no después de ver la condición de carrera en vivo (dos pipelines corriendo en serie sobre el mismo commit, el segundo pisando o saltándose la promoción del primero). El patrón correcto no es complicado una vez que se conoce — el costo fue no anticiparlo.
  • Separar siempre "chequeo de disponibilidad" de "migraciones" en init containers distintos, y que el chequeo use el mínimo de parámetros posible (host/puerto/usuario/db) en vez de reusar una URI de conexión pensada para la app. Confirmado como decisión correcta en el incidente de crashloop de Medusa.
  • No escribir un script que regenere credenciales completas en cada corrida (create-commerce-secrets.sh rota JWT/COOKIE/passwords de Postgres/Redis/MinIO enteros cada vez que se ejecuta, incluso si solo hacía falta agregar una clave nueva) — un script de setup inicial y uno de "agregar una clave a un secret ya vivo" deberían haber sido dos herramientas distintas desde el principio, no una sola que hay que saber cuándo NO correr completa.