
Eco²
Backend · Cloud infrastructure
Indicaciones de reciclaje a partir de una foto y una conversación.
Un asistente de IA todo en uno que entiende cómo funciona el reciclaje en Corea.
Eco² vocabulary
- edge
- auth offload
- domain api
- task queue
- scan pipeline
- chat agent
- event bus
- cluster
- gitops
- autoscaling
- observability
- load test
- evaluation
Edge: ROUTE 53 · ALB · HTTPS 443 · internet-facing · external-dns · istio-ingressgateway · NodePort · eco2-gateway · VirtualService · x-canary · AuthorizationPolicy · ENVOY SIDECAR · kiali-serverAuth Offload: AuthorizationPolicy · action: CUSTOM · notPaths · envoyExtAuthzGrpc · failOpen: false · CheckRequest · x-user-id · BlacklistCache · BootstrapFromRedis · outbox:blacklist · blacklist.events · UsersServiceDomain API: VirtualService · x-user-id · /api/v1/scan · X-Idempotency-Key · job_id · stream_url · 202 ACCEPTED · Retry-After · ScanTask · UsersService · ImageService · ENVOY SIDECARTask Queue: outbox:blacklist · blacklist.events · RabbitmqCluster · scan.direct · reward.events · dlx · x-dead-letter-exchange · chat.process · AioPikaBroker · task_acks_late · apply_async · gevent · scan.vision · scan.rule · scan.answer · scan.reward · CELERY CHAIN · QueueLength · inspect ping · QUEUE SATURATIONScan Pipeline: ScanTask · scan.direct · reward.events · apply_async · gevent · scan.vision · scan.rule · scan.answer · scan.reward · CELERY CHAIN · RewardStep · item_class_list.yaml · situation_tags.yaml · LITE RAG · JsonRegulationRetriever · PipelineStage · waste_rag · XADD · domain: worker-ai · pipeline_duration · vision_stage_durationChat Agent: ImageService · chat.process · AioPikaBroker · create_chat_graph · route_by_intent · MULTI-INTENT FANOUT · waste_rag · recyclable_price · collection_point · image_generation · aggregator · thread_id · SyncableRedisSaver · AsyncPostgresSaver · LANGSMITH_TRACING · regenerateEvent Bus: job_id · stream_url · PipelineStage · XADD · scan:events:{shard} · XREADGROUP · XACK · XAUTOCLAIM · PendingReclaimer · STATE KV · scan:state:{job_id} · sse:events:{shard} · SSEBroadcastManager · Last-Event-ID · scan_sse_connections_active · ServiceMonitor · traceparentCluster: NodePort · kubeadm init · kubeadm join · vxlanMode · BGPConfiguration · module "vpc" · worker_ai · nodeSelector · domain: worker-ai · NoSchedule · 24-NODE CLUSTERGitOps: external-dns · x-canary · dev-root · ApplicationSet · sync-wave · selfHeal · ignoreDifferences · argocd-image-updater · update-strategy: digest · write-back-method · targetRevision · ci-services.ymlAutoscaling: ignoreDifferences · ScaledObject · QueueLength · cooldownPeriod · pollingInterval · fallback · maxReplicaCount · stabilizationWindowSeconds · HorizontalPodAutoscaler · scan_sse_connections_active · prometheus-adapterObservability: 24-NODE CLUSTER · prometheus-adapter · FLUENT BIT · Elasticsearch · Kibana · kube-prometheus-stack · AlertmanagerConfig · ServiceMonitor · JAEGER · OPENTELEMETRY · traceparent · kiali-server · LANGSMITH_TRACINGLoad Test: k6 · ramping-vus · thresholds · pipeline_duration · vision_stage_duration · poll_timeout · inspect ping · WORKER RESTART · POLLING TIMEOUT · QUEUE SATURATIONEvaluation: EvalConfig · eval_mode · eval_sample_rate · eval_cost_budget_daily_usd · EvalResult · EvalGrade · code_grader · llm_grader · CUSUM · regenerate · OpenAIBARSEvaluator
Cómo se conectan realmente los 24 nodos, un flujo a la vez.
Kubernetes autogestionado construido con kubeadm. El mapa sitúa los 24 nodos físicos y sus workloads dentro de las cinco capas del README y los une con sus conexiones reales. Al elegir un flujo solo se resalta esa ruta, con pasos numerados.
Identifica residuos a partir de una foto y explica cómo desecharlos, y en la conversación llama a herramientas de lugares, clima, precios de reciclaje y búsqueda web, y genera imágenes. En este proyecto en equipo empecé por el clúster y la base de despliegue, y amplié mi alcance al backend de dominio, el procesamiento asíncrono, el agente conversacional y la verificación.
Desde el desarrollo para el concurso hasta el refuerzo del backend y la operación
El servicio terminó su ciclo; una demo grabada y el informe técnico lo muestran en funcionamiento.
Solicitud de Scan → entrega en vivo
Una solicitud de análisis de foto se convierte en trabajo encolado, y sus eventos de progreso vuelven al mismo navegador.
Navegadorconsulta DNS: Consulta DNSRoute 53
Solo se resuelve el nombre a partir de los registros de Route 53. Las solicitudes no pasan por el DNS.
Navegadorflujo de datos: HTTPS 443AWS ALB
TLS termina en el ALB.
AWS ALBflujo de datos: HTTP · NodePortIstio ingress Envoy
k8s-ingress-gatewaySe entrega al Envoy de ingress de Istio a través del NodePort del destino de instancia EC2.
Istio ingress Envoy
k8s-ingress-gatewayflujo de datos: VirtualServiceScan APIk8s-api-scanSe enruta a la API de Scan, que encola el trabajo y devuelve un job_id de inmediato; la consulta del resultado responde 202 hasta que el trabajo termina.
Scan API
k8s-api-scanflujo de datos: Tarea de CeleryRabbitMQk8s-rabbitmqLa tarea de Scan va a RabbitMQ.
RabbitMQ
k8s-rabbitmqflujo de datos: consumescan-workerk8s-worker-ai · k8s-worker-ai-2scan-worker (Celery · gevent), en el pool de IA, la toma y ejecuta Vision → Rule → Answer → Reward. Las cuatro etapas son tareas de Celery encadenadas, no nodos.
Pool de IA
k8s-worker-ai · k8s-worker-ai-2flujo de datos: HTTPSLLM APILos workers de scan y chat llaman a las API de OpenAI y Google.
scan-worker
k8s-worker-ai · k8s-worker-ai-2flujo de datos: XADD scan:eventsStreamsk8s-redis-streamsLos eventos de progreso se escriben en uno de los cuatro shards de Streams.
Streams
k8s-redis-streamsflujo de datos: XREADGROUPEvent Routerk8s-event-routerEl Event Router los lee como consumer group y hace XACK tras procesarlos; pending y reclaim mantienen la entrega at-least-once.
Event Router
k8s-event-routerflujo de datos: SETEX stateState KVk8s-redis-streamsEscribe el último estado y una marca de procesamiento duplicado en State KV, en el mismo nodo de Redis.
Event Router
k8s-event-routerflujo de datos: PUBLISHPub/Subk8s-redis-pubsubSe entrega en tiempo real en el canal del trabajo, en el Pub/Sub de shard.
Pub/Sub
k8s-redis-pubsubflujo de datos: SUBSCRIBESSE Gatewayk8s-sse-gatewayEl SSE Gateway se suscribe mediante un único listener compartido por proceso y reparte a cada navegador conectado.
SSE Gateway
k8s-sse-gatewayflujo de datos: Stream SSENavegadorUna conexión abierta por la misma ruta de ALB e ingress. La entrega es at-least-once; los duplicados se manejan de forma idempotente.
State KV
k8s-redis-streamsflujo de datos: Recuperación al reconectarSSE Gatewayk8s-sse-gatewayAl reconectar con Last-Event-ID, State KV y los Streams conservados completan los eventos perdidos.
Chat · tokens y almacenamiento
Los tokens de Chat siguen la misma ruta de eventos que Scan; los checkpoints y los mensajes los guardan dos workloads distintos.
Navegadorflujo de datos: HTTPS 443AWS ALB
TLS termina en el ALB.
AWS ALBflujo de datos: HTTP · NodePortIstio ingress Envoy
k8s-ingress-gatewaySe entrega al Envoy de ingress de Istio a través del NodePort del destino de instancia EC2.
Istio ingress Envoy
k8s-ingress-gatewayflujo de datos: VirtualServiceChat APIk8s-api-chatSe enruta a la API de Chat.
Chat API
k8s-api-chatflujo de datos: Tarea de TaskiqRabbitMQk8s-rabbitmqLa tarea de Chat va a RabbitMQ.
RabbitMQ
k8s-rabbitmqflujo de datos: consumechat-workerk8s-worker-ai · k8s-worker-ai-2chat-worker (Taskiq · asyncio) clasifica la intención con LangGraph, luego ejecuta la visión si hace falta, las herramientas seleccionadas, el agregador y un resumen si hace falta, y responde. Cada solicitud solo ejecuta las ramas que necesita.
Pool de IA
k8s-worker-ai · k8s-worker-ai-2flujo de datos: HTTPSLLM APILos workers de scan y chat llaman a las API de OpenAI y Google.
chat-worker
k8s-worker-ai · k8s-worker-ai-2flujo de datos: XADD chat:eventsStreamsk8s-redis-streamsLos tokens y los eventos de etapa se escriben en cuatro shards de Streams; desde ahí, la ruta de entrega es la misma que la de Scan.
Streams
k8s-redis-streamsflujo de datos: XREADGROUPEvent Routerk8s-event-routerEl Event Router los lee como consumer group y hace XACK tras procesarlos; pending y reclaim mantienen la entrega at-least-once.
Event Router
k8s-event-routerflujo de datos: PUBLISHPub/Subk8s-redis-pubsubSe entrega en tiempo real en el canal del trabajo, en el Pub/Sub de shard.
Pub/Sub
k8s-redis-pubsubflujo de datos: SUBSCRIBESSE Gatewayk8s-sse-gatewayEl SSE Gateway se suscribe mediante un único listener compartido por proceso y reparte a cada navegador conectado.
SSE Gateway
k8s-sse-gatewayflujo de datos: Stream SSENavegadorUna conexión abierta por la misma ruta de ALB e ingress. La entrega es at-least-once; los duplicados se manejan de forma idempotente.
chat-worker
k8s-worker-ai · k8s-worker-ai-2flujo de datos: checkpointCachek8s-redis-cacheEl checkpoint de LangGraph se guarda en Redis Cache.
Cache
k8s-redis-cacheflujo de datos: leer el checkpointcheckpoint-syncerk8s-worker-ai · k8s-worker-ai-2checkpoint-syncer lee el checkpoint desde Redis.
checkpoint-syncer
k8s-worker-ai · k8s-worker-ai-2flujo de datos: sincronizar con PostgreSQLPostgreSQLk8s-postgresqlAsyncPostgresSaver lo guarda en PostgreSQL de forma asíncrona.
Streams
k8s-redis-streamsflujo de datos: chat-persistence grouppersistence consumerk8s-api-chatEl persistence consumer del nodo de Chat lee los eventos done como consumer group.
persistence consumer
k8s-api-chatflujo de datos: guardar mensajesPostgreSQLk8s-postgresqlLos mensajes de Chat se guardan en PostgreSQL. Es un workload distinto de checkpoint-syncer.
Entrada · autenticación
La ruta síncrona desde la entrada del clúster hasta una API de dominio. Solo las rutas protegidas por una política comprueban primero la autenticación; el tráfico de pods entre nodos va por Calico VXLAN.
Navegadorconsulta DNS: Consulta DNSRoute 53
Solo se resuelve el nombre a partir de los registros de Route 53. Las solicitudes no pasan por el DNS.
Navegadorflujo de datos: HTTPS 443AWS ALB
TLS termina en el ALB.
AWS ALBflujo de datos: HTTP · NodePortIstio ingress Envoy
k8s-ingress-gatewaySe entrega al Envoy de ingress de Istio a través del NodePort del destino de instancia EC2.
Istio ingress Envoy
k8s-ingress-gatewayflujo de datos: ext-authz · gRPC 50051ext-authzk8s-api-authSolo las rutas bajo una política CUSTOM consultan primero al ext-authz en Go (tiempo de espera de 2 s, failOpen false). Rutas como login, health y docs quedan excluidas.
ext-authz
k8s-api-authflujo de datos: consulta de la blacklistblacklistk8s-redis-authEl token se comprueba contra la blacklist de Redis.
Istio ingress Envoy
k8s-ingress-gatewayflujo de datos: VirtualServiceChat APIk8s-api-chatSe enruta a la API de Chat.
Chat API
k8s-api-chatflujo de datos: gRPCimages APIk8s-api-imageLa llamada síncrona chat → images indicada en el README.
auth API
k8s-api-authflujo de datos: gRPCusers APIk8s-api-usersLa llamada síncrona auth → users indicada en el README.
Pool de almacenamiento · escrituras asíncronas
La blacklist de autenticación y la propiedad de los personajes las guardan los workers del pool de almacenamiento, que reciben su trabajo de RabbitMQ.
blacklist
k8s-redis-authflujo de datos: outbox:blacklistauth-relayk8s-worker-storage · k8s-worker-storage-2auth-relay (el auth-Bus del README) lee el outbox de Redis.
auth-relay
k8s-worker-storage · k8s-worker-storage-2flujo de datos: blacklist.eventsRabbitMQk8s-rabbitmqVuelve a publicar en RabbitMQ, con reintentos y una DLQ.
RabbitMQ
k8s-rabbitmqflujo de datos: blacklist.eventsauth-workerk8s-worker-storage · k8s-worker-storage-2auth-worker recibe los eventos de la blacklist.
auth-worker
k8s-worker-storage · k8s-worker-storage-2flujo de datos: guardar la blacklistblacklistk8s-redis-authSe guardan en la blacklist de Redis.
RabbitMQ
k8s-rabbitmqflujo de datos: Celery batchusers-workerk8s-worker-storage · k8s-worker-storage-2users-worker recibe por lotes el trabajo de propiedad de personajes.
users-worker
k8s-worker-storage · k8s-worker-storage-2flujo de datos: UPSERTPostgreSQLk8s-postgresqlSe aplica a PostgreSQL.
Configurar · escalar · observar
La Platform Layer no es un paso por el que pasen las solicitudes; despliega, configura, escala y observa las demás capas. Los nodos son instancias EC2 creadas con Terraform, con kubeadm y Calico instalados mediante Ansible; la CI solo valida el Terraform y nunca lo aplica automáticamente.
GitHub Actions · Docker Hubconfiguración · escalado: imagen · revisión de manifestArgo CD image updater
k8s-masterArgo CD alinea la configuración del clúster mediante App-of-Apps y Sync Waves. Solo se confirmó la ubicación en el control plane del image updater.
ALB Controller · ExternalDNS
k8s-masterconfiguración · escalado: Ingress → ALB · registros DNSAdministrado por AWSEl ALB Controller y ExternalDNS configuran los recursos del lado de AWS. No es una ruta que sigan las solicitudes.
Istiod
k8s-masterconfiguración · escalado: Configuración xDSIstio ingress Envoyk8s-ingress-gatewayIstiod envía por xDS la configuración de Gateway, VirtualService y EnvoyFilter al Envoy de ingress y al sidecar Envoy de cada API.
KEDA
k8s-monitoringconfiguración · escalado: número de podsPool de IAk8s-worker-ai · k8s-worker-ai-2KEDA ajusta el número de pods de los workers. El número de nodos no cambia.
KEDA
k8s-monitoringconfiguración · escalado: número de podspool de almacenamientok8s-worker-storage · k8s-worker-storage-2Los pods de los workers del pool de almacenamiento se escalan igual.
Fluent Bitobservabilidad: logsElasticsearch
k8s-loggingFluent Bit es un DaemonSet en cada nodo y envía los logs a Elasticsearch.
Pool de IA
k8s-worker-ai · k8s-worker-ai-2observabilidad: trazado de ejecuciones de LLMLangSmithLas trazas de las llamadas a LLM van a LangSmith, un SaaS externo.
Todas las conexiones con el mismo grosor. Elija un flujo para resaltar solo su recorrido, con pasos numerados.
- Continua · dirección en la que fluyen solicitudes, trabajo, eventos y escrituras
- Punteada · consulta DNS; las solicitudes no pasan por ella
- Discontinua · configuración o escalado; no es una ruta de datos
- Raya y punto largos · registros y trazado de ejecuciones
- Línea negra gruesa · el flujo seleccionado; los números dan el orden
- Recuadro · un nodo físico, con el nombre del host en la cabecera
- Chip interior · una carga de trabajo que corre en ese nodo
- Marco discontinuo · un pool de programación de dos nodos
- Recuadro discontinuo · fuera del clúster, no se cuenta como nodo
- Contorno naranja · donde decide un modelo
- Control plane1 nodo
- Domain API8 nodos
- Pool de IA2 nodos
- pool de almacenamiento2 nodos
- Data5 nodos
- Platform6 nodos
Las cinco capas del README (las bandas) y los grupos físicos (el tono de la cabecera de cada nodo) agrupan de forma distinta los mismos 24 nodos. State KV comparte el nodo de Streams y no se cuenta aparte; Route 53, el ALB y los servicios fuera del clúster no son nodos. Un pool es un rango de scheduling, no la afirmación de que cada pod se ejecute en ambos nodos.
24nodos
24 = 1 control plane + 8 API + 4 worker + 5 data + 6 platform
1Control plane
role: control-planekube-apiserver · scheduler · controller-manager · etcd, además de los controladores de la plataforma.
- k8s-master
8Domain API
domain: <servicio>Un nodo por dominio. Las llamadas internas usan gRPC.
- k8s-api-auth
- k8s-api-users
- k8s-api-scan
- k8s-api-character
- k8s-api-location
- k8s-api-image
- k8s-api-chat
- k8s-api-info
4Execution worker
Dos pools de scheduling de dos nodos cada uno. KEDA cambia el número de pods; el número de nodos se mantiene.
pool de almacenamiento
domain: worker-storage- k8s-worker-storage
- k8s-worker-storage-2
Pool de IA
domain: worker-ai- k8s-worker-ai
- k8s-worker-ai-2
5Data
Redis se reparte en cuatro nodos por propósito. El almacenamiento de PostgreSQL es EBS CSI · gp3.
- k8s-postgresql
- k8s-redis-auth
- k8s-redis-streams
- k8s-redis-cache
- k8s-redis-pubsub
6Platform
La mensajería, la observabilidad, el ingress y la entrega en tiempo real tienen cada uno su propio nodo.
- k8s-rabbitmq
- k8s-monitoring
- k8s-logging
- k8s-ingress-gateway
- k8s-sse-gateway
- k8s-event-router
- Cada nodo
- Fluent Bit · DaemonSet
- Calico
Modelos configurados · por proveedor
El servicio se cerró, así que son los modelos configurados en el repositorio, no opciones disponibles hoy. Cada rol se indica por separado; no es una lista de ejecuciones verificadas.
OpenAI
Proveedor predeterminado de Chat
Chat
openai/gpt-5.2por defecto
El modelo predeterminado es gpt-5.2; si la solicitud indica un modelo, se usa ese.
Scan
gpt-5.2por defectogpt-5.2-progpt-5.1gpt-5gpt-5-progpt-5-mini
Se rechazan los modelos fuera del mapeo de 13 modelos.
Mapeo de imágenes
gpt-image-1.5
Aparte de gpt-5.2, el modelo de orquestación de Responses. La generación de imágenes está desactivada por defecto.
Evaluación
gpt-4o-minipor defecto
El calificador LLM de la evaluación de conversaciones, aparte del modelo de Chat.
Google
Cuando Chat elige Google
Chat
google/gemini-3-pro-previewgoogle/gemini-3-flash-preview
Con Google seleccionado, gemini-3-flash-preview es el predeterminado.
Scan
gemini-3-pro-previewgemini-3-flash-previewgemini-2.5-progemini-2.5-flashgemini-2.5-flash-litegemini-2.0-flashgemini-2.0-flash-lite
Mapeo de imágenes
gemini-3-pro-image-preview
Fuentebackend main d8840c7Commit público del September 29, 2026 · comprobado el October 8, 2026