Compare commits

...
Author SHA1 Message Date
devops c243f02ec4 docs(adr): marcar ADR 0006 como aceptada, nota de implementación
Build and Push Docs Portal / Escaneo de Secretos (Gitleaks) (pull_request) Successful in 51s
Build and Push Docs Portal / Construir y publicar Docs Portal (pull_request) Skipped
Aprobada tras el diagnóstico de memoria del host (swap saturado
resuelto, ~500-700MiB liberados al desactivar monitoring). Agrega
nota de implementación con 3 desviaciones reales encontradas al
verificar el código fuente del plugin en el tag v1.4.1 antes de
escribir código: no hace falta subscriber propio (el plugin trae los
suyos), las rutas del plugin no devuelven facetDistribution (se
agrega una ruta Store API propia), y se conecta vía plugins: no
modules:. Ninguna cambia la decisión, solo el cómo.
2026-08-26 14:56:19 -05:00
devops 31782a2838 Merge main into fix/adr0006-motor-busqueda-facetas 2026-08-26 14:55:47 -05:00
devops 9069f165c0 Merge fix/disable-monitoring-stack into main 2026-08-26 14:08:28 -05:00
devops 60766ae98e Desactivar temporalmente el stack de monitoring (Grafana+Prometheus)
Sin uso actual, y el host está evaluando capacidad de memoria para la
Etapa 2 del ADR 0006 (Meilisearch) con swap bajo presión. Se quita del
app-of-apps para liberar los recursos del namespace `monitoring`
(Grafana, Prometheus, Alertmanager, kube-state-metrics,
prometheus-operator -- estos dos últimos venían en CrashLoopBackOff
desde hace 37 días, ~8000 reinicios cada uno, conexión rechazada
contra el apiserver in-cluster -- y los 3 node-exporter).

Reversible: reagregar ambos archivos re-despliega el stack completo
vía Helm/kustomize sin pasos manuales. Sin pérdida de datos -- el
namespace monitoring no tenía ningún PVC, confirmado antes de borrar
(kubectl -n monitoring get pvc -> vacío).

Se agregó el finalizer resources-finalizer.argocd.argoproj.io a ambas
Applications (monitoring-app, monitoring-governance) antes de este
commit para que Argo CD borre en cascada los recursos desplegados al
podarlas, no solo el objeto Application -- sin eso quedarían pods
huérfanos corriendo sin liberar memoria.
2026-08-26 14:08:12 -05:00
devops 69467d5f4d Merge fix/commerce-root-redirect-app into main 2026-08-26 13:33:19 -05:00
gitea-actions f5d09059f0 chore(gitops): deploy Docs Portal v1.0.162 [skip ci] 2026-08-26 05:38:36 +00:00
devops 5ce7030c4d docs(adr): propuesta de motor de busqueda y facetas (Fase 5 Etapa 3)
Build and Push Docs Portal / Escaneo de Secretos (Gitleaks) (pull_request) Successful in 32s
Build and Push Docs Portal / Construir y publicar Docs Portal (pull_request) Skipped
Etapa 1 (auditoria/propuesta, sin codigo) de la Etapa 3 de Fase 5:
motor de busqueda y filtros facetados reales, reemplazando el
filtrado/conteo 100% client-side que dejo la sub-fase 3 de Etapa 2.

Verificado contra documentacion oficial vigente (no memoria de
entrenamiento):
- Medusa no tiene modulo de busqueda propio integrado con
  Meilisearch; el Search Module nativo llego en Medusa 2.19, y el
  plugin comunitario @rokmohar/medusa-plugin-meilisearch se conecta a
  el solo desde su version ^2.0.0 (requiere Medusa >=2.19). Nuestro
  backend corre Medusa 2.18.0 -- la version compatible es la linea
  ^1.4.1 del plugin (Medusa >=2.15 <2.19), documentada como deuda
  tecnica explicita si se sube Medusa mas adelante.
- Impacto de recursos evaluado contra el estado real del host (swap
  al 100%, mismo tipo de contencion que el incidente de Gitea):
  Meilisearch recomendado sobre Typesense por menor huella de RAM y
  por ser el unico con integracion Medusa mantenida para nuestra
  version -- comparacion mantenida breve porque la diferencia es
  clara, sin profundizar mas de lo necesario.
- Diseno de indexacion (campos buscables/filtrables/ordenables),
  sincronizacion (mismo patron de subscriber por eventos que
  revalidate-storefront.ts, sumando product-category.* al set de
  eventos) y UI de facetas/autocompletado (reutiliza catalog-client.tsx
  y CatalogProvider.searchProducts ya existentes, sin componentes
  nuevos).

Cross-referencia agregada en ADR 0004 (que ya habia identificado
Meilisearch como paso natural) y entrada nueva en mkdocs.yml.

Etapa 2 (implementacion) NO arranca hasta aprobacion explicita de esta
propuesta.
2026-08-25 18:10:28 -05:00
6 changed files with 303 additions and 62 deletions

No files matched your search

-40
View File
@@ -1,40 +0,0 @@
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: monitoring-app
namespace: argocd
spec:
project: default
source:
repoURL: https://prometheus-community.github.io/helm-charts
chart: kube-prometheus-stack
targetRevision: 58.3.3
helm:
parameters:
- name: prometheusOperator.admissionWebhooks.patch.ttlSecondsAfterFinished
value: "60"
valuesObject:
grafana:
ingress:
enabled: true
ingressClassName: traefik
hosts:
- grafana.cruzcloud.net
destination:
server: https://kubernetes.default.svc
namespace: monitoring
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
- ServerSideApply=true
-20
View File
@@ -1,20 +0,0 @@
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: monitoring-governance
namespace: argocd
spec:
project: default
source:
repoURL: https://gitea.cruzcloud.net/devops/platform-infra.git
path: monitoring-governance
targetRevision: main
destination:
server: https://kubernetes.default.svc
namespace: monitoring
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
@@ -109,7 +109,10 @@ Un motor de búsqueda dedicado (Meilisearch, autohospedado) queda
identificado como el siguiente paso natural una vez el catálogo
crezca más allá de ~100 productos activos, pero no es parte del
alcance inmediato de Etapa 2 — se revisará cuando ese techo esté
cerca.
cerca. **Actualización 2026-08-25:** terminada la Etapa 2 (ver
[ADR 0005](0005-rediseno-storefront.md)), el disparador real resultó
ser la complejidad de facetas de la taxonomía, no el volumen de
productos — ver [ADR 0006](0006-motor-busqueda-facetas.md).
**Compatibilidad con Medusa Admin confirmada:** ninguna de las tres
opciones evaluadas, incluida la elegida, toca
@@ -0,0 +1,297 @@
# ADR 0006 — Motor de búsqueda y filtros facetados (Fase 5, Etapa 3)
**Estado:** aceptada — Etapa 2 en implementación (aprobada 2026-08-26 tras diagnóstico de memoria del host)
**Fecha:** 2026-08-25
## Contexto
[ADR 0004](0004-evaluacion-stack-multi-categoria.md) ya identificó un
motor de búsqueda dedicado (Meilisearch, autohospedado) como "el
siguiente paso natural" para ARI Shopping, pero lo dejó fuera del
alcance de Etapa 2 explícitamente hasta que el catálogo se acercara al
techo real de ~100 productos activos que impone
`fetchProducts(filters, limit = 100)` en `medusa.ts`.
**Ese techo todavía no llegó** — el catálogo real hoy son 26 productos
(17 legacy + 9 demo, ver [ADR 0005](0005-rediseno-storefront.md)
sección 5), lejos de 100. El disparador de esta propuesta no es el
techo de volumen sino la **complejidad de facetas**: la Etapa 2 ya
construyó una taxonomía real de 6 categorías raíz / 21 nodos
(navegación, mega-menú, breadcrumb — PRs #36-42) y un filtrado con
conteo por valor (`categoryCounts`/`brandCounts`/`ageCounts` en
`catalog-client.tsx`, PR #40) que hoy se calcula **100% client-side**
sobre los productos ya traídos — el mismo patrón de "deuda de
alcance" que el hallazgo #4 de ADR 0004 ya señaló, ahora con más
dimensiones de filtro que multiplicar. Sigue siendo tratable a 26
productos; deja de serlo mucho antes de llegar a 100 si el catálogo
crece a la vez en número de productos y en dimensiones filtrables.
Restricción no negociable, igual que en toda la Fase 5: el flujo
**Admin → evento `product.updated` → `revalidate-storefront.ts` →
`revalidateTag("medusa-products")`**, que hoy mantiene el storefront
sincronizado sin intervención manual, no se toca. Cualquier índice de
búsqueda debe sincronizarse por el mismo mecanismo de eventos, nunca
por un cron ni un paso manual.
## 1. Estado real de la integración Medusa v2 + Meilisearch
Verificado contra la documentación oficial vigente el 2026-08-25, no
contra memoria de entrenamiento:
- **Medusa no tiene un módulo de búsqueda propio integrado con
Meilisearch hoy.** La guía oficial
(`docs.medusajs.com/resources/integrations/guides/meilisearch`) es
un tutorial de módulo custom desde cero (`npm install meilisearch` +
workflows/subscribers propios) — no un paquete instalable.
- **Medusa sí introdujo un "Search Module" propio en la versión
2.19.0.** El paquete comunitario `@rokmohar/medusa-plugin-meilisearch`
(el más usado y mantenido para Meilisearch+Medusa) se conecta a ese
Search Module desde su versión `^2.0.0`, pero esa versión del plugin
**requiere Medusa `^2.19.0`**.
- **Nuestro backend corre Medusa `2.18.0`** (`commerce-backend/package.json`)
— justo por debajo de ese corte. La tabla de compatibilidad del
plugin (`github.com/rokmohar/medusa-plugin-meilisearch`) resuelve
esto: la línea `^1.4.1` soporta `Medusa >= 2.15 < 2.19`, servidor
Meilisearch `>= 1.5`, Node `>= 22`. El propio repo lo explica: *"The
2.19 release removed the search interface the v1 line was written
against, so the two lines do not overlap: v1 stops at Medusa 2.18,
v2 starts at 2.19."*
- Node de `commerce-backend` ya es `22.18.0` (Dockerfile) — cumple el
mínimo del plugin sin cambios.
**Implicación concreta:** para adoptar Meilisearch sin subir de
versión Medusa (fuera de alcance de este ADR — sería su propia
migración), la pieza a instalar es `@rokmohar/medusa-plugin-meilisearch@^1.4.1`,
no la última versión del plugin. Esto es deuda técnica documentada,
no un obstáculo: si en el futuro se sube Medusa a `2.19+`, migrar a la
línea `^2.0.0` del plugin (y al Search Module nativo) es el camino
recto.
## 2. Impacto de recursos
Estado real del host ZimaOS al momento de esta auditoría (`free -h`,
`docker stats`): 15 GiB RAM totales, **swap al 100% (5.2/5.2 GiB
usados)**, solo 351 MiB realmente libres (6.5 GiB "available" vía
cache reclamable), 4 vCPU — la misma clase de contención que ya forzó
el fix de `cpu_shares` de Gitea. Cualquier servicio nuevo en este host
es una decisión de capacidad real, no teórica.
- **Meilisearch no publica un mínimo de RAM oficial.** Su propio FAQ
(`meilisearch.com/docs/resources/help/faq`) solo dice que "más RAM
implica búsquedas más rápidas" y recomienda ~10x el tamaño del
dataset crudo en disco — sin piso duro. La cifra de "~1 GiB
cómodo" que circula en blogs de la comunidad es una estimación, no
una garantía del proveedor — se cita aquí como referencia, no como
hecho verificado.
- Meilisearch usa almacenamiento memory-mapped: el índice puede vivir
parcialmente en disco cuando no entra en RAM, degradando latencia en
vez de fallar. A la escala actual (26 productos, dataset de KB) el
uso real de RAM del índice en sí es insignificante — el costo es el
proceso base de Meilisearch, no el dataset.
- **Comparación con Typesense** (pedida explícitamente, mantenida
breve porque la diferencia relevante para este caso es clara y no
requiere más profundidad): Typesense mantiene el índice completo en
RAM (~30% más RAM que Meilisearch para el mismo dataset, según
benchmarks públicos) y, a diferencia de Meilisearch, **no tiene
ningún plugin ni integración con Medusa** — habría que escribir la
sincronización completa desde cero igual que con la guía "custom"
de Meilisearch, pero sin ninguna base comunitaria mantenida
compatible con nuestra versión de Medusa. Con Meilisearch ya
teniendo un plugin activo para `Medusa 2.18` y menor huella de RAM,
no hay motivo para evaluar Typesense más a fondo en este caso.
- **Recomendación:** desplegar Meilisearch en k3d con `requests`/`limits`
explícitos y conservadores desde el día uno (ej. `request: 256Mi/0.1
CPU`, `limit: 768Mi/0.5 CPU` — a ajustar con datos reales de uso, no
supuestos), y tratarlo como el mismo tipo de riesgo operativo que ya
se vivió con Gitea: monitorear consumo real post-despliegue antes de
darlo por estable. Dado el swap ya saturado, este es el punto de
mayor incertidumbre de toda la propuesta — más que la elección de
motor de búsqueda en sí.
## 3. Modelo de indexación
Basado en la taxonomía real ya viva en Medusa (Etapa 2) y en
`Product`/`Category` de `lib/headless/types.ts`:
| Campo | Buscable (texto, tolerante a typos) | Filtrable / faceta | Ordenable |
|---|---|---|---|
| `name` | Sí | No | No |
| `shortDescription` / `description` | Sí | No | No |
| `category` (nombre de la hoja real) | Sí | Sí (con conteo) | No |
| `collection` | Sí | Sí (con conteo) | No |
| `brand` | Sí | Sí (con conteo) | No |
| `ageRange` | No | Sí (con conteo) | No |
| `tags` | Sí | No | No |
| `price` | No | Sí (rango) | Sí |
| `compareAtPrice` | No | No | No (solo se usa para el badge, no como filtro) |
| `isNew` / `featured` | No | No | Sí (orden "Novedades"/"Destacados", igual que hoy) |
| `available` | No | Sí (booleano) | No |
| `slug`, `thumbnail`, `id` | No | No | No (solo se devuelven, no se indexan como facetas) |
La jerarquía de categorías (raíz/hija) no se indexa como un campo
aparte: el índice guarda el nombre de la hoja real tal como hoy lo
hace `product.category`, y el breadcrumb/mega-menú siguen resolviendo
la jerarquía contra `/store/product-categories` (sin cambios, ya
funciona desde la sub-fase 2). El motor de búsqueda resuelve
**búsqueda de texto + conteo de facetas**, no reemplaza la fuente de
la jerarquía.
## 4. Diseño de sincronización
Mismo patrón que `revalidate-storefront.ts`, no uno nuevo: un
subscriber adicional en `commerce-backend/src/subscribers/` (ej.
`sync-search-index.ts`) que reacciona a eventos y le pide al plugin
que reindexe el documento afectado — nunca Medusa escribiendo
directamente en Meilisearch fuera de este canal.
Eventos a escuchar, confirmados en la documentación oficial de
eventos de Medusa (`docs.medusajs.com/resources/events-reference`):
- `product.created` / `product.updated` / `product.deleted`
- `product-variant.created` / `product-variant.updated` / `product-variant.deleted`
(mismo set que ya usa `revalidate-storefront.ts`, hoy validado en
producción)
- **Nuevo respecto al subscriber actual:** `product-category.created`
/ `product-category.updated` / `product-category.deleted` — un
cambio de nombre o jerarquía de categoría debe refrescar las
facetas del índice, y hoy `revalidate-storefront.ts` no escucha
estos eventos porque el storefront los resuelve en cada request
contra `/store/product-categories` directamente, sin necesidad de
revalidación. El índice de búsqueda sí necesita enterarse.
**Punto a verificar en vivo en Etapa 2, no asumido aquí:** existe al
menos un reporte público de un evento `product-collection.updated`
que no se disparaba de forma confiable en ciertas versiones de Medusa
(`github.com/medusajs/medusa/issues/11197`). Antes de dar por cerrado
el diseño de sincronización hay que repetir exactamente la validación
que ya se hizo para `revalidate-storefront.ts` en la auditoría de
Etapa 1 de Fase 5: crear/editar una categoría real vía Admin y
confirmar en vivo que el evento llega al subscriber, no confiar en que
la documentación coincide con el comportamiento real de `2.18.0`
(el mismo tipo de brecha que ya se encontró una vez con la relación
`+categories` de `/store/products`).
## 5. Diseño de UI — filtros facetados y búsqueda
**Filtros facetados (sidebar de `/catalog`):** mismo layout que ya
construyó la sub-fase 3 (`catalog-client.tsx`, PR #40) — sidebar con
"Categoría"/"Marca"/"Edad" como pills con conteo entre paréntesis y
slider de precio máximo. Lo único que cambia es **de dónde sale el
conteo**: hoy `categoryCounts`/`brandCounts`/`ageCounts` se calculan
recorriendo el arreglo de productos ya traído en el cliente; con el
motor de búsqueda, esos conteos vienen del propio Meilisearch
(`facetDistribution`) en la misma respuesta que trae los productos
filtrados, sin recorrer nada en el navegador. El breadcrumb no cambia
— sigue resolviéndose contra la jerarquía real de categorías, no
contra el índice de búsqueda.
```
Inicio > Mochilas y morrales > Marvel breadcrumb real (sin cambios)
┌────────────┬──────────────────────────────────────┐
│ Categoría │ [buscador con autocompletado] │ ← nuevo
│ ☐ Marvel(6)│ [card][card][card] │
│ ☐ Frozen(4)│ [card][card][card] │
│ Marca │ │
│ ☐ Disney(2)│ conteos ahora vienen de Meilisearch, │
│ Precio │ no de recorrer el arreglo en cliente │
│ [====○===] │ │
└────────────┴──────────────────────────────────────┘
```
**Búsqueda con autocompletado (barra del navbar):** hoy
`PredictiveSearch` (`components/search/predictive-search.tsx`) filtra
por substring sobre los productos ya cargados en memoria del cliente —
funciona a 26 productos, no escala y no tolera errores de tipeo (ADR
0004, hallazgo #5). Se reemplaza la fuente de datos del mismo
componente visual por `searchProducts(query)` del `CatalogProvider`
(interfaz que **ya existe** en `lib/headless/types.ts`, sin necesidad
de un tipo nuevo) apuntando a Meilisearch en vez de al `?q=` de
Medusa: tolerancia a typos y ranking por relevancia nativos del motor,
mismo contrato de datos que ya consume el dropdown de resultados —
cero cambio de componente React, solo de qué hay detrás de
`CatalogProvider.searchProducts`.
## Opciones consideradas
| Opción | A favor | En contra |
|---|---|---|
| **Meilisearch autohospedado** (`@rokmohar/medusa-plugin-meilisearch@^1.4.1`, sincronizado por eventos) | Plugin comunitario activo y compatible con nuestra versión exacta de Medusa (2.18); menor huella de RAM que la alternativa evaluada; almacenamiento memory-mapped se degrada en vez de fallar bajo presión de memoria; mismo patrón de subscriber que `revalidate-storefront.ts`, cero riesgo para ese flujo | Ningún paquete "oficial" de Medusa (el plugin es comunitario, no del core); atado a la línea `v1` del plugin mientras no se suba Medusa a 2.19+; un servicio más para operar en un host ya con swap saturado |
| **Typesense autohospedado** | Autocompletado ~2x más rápido según benchmarks públicos | Cero integración con Medusa (habría que escribir la sincronización completa desde cero, igual esfuerzo que la guía "custom" de Meilisearch pero sin base comunitaria); ~30% más RAM que Meilisearch para el mismo dataset, el peor trade-off posible dado el estado actual del host |
| **Módulo custom desde cero** (seguir la guía oficial de Medusa, sin el plugin de rokmohar) | Sin dependencia de un paquete de terceros; control total | Reimplementa lo que el plugin comunitario ya resuelve (declaración de índices, reindexado atómico, tracking de escrituras); más superficie propia para mantener sin ganancia clara sobre usar el plugin ya compatible con 2.18 |
| **No adoptar motor de búsqueda todavía** (seguir con filtrado 100% client-side) | Cero riesgo, cero componente nuevo | No resuelve la deuda de facetas ya identificada en ADR 0004 y agravada por la sub-fase 3; el techo de complejidad de filtros llega antes que el de 100 productos si el catálogo sigue creciendo en categorías |
## Decisión
**Meilisearch autohospedado**, vía `@rokmohar/medusa-plugin-meilisearch@^1.4.1`
(no la última versión del plugin — esa exige Medusa 2.19+, fuera de
alcance), sincronizado por el mismo patrón de subscriber por eventos
que ya usa `revalidate-storefront.ts`, con `product-category.*` sumado
al set de eventos existente. Se despliega en k3d con límites de
recursos conservadores desde el primer día y se trata como
experimento a monitorear, no como capacidad garantizada, dado el
estado actual de memoria del host.
**No se sube la versión de Medusa como parte de esta decisión** —
queda como deuda técnica documentada para cuando se justifique
migrar a la línea `v2` del plugin y al Search Module nativo de
Medusa.
## Consecuencias
- Se gana: conteo de facetas real (no client-side), búsqueda tolerante
a errores de tipeo con ranking por relevancia, y una arquitectura
que ya no depende del techo de 100 productos de `fetchProducts`.
- Se acepta como deuda técnica: quedar atado a la línea `v1` del
plugin de Meilisearch mientras Medusa siga en `2.18.x`; migrar a
Medusa `2.19+` es un proyecto aparte, no parte de esta Etapa 3.
- Riesgo operativo real y no resuelto todavía por este ADR: el host ya
corre con el swap saturado — el despliegue de Etapa 2 debe empezar
con límites de recursos conservadores y validación en vivo de
consumo real antes de confiar en el servicio, siguiendo la misma
lección que dejó el incidente de recursos de Gitea.
- Revertir esta decisión implica desinstalar el plugin y el
subscriber nuevo, y volver el buscador/filtrado a 100% client-side
— no hay migración de datos que deshacer, porque Meilisearch nunca
es la fuente de verdad, solo una copia de solo lectura indexada
desde Medusa.
## Nota de implementación (2026-08-26, antes de escribir código de Etapa 2)
Antes de tocar código se verificó el código fuente real de
`@rokmohar/medusa-plugin-meilisearch` en el tag exacto `v1.4.1`
(`github.com/rokmohar/medusa-plugin-meilisearch`), no su README
genérico ni memoria de entrenamiento — misma disciplina que ya destapó
el bug de `+categories` en `/store/products`. Aparecieron tres
desviaciones reales respecto al diseño de §4/§5 de este ADR:
1. **No se escribe un subscriber nuevo.** El plugin trae sus propios
subscribers (`meilisearch-product-upsert.ts`,
`meilisearch-category-upsert.ts`, variantes/colección/inventario),
auto-registrados al instalar el paquete — el propio README dice
*"You don't need custom subscribers anymore, you can remove them."*
Escribir `sync-search-index.ts` como describe §4 causaría doble
indexado. La escucha de `product-category.*` que pedía §4 ya viene
incluida en los subscribers del plugin.
2. **Las rutas Store API del plugin no devuelven `facetDistribution`**,
pese a que §5 asume que sí. El servicio interno
(`MeiliSearchService.search()`) sí puede pedirlo vía
`additionalOptions: { facets: [...] }`, pero las rutas
empaquetadas nunca lo piden ni lo reenvían. Se agrega una ruta
Store API propia (`src/api/store/search/route.ts`) que resuelve el
servicio del plugin desde el container y arma
`{ products, facetDistribution }`. Consecuencia positiva no
buscada: Meilisearch queda 100% `ClusterIP`-only, sin Ingress, sin
key pública ni ruta de red navegador→Meilisearch — todo pasa por
Medusa.
3. **El plugin se conecta vía un array `plugins:` nuevo en
`medusa-config.ts`**, no otra entrada en `modules:` (el único
precedente en este repo, el file-provider S3, usa `modules:`), y
usa nombres de env var propios (`MEILISEARCH_HOST`/
`MEILISEARCH_API_KEY`, leídos por el plugin) distintos del env var
del servidor Meilisearch en sí (`MEILI_MASTER_KEY`, leído por el
contenedor `getmeili/meilisearch`) — mismo valor, dos nombres de
secret.
Ninguna de las tres cambia la decisión ni sus consecuencias — cambian
el cómo, no el qué. Plan de implementación completo, fase por fase,
en la sesión que aprobó esta Etapa 2 (2026-08-26).
+1
View File
@@ -92,6 +92,7 @@ nav:
- "0003 · HTTP/2 sobre QUIC": decisiones/0003-por-que-http2-sobre-quic-tunnel.md
- "0004 · Stack multi-categoría": decisiones/0004-evaluacion-stack-multi-categoria.md
- "0005 · Rediseño storefront": decisiones/0005-rediseno-storefront.md
- "0006 · Motor de búsqueda y facetas": decisiones/0006-motor-busqueda-facetas.md
- Plantilla ADR: decisiones/plantilla-adr.md
- Playbooks:
- Crashloop Medusa: playbooks/incidente-crashloop-medusa.md
@@ -25,7 +25,7 @@ spec:
runAsNonRoot: false
containers:
- name: app
image: gitea.cruzcloud.net/devops/docs-portal:v1.0.161
image: gitea.cruzcloud.net/devops/docs-portal:v1.0.162
# El base saca TODAS las capabilities. Probado en vivo y
# revertido: con drop: ALL (aunque se agregue NET_BIND_SERVICE
# de vuelta) el propio entrypoint de nginx:1.27-alpine falla al