Capa de interoperabilidad · Prueba técnica de arquitectura

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/.