docs: ADR 0011 (ambiente de Staging) + notas de la sesión 2026-09-13/14
Build and Push Docs Portal / Escaneo de Secretos (Gitleaks) (push) Successful in 27s
Build and Push Docs Portal / Construir y publicar Docs Portal (push) Successful in 6m1s

Documenta el ambiente de Staging (staging.cruzcloud.net, promoción
manual, footer con version real), y agrega a notas-sueltas la
correccion de bodega Cali, redes sociales reales, rediseño de galeria
estilo Amazon, la leccion de min-w-0 en CSS Grid, y la remocion
definitiva de la barra flotante de carrito en mobile. De paso, suma a
la nav el ADR 0010 que existía en el repo pero nunca se había
enlazado.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_012Y4df3Z7odr9Cg8F2nw6uV
This commit is contained in:
devopsandClaude Sonnet 5 committed 2026-09-14 05:00:19 +00:00
1 parent 009d5c63df
commit fe4ed8005a
3 files changed
+184 -1

No files matched your search

@@ -0,0 +1,115 @@
# ADR 0011 — Ambiente de Staging para el storefront
**Estado:** aceptada — desplegado y verificado en vivo
**Fecha:** 2026-09-14
## Contexto
Hasta este punto, todo cambio de frontend se probaba directamente
contra `shop.cruzcloud.net` (producción): el mismo push a `main` que
disparaba el build de imagen también actualizaba el manifiesto real
que sirve tráfico. Cada iteración de UI (rediseño de la página de
producto, zoom estilo Amazon, ajustes mobile) implicaba validar en
vivo sobre el sitio real, sin una red de contención — un cambio roto
llegaba directo al usuario final antes de poder revertirlo.
El usuario pidió explícitamente un ambiente de Staging para dejar de
probar en producción ("Me interesa crear el ambiente Staging para no
estar probando en Prod").
## Opciones consideradas
| Opción | A favor | En contra |
|---|---|---|
| **Namespace + Ingress propios, backend compartido con Prod** — elegida | Cero costo adicional de Postgres/Medusa/Meilisearch en un NAS ya ajustado de recursos; rápido de armar reusando el mismo patrón workload+governance de `ecommerce` | Staging y Prod comparten datos reales (catálogo, inventario, órdenes) — no aísla pruebas que muten datos de negocio |
| Backend propio para Staging (Postgres/Medusa/Meilisearch duplicados) | Aislamiento completo, se podrían probar migraciones de datos sin riesgo | Duplica el consumo de recursos de la NAS sin necesidad todavía (decisión explícita del usuario de descartar esto por ahora) |
| Feature flags / preview deploys por PR en vez de un ambiente fijo | Sin infraestructura nueva que mantener | Gitea Actions en este lab no tiene un mecanismo de preview-per-branch ya armado; más esfuerzo de tooling que un namespace nuevo |
## Decisión
Namespace `ecommerce-staging` nuevo, con su propio Ingress
(`staging.cruzcloud.net`) y su propio Deployment de frontend (misma
imagen Docker que Prod), pero apuntando al **mismo backend Medusa** que
producción (`medusa-svc.ecommerce.svc.cluster.local:9000` — FQDN
cross-namespace, un nombre corto solo resuelve dentro del mismo
namespace). Flujo de promoción: **todo push a `main` despliega a
Staging automáticamente**; promover a Producción es una acción manual
separada (`scripts/promote-to-production.sh`).
## Qué se armó
- `apps-registry/workloads/ecommerce-staging/` — overlay Kustomize:
1 réplica (no 2 como Prod — ambiente de verificación, no de tráfico
real), requests/limits más chicos, mismo `securityContext` que Prod
(mismas restricciones del Dockerfile: `runAsUser` numérico,
`NET_BIND_SERVICE`, `readOnlyRootFilesystem`).
- `apps-registry/apps/ecommerce-staging-app.yaml` +
`ecommerce-staging-governance-app.yaml` — Applications de Argo CD
(workload + governance separadas, misma convención que el resto del
lab).
- `platform-infra/ecommerce-staging-governance/` — ResourceQuota,
LimitRange y NetworkPolicy propios del namespace nuevo.
- `.gitea/workflows/build.yaml` — el paso de CD (`Actualizar
Manifiesto GitOps`) ahora apunta a
`workloads/ecommerce-staging/frontend/patches/deployment.yaml` en
vez del manifiesto de Prod: cada push a `main` bumpea el tag de
imagen (y, desde el mismo día, la variable `APP_VERSION` — ver nota
de implementación) de Staging automáticamente.
- `scripts/promote-to-production.sh` — lee el tag actualmente
desplegado en Staging, pide confirmación explícita, y lo aplica al
manifiesto real de Producción (`workloads/ecommerce/frontend/patches/deployment.yaml`).
Nunca corre automáticamente: es la única vía para que un cambio
llegue a `shop.cruzcloud.net`.
- Secrets `commerce-storefront` y `gitea-registry-secret` copiados
(no regenerados) desde el namespace `ecommerce` hacia
`ecommerce-staging`, para que el frontend de Staging tenga las
mismas credenciales reales contra el backend compartido.
## Descubrimiento de red real (no solo Kubernetes)
Confirmado en vivo el mismo día: aunque Cloudflare tiene un wildcard
`*.cruzcloud.net`, eso **no alcanza** para exponer un Ingress nuevo. La
cadena real es Cloudflare → túnel `cloudflared` → **Nginx Proxy
Manager** → `k3d-lab-cluster-serverlb` (puerto 90) → Traefik → Service.
Cada subdominio que ya funciona (`shop`, `commerce`, `media`, etc.)
tiene su propia fila de Proxy Host en NPM apuntando a
`192.168.68.61:90`. Un Ingress nuevo sin esa fila devuelve la página
por defecto de NPM aunque Traefik ya esté enrutando bien internamente
— verificado con `curl -H "Host: staging.cruzcloud.net"
http://192.168.68.61:90/` (funcionaba) contra el dominio público
(seguía devolviendo la página por defecto hasta que se agregó la fila
en NPM). Ver [Red y exposición](../arquitectura/red-y-exposicion.md).
Esta fila de NPM la agregó el usuario manualmente — no hay credenciales
de ese panel disponibles para automatizarlo.
## Nota de implementación (2026-09-14): versión real visible en el footer
El footer mostraba un string fijo (`v4.1`), inútil para distinguir a
simple vista si Staging y Producción están en la misma versión.
Se agregó una variable de entorno `APP_VERSION` (leída en
`footer.tsx` vía `process.env.APP_VERSION`, sin necesidad de prefijo
`NEXT_PUBLIC_` por ser un Server Component) a ambos manifiestos de
Deployment; el mismo paso del CD que bumpea el tag de imagen ahora
también bumpea `APP_VERSION` (vía `perl -0777` para una sustitución
multilínea, ya que el nombre y el valor de la variable viven en líneas
distintas del YAML — un `sed` de una sola línea no alcanza).
`promote-to-production.sh` hace el mismo bump al promover. Verificado
en vivo con Playwright: tras el primer push, Staging mostró `v1.0.263`
mientras Producción seguía en `v4.1` (la imagen vieja no leía la
variable); tras promover, ambos ambientes quedaron visualmente
distinguibles por versión real en su footer.
## Consecuencias
- Ganado: ningún cambio de frontend vuelve a validarse por primera vez
contra tráfico real; Staging y Producción ahora se distinguen a
simple vista por la versión mostrada en el footer.
- Deuda aceptada: Staging comparte datos reales de negocio con
Producción (mismo Medusa/Postgres) — una prueba que cree o modifique
órdenes/inventario en Staging afecta datos reales. Si esto se vuelve
un problema, la opción descartada de backend propio para Staging
queda como camino de escalamiento.
- Para revertir: apuntar de nuevo `MANIFEST_FILE`/`KUSTOMIZE_DIR` en
`build.yaml` hacia `workloads/ecommerce/...` y eliminar el namespace
`ecommerce-staging` — el namespace de Producción no cambia de forma
en ningún momento de este ADR.