Anexo D. Registro de decisiones (ADR)
| ADR | Estado | Decisión | Qué se sacrifica |
|---|---|---|---|
| 001 | Aceptado el 10/11/2026 | KrakenD como gateway delgado, en lugar de Kong | Las cuotas por partner viven un salto más adentro |
| 002 | Aceptado el 10/11/2026 | Kafka como transporte de eventos, en lugar de SNS con SQS | Reintentos y DLQ se construyen; más costo y operación |
| 003 | Aceptado el 10/11/2026 | La capa es dueña del stock vendible y de las reservas | Única excepción a no poseer datos de negocio; garantía parcial frente a ventas fuera de la capa |
| 004 | Aceptado el 10/11/2026 | Saga orquestada en order-service | order-service es el punto de mayor acoplamiento lógico; estado y recuperación son código propio |
| 005 | Aceptado el 10/11/2026 | Modelo de lectura por eventos para stock y precio | Dato con segundos de desactualización; más piezas en la alimentación |
| 006 | Aceptado el 10/11/2026 | Rate limit en dos niveles: KrakenD y Envoy | Dos lugares de configuración; un servicio de cuotas más |
| 007 | Aceptado el 10/11/2026 | Sync solo lo que la capa responde con sus datos; async lo que depende de terceros | Crear orden responde 202, no el resultado final |
| 008 | Aceptado el 10/11/2026 | Istio con sidecars para capacidades transversales | Memoria y latencia por sidecar; complejidad de la malla |
| 009 | Aceptado el 10/11/2026 | Secretos en AWS Secrets Manager con Secrets Store CSI Driver | El manifiesto nombra al proveedor; la rotación no es instantánea |
| 010 | Aceptado el 10/11/2026 | Java con Spring Boot en dominio, Node.js con Express en adaptadores, gRPC en un punto, y en dos por el ADR-025 (aceptado, sin implementar) | Memoria y arranque de la JVM (la máquina virtual de Java); dos cadenas de herramientas |
| 011 | Aceptado el 10/11/2026 | Versión mayor en la ruta y errores con Problem Details | Tentación de duplicar código al llegar /v2 |
| 012 | Aceptado el 10/11/2026 | Configuración modular del gateway, ensamblada por el pipeline | Los equipos no usan funciones avanzadas; ensamblador propio |
| 013 | Aceptado el 10/11/2026 | Pasarela del demo: Stripe en modo de prueba más pasarela simulada | Tarjetas con autenticación adicional no soportadas en el demo |
| 014 | Aceptado el 10/11/2026 | Contrato gRPC de inventario alineado con el estándar de estilo de buf | Tres mensajes de respuesta casi idénticos |
| 015 | Aceptado el 10/11/2026 | order-service valida el precio con su propia vista, alimentada por el tópico de precios; ventana igual al vencimiento de la reserva | Dos copias derivadas del precio; durante la ventana se vende a un precio que ya no rige, salvo corrección |
| 016 | Aceptado el 10/11/2026 | Todo error del borde sale en Problem Details: el gateway de entrada de Istio normaliza lo que KrakenD y Envoy emiten sin cuerpo | Un filtro Lua propio en el borde, con su prueba |
| 017 | Aceptado el 10/11/2026 | Particiones, réplicas, limpieza y retención de cada tópico, y sus tópicos de reintento y DLQ, viven en el contrato AsyncAPI | El contrato cambia con cada ajuste operativo |
| 018 | Aceptado el 10/11/2026 | Cada adaptador publica una marca de sincronización de su sistema de origen; asOf significa "vigente hasta" y stale detecta la caída del legado aunque nada cambie |
Un canal y un mensaje más; asOf deja de ser la fecha del último cambio |
| 019 | Aceptado el 11/11/2026 | inventory-service consume el catálogo y responde en notFound los SKU fuera del surtido del canal, igual que precio |
Un consumidor y una tabla más en inventory |
| 020 | Aceptado el 11/11/2026 | El evento de precio lleva el calendario de vigencias del alcance y el precio se elige al leer: la promoción programada entra y sale sola | El adaptador guarda las ventanas de cada alcance; la regla se implementa en pricing y en order |
| 021 | Aceptado el 11/11/2026 | Métricas de negocio en formato Prometheus en /metrics, leídas por la plataforma; sin etiquetas de valores sin límite |
Dos caminos de telemetría: trazas por envío y métricas por lectura |
| 022 | Aceptado el 15/11/2026; reemplazado en parte por 027 (endpoint de Kubernetes) | Infraestructura del demo en AWS con OpenTofu: raíces separadas, estado local cifrado, secretos de solo escritura, un rol por carga, EKS mínimo y apagado por interruptores | Un solo NAT; la llave del certificado de origen en el estado cifrado |
| 023 | Aceptado el 11/11/2026 (en implementación) | Cada servicio tiene su espacio de llaves en Redis: prefijo con su nombre y un usuario que solo accede a ese prefijo | Sin aislamiento de rendimiento entre servicios; un usuario y un secreto más por servicio |
| 024 | Aceptado el 15/11/2026 | Cargas en Kubernetes con un chart genérico ensayado en kind, secretos en /etc/andes/secrets por Pod Identity, y Kafka en Confluent Cloud con tópicos y permisos sacados del AsyncAPI |
Ruta de secretos distinta de Docker Compose; llaves de Confluent en el estado cifrado; las 151 particiones del contrato cuestan 0,70 dólares por hora |
| 025 | Aceptado el 15/11/2026 (sin implementar) | La dirección de entrega llega al OMS por un ticket de reclamo: oms-adapter la pide a order-service por gRPC, sin pasar por Kafka | Una segunda llamada síncrona interna |
| 026 | Aceptado el 14/11/2026 | Los identificadores de la orden tienen formato declarado en el contrato y salen del detector de tarjetas, que queda solo en el texto libre y en payment.token |
Una tarjeta puesta a propósito en un identificador no se detecta; el contrato es más estricto en esos campos |
| 027 | Aceptado el 14/11/2026; reemplaza en parte el 022 | La API de Kubernetes es solo privada y se entra por un túnel de Session Manager por un bastión, con el endpoint público limitado por IP como respaldo | Un recurso más que cobra por hora (unos 0,005 dólares) y depende del NAT; todo lo que habla con la API necesita el túnel abierto |
| 028 | Aceptado el 14/11/2026 | Kafka en un pod del clúster para desarrollo, ensayos y respaldo, y Confluent Cloud del 15/11/2026 al demo, con un interruptor de configuración (KAFKA_MODE, con valores pod o confluent) |
En modo pod, un solo nodo sin réplicas y sin permisos por servicio; lo propio de Confluent se prueba con poco margen antes del demo |
| 029 | Aceptado el 15/11/2026 | Los datos sensibles se enmascaran con --data_redacted-- al pasar a la DLQ; el resto del mensaje se conserva como el original |
La DLQ no se reprocesa tal cual: el valor enmascarado se recupera del tópico de reintento o del origen |
| 030 | Aceptado el 15/11/2026 | La entrada sigue con Gateway y VirtualService de Istio (networking.istio.io/v1), sin la Gateway API de Kubernetes |
El estándar portable entre implementaciones; queda como evolución |
| 031 | Aceptado el 15/11/2026 | Recorrido en vivo de una petición sobre el diagrama, reconstruido desde las trazas de Tempo, en monitor.<zona>/recorrido |
Una carga más en el borde; el mapeo depende de nombres de servicio y de tópico, y la búsqueda por correlationId necesita una cabecera aún sin capturar en Java |
| 032 | Aceptado el 15/11/2026 | Panel de monitoreo de solo lectura (monitor.andesretail.com) sobre una pila de observabilidad en el clúster: Prometheus, Loki, Tempo, Grafana, OpenTelemetry y Kiali |
Una réplica de cada pieza, 3 días de métricas y 2 de logs y trazas, sin Alertmanager; los almacenes sin mTLS dentro del clúster |
| 033 | Aceptado el 15/11/2026 | Consola del demo en control.<zona>: cambia entre AS-IS y TO-BE, lanza los seis escenarios de k6 y apaga o degrada los simuladores, con escritura acotada en el clúster y auditoría |
La consola puede crear políticas de autorización en legacy (Kubernetes no limita create por nombre); el correo del operador viene de Cloudflare Access sin verificar su firma |
| 034 | Aceptado el 15/11/2026 | Kafka en pod y Confluent Cloud siempre arriba, con un comando de cambio rápido (make kafka-switch) |
Memoria del pod siempre ocupada y Confluent cobrando aunque no se use; el cambio no lleva mensajes en vuelo, y se drena antes de salir del pod |
| 035 | Aceptado el 15/11/2026 | La tienda ofrece dos caminos para escribir la tarjeta en Stripe, con un interruptor: el componente incrustado de Stripe y la página de pago alojada por Stripe; la saga, el contrato y las llaves de payment-service no cambian |
Alojado: un salto fuera del sitio y una segunda llave secreta, acotada (no cobra ni reembolsa); incrustado: Stripe.js se carga en la página de pago |
Estado de los registros: del 001 al 030, el 031, el 032, el 033, el 034 y el 035 están decididos o aceptados. El 022, el 024 y el 025 los aceptó Andrés el 15/11/2026; el 025 está aceptado y sin implementar. El 023 se decidió durante el desarrollo, con aviso, por un detalle que solo aplica el diseño, y está en implementación. Lo aplicado hasta hoy en AWS (la base y un clúster por horas, sección 3.9) se aprobó paso a paso, cada vez.
El texto completo de cada ADR (contexto, opciones, decisión, costo y cuándo se revisaría) está en docs/adr/.