Персонаж-глобус Eco², доопрацьований для цього портфоліо на основі останнього офіційного головного персонажа: блакитний глобус із зеленими материками, паростком на маківці й коричневим усміхненим обличчям
Назад до зали

Eco²

Backend · Cloud infrastructure

Сортування відходів за одним фото й розмовою.

Універсальний AI-асистент, що розуміє, як влаштоване сортування відходів у Кореї.

2025.10.31 — 2026.02.10

Командний проєкт · інфраструктура й основа розгортання → доменний бекенд → асинхронна обробка, розмовний агент, верифікація

2025 새싹 해커톤 (Saessak Hackathon)Відзнака за високі результати · 2025.12.02

  • ВебзастосунокСервіс закрито

Eco² vocabulary

Lens
Service Path
Request Path
Async Work
Operations
Infrastructure
Measurement
  1. edge
  2. auth offload
  3. domain api
  1. task queue
  2. scan pipeline
  3. chat agent
  4. event bus
  1. cluster
  2. gitops
  3. autoscaling
  1. observability
  2. load test
  3. 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

Як насправді з’єднані 24 вузли, по одному потоку за раз.

Самокерований Kubernetes, зібраний за допомогою kubeadm. Карта розміщує 24 фізичні вузли й робочі навантаження на них у п’яти шарах із README і з’єднує їх фактичними зв’язками. Оберіть потік, і буде підсвічено лише цей шлях із пронумерованими кроками.

Він розпізнає відходи на фото й пояснює, як їх утилізувати, а в розмові викликає інструменти для місць, погоди, цін на вторсировину та вебпошуку й генерує зображення. У цьому командному проєкті я почав із кластера й основи розгортання, а потім розширив свою зону до доменного бекенду, асинхронної обробки, розмовного агента й верифікації.

Від розробки для конкурсу до посилення бекенду й експлуатації

Сервіс завершив роботу; записане демо й технічний звіт показують його в дії.

Карта зв’язків кластера · накреслено заново за маніфестами й кодом на коміті a072127
Карта зв’язків кластера Eco² · 24 вузлиКарта 24 фізичних вузлів у п’яти смугах шарів із README. Браузер лише знаходить ім’я в Route 53; після завершення TLS на ALB на порту 443 Istio ingress Envoy на NodePort надсилає запит до доменного API. Scan API ставить роботу в чергу RabbitMQ і одразу повертає job_id; scan-worker у пулі AI виконує XADD подій поступу в Redis Streams. Event Router читає їх, оновлює State KV і публікує в Pub/Sub, а SSE Gateway надсилає їх у браузер. checkpoint-syncer зберігає контрольні точки Chat, а persistence consumer на вузлі Chat зберігає повідомлення в PostgreSQL. Platform Layer — не шлях запитів; він налаштовує, масштабує й спостерігає.БраузерHTTPS · SSEAWS ALB443 · тут завершується TLSRoute 53DNSGitHub Actions · Docker Hubобраз · ревізія маніфестуLLM APIOpenAI · GoogleLangSmithтрасування запусків LLMFluent BitDaemonSet · кожен вузолk8s-masterALB Controller · ExternalDNSArgo CD image updaterIstiodcontrol planek8s-ingress-gatewayIstio ingress Envoyk8s-api-scanScan APIk8s-api-chatChat APImessage consumerpersistence consumerk8s-api-authauth APIext-authzk8s-api-infoInfo APIinfo-workerk8s-api-charactercharacter APIk8s-api-imageimages APIk8s-api-usersusers APIk8s-api-locationlocation APIk8s-sse-gatewaySSE Gatewayk8s-event-routerEvent Routerk8s-rabbitmqRabbitMQk8s-worker-aik8s-worker-ai-2k8s-worker-storagek8s-worker-storage-2k8s-redis-pubsubPub/Subk8s-redis-streamsStreamsState KVk8s-redis-cacheCachek8s-postgresqlPostgreSQLk8s-redis-authblacklistk8s-monitoringKEDAPrometheusGrafanaAlertmanagerk8s-loggingElasticsearchKibanascan-workerchat-workercheckpoint-syncerauth-relayauth-workerusers-workercharacter-workercharacter-match-workerKialiJaeger · dev in-memoryКластер Kubernetes24 вузли · kubeadmEdge Layer1 вузолService Layer8 вузлів · Envoy sidecarIntegration Layer7 вузлівPersistence Layer5 вузлівPlatform Layer3 вузли · налаштування · масштабування · спостереженняПід керуванням AWSПул AIdomain: worker-aiпул storagedomain: worker-storageБез закріпленого вузла1DNS-запит2 HTTPS 443 · Браузер → AWS ALB23HTTP · NodePort4VirtualService5Завдання Celery6 consume · RabbitMQ → scan-worker67 HTTPS · Пул AI → LLM API78XADD scan:events9XREADGROUP10SETEX state11PUBLISH12SUBSCRIBE13Потік SSE14Відновлення після перепідключення1 HTTPS 443 · Браузер → AWS ALB12HTTP · NodePort3VirtualService4Завдання Taskiq5 consume · RabbitMQ → chat-worker56 HTTPS · Пул AI → LLM API67XADD chat:events8XREADGROUP9PUBLISH10SUBSCRIBE11Потік SSE12checkpoint13читання контрольної точки14синхронізація з PostgreSQL15chat-persistence group16збереження повідомлень1DNS-запит2 HTTPS 443 · Браузер → AWS ALB23HTTP · NodePort4ext-authz · gRPC 500515перевірка чорного списку6VirtualService7gRPC8gRPC1outbox:blacklist2blacklist.events3 blacklist.events · RabbitMQ → auth-worker34збереження чорного списку5 Celery batch · RabbitMQ → users-worker56UPSERT1образ · ревізія маніфесту2Ingress → ALB · DNS-записи3конфігурація xDS4кількість подів5 кількість подів · KEDA → пул storage56журнали7 трасування запусків LLM · Пул AI → LangSmith7

Запит Scan → доставка наживо

Запит на аналіз фото стає роботою в черзі, а події її поступу повертаються в той самий браузер.

  1. БраузерDNS-запит: DNS-запитRoute 53

    З записів Route 53 визначається лише ім’я. Запити через DNS не проходять.

  2. Браузерпотік даних: HTTPS 443AWS ALB

    TLS завершується на ALB.

  3. AWS ALBпотік даних: HTTP · NodePortIstio ingress Envoyk8s-ingress-gateway

    Передається в Istio ingress Envoy через NodePort цілі-інстансу EC2.

  4. Istio ingress Envoyk8s-ingress-gatewayпотік даних: VirtualServiceScan APIk8s-api-scan

    Маршрутизується до Scan API, який ставить роботу в чергу й одразу повертає job_id; на запит результату він відповідає 202, доки завдання не завершиться.

  5. Scan APIk8s-api-scanпотік даних: Завдання CeleryRabbitMQk8s-rabbitmq

    Завдання Scan іде в RabbitMQ.

  6. RabbitMQk8s-rabbitmqпотік даних: consumescan-workerk8s-worker-ai · k8s-worker-ai-2

    scan-worker (Celery · gevent) у пулі AI бере його й виконує Vision → Rule → Answer → Reward. Чотири етапи — це завдання Celery, з’єднані в ланцюжок, а не вузли.

  7. Пул AIk8s-worker-ai · k8s-worker-ai-2потік даних: HTTPSLLM API

    Воркери scan і chat викликають API OpenAI і Google.

  8. scan-workerk8s-worker-ai · k8s-worker-ai-2потік даних: XADD scan:eventsStreamsk8s-redis-streams

    Події поступу записуються в один із чотирьох шардів Streams.

  9. Streamsk8s-redis-streamsпотік даних: XREADGROUPEvent Routerk8s-event-router

    Event Router читає їх як consumer group і після обробки виконує XACK; pending і reclaim забезпечують доставку at-least-once.

  10. Event Routerk8s-event-routerпотік даних: SETEX stateState KVk8s-redis-streams

    Він записує останній стан і маркер повторної обробки в State KV на тому самому вузлі Redis.

  11. Event Routerk8s-event-routerпотік даних: PUBLISHPub/Subk8s-redis-pubsub

    Доставляється в реальному часі каналом завдання в шардованому Pub/Sub.

  12. Pub/Subk8s-redis-pubsubпотік даних: SUBSCRIBESSE Gatewayk8s-sse-gateway

    SSE Gateway підписується через один спільний listener на процес і розсилає кожному підключеному браузеру.

  13. SSE Gatewayk8s-sse-gatewayпотік даних: Потік SSEБраузер

    З’єднання, відкрите тим самим шляхом через ALB та ingress. Доставка at-least-once; дублікати обробляються ідемпотентно.

  14. State KVk8s-redis-streamsпотік даних: Відновлення після перепідключенняSSE Gatewayk8s-sse-gateway

    Під час перепідключення з Last-Event-ID State KV і збережені Streams заповнюють пропущені події.

Chat · токени й зберігання

Токени Chat ідуть тим самим шляхом подій, що й Scan; контрольні точки й повідомлення зберігають два різні робочі навантаження.

  1. Браузерпотік даних: HTTPS 443AWS ALB

    TLS завершується на ALB.

  2. AWS ALBпотік даних: HTTP · NodePortIstio ingress Envoyk8s-ingress-gateway

    Передається в Istio ingress Envoy через NodePort цілі-інстансу EC2.

  3. Istio ingress Envoyk8s-ingress-gatewayпотік даних: VirtualServiceChat APIk8s-api-chat

    Маршрутизується до Chat API.

  4. Chat APIk8s-api-chatпотік даних: Завдання TaskiqRabbitMQk8s-rabbitmq

    Завдання Chat іде в RabbitMQ.

  5. RabbitMQk8s-rabbitmqпотік даних: consumechat-workerk8s-worker-ai · k8s-worker-ai-2

    chat-worker (Taskiq · asyncio) класифікує намір за допомогою LangGraph, потім за потреби виконує vision, обрані інструменти, aggregator і за потреби підсумок, після чого відповідає. Кожен запит виконує лише потрібні йому гілки.

  6. Пул AIk8s-worker-ai · k8s-worker-ai-2потік даних: HTTPSLLM API

    Воркери scan і chat викликають API OpenAI і Google.

  7. chat-workerk8s-worker-ai · k8s-worker-ai-2потік даних: XADD chat:eventsStreamsk8s-redis-streams

    Токени й події етапів записуються в чотири шарди Streams; далі шлях доставки такий самий, як у Scan.

  8. Streamsk8s-redis-streamsпотік даних: XREADGROUPEvent Routerk8s-event-router

    Event Router читає їх як consumer group і після обробки виконує XACK; pending і reclaim забезпечують доставку at-least-once.

  9. Event Routerk8s-event-routerпотік даних: PUBLISHPub/Subk8s-redis-pubsub

    Доставляється в реальному часі каналом завдання в шардованому Pub/Sub.

  10. Pub/Subk8s-redis-pubsubпотік даних: SUBSCRIBESSE Gatewayk8s-sse-gateway

    SSE Gateway підписується через один спільний listener на процес і розсилає кожному підключеному браузеру.

  11. SSE Gatewayk8s-sse-gatewayпотік даних: Потік SSEБраузер

    З’єднання, відкрите тим самим шляхом через ALB та ingress. Доставка at-least-once; дублікати обробляються ідемпотентно.

  12. chat-workerk8s-worker-ai · k8s-worker-ai-2потік даних: checkpointCachek8s-redis-cache

    Контрольна точка LangGraph зберігається в Redis Cache.

  13. Cachek8s-redis-cacheпотік даних: читання контрольної точкиcheckpoint-syncerk8s-worker-ai · k8s-worker-ai-2

    checkpoint-syncer читає контрольну точку з Redis.

  14. checkpoint-syncerk8s-worker-ai · k8s-worker-ai-2потік даних: синхронізація з PostgreSQLPostgreSQLk8s-postgresql

    AsyncPostgresSaver асинхронно зберігає її в PostgreSQL.

  15. Streamsk8s-redis-streamsпотік даних: chat-persistence grouppersistence consumerk8s-api-chat

    persistence consumer на вузлі Chat читає події done як consumer group.

  16. persistence consumerk8s-api-chatпотік даних: збереження повідомленьPostgreSQLk8s-postgresql

    Повідомлення Chat зберігаються в PostgreSQL. Це інше робоче навантаження, ніж checkpoint-syncer.

Вхід · автентифікація

Синхронний шлях від входу в кластер до доменного API. Лише шляхи під політикою спершу перевіряють автентифікацію; трафік подів між вузлами йде через Calico VXLAN.

  1. БраузерDNS-запит: DNS-запитRoute 53

    З записів Route 53 визначається лише ім’я. Запити через DNS не проходять.

  2. Браузерпотік даних: HTTPS 443AWS ALB

    TLS завершується на ALB.

  3. AWS ALBпотік даних: HTTP · NodePortIstio ingress Envoyk8s-ingress-gateway

    Передається в Istio ingress Envoy через NodePort цілі-інстансу EC2.

  4. Istio ingress Envoyk8s-ingress-gatewayпотік даних: ext-authz · gRPC 50051ext-authzk8s-api-auth

    Лише шляхи під політикою CUSTOM спершу звертаються до Go ext-authz (тайм-аут 2 с, failOpen false). Шляхи на кшталт login, health і docs виключено.

  5. ext-authzk8s-api-authпотік даних: перевірка чорного спискуblacklistk8s-redis-auth

    Токен перевіряється за чорним списком Redis.

  6. Istio ingress Envoyk8s-ingress-gatewayпотік даних: VirtualServiceChat APIk8s-api-chat

    Маршрутизується до Chat API.

  7. Chat APIk8s-api-chatпотік даних: gRPCimages APIk8s-api-image

    Синхронний виклик chat → images, зазначений у README.

  8. auth APIk8s-api-authпотік даних: gRPCusers APIk8s-api-users

    Синхронний виклик auth → users, зазначений у README.

Пул storage · асинхронний запис

Чорний список автентифікації та володіння персонажами зберігають воркери пулу storage, які беруть роботу з RabbitMQ.

  1. blacklistk8s-redis-authпотік даних: outbox:blacklistauth-relayk8s-worker-storage · k8s-worker-storage-2

    auth-relay (auth-Bus у README) читає outbox Redis.

  2. auth-relayk8s-worker-storage · k8s-worker-storage-2потік даних: blacklist.eventsRabbitMQk8s-rabbitmq

    Він повторно публікує в RabbitMQ, з повторами й DLQ.

  3. RabbitMQk8s-rabbitmqпотік даних: blacklist.eventsauth-workerk8s-worker-storage · k8s-worker-storage-2

    auth-worker отримує події чорного списку.

  4. auth-workerk8s-worker-storage · k8s-worker-storage-2потік даних: збереження чорного спискуblacklistk8s-redis-auth

    Вони зберігаються в чорному списку Redis.

  5. RabbitMQk8s-rabbitmqпотік даних: Celery batchusers-workerk8s-worker-storage · k8s-worker-storage-2

    users-worker отримує роботу з володіння персонажами пакетами.

  6. users-workerk8s-worker-storage · k8s-worker-storage-2потік даних: UPSERTPostgreSQLk8s-postgresql

    Вона застосовується до PostgreSQL.

Налаштування · масштабування · спостереження

Platform Layer — не етап, через який проходять запити; він розгортає, налаштовує, масштабує й спостерігає інші шари. Вузли — це інстанси EC2, створені Terraform, із kubeadm і Calico, встановленими через Ansible; CI лише перевіряє Terraform і ніколи не застосовує його автоматично.

  1. GitHub Actions · Docker Hubналаштування · масштабування: образ · ревізія маніфестуArgo CD image updaterk8s-master

    Argo CD узгоджує конфігурацію кластера через App-of-Apps і Sync Waves. Підтверджено лише розміщення image updater на control-plane.

  2. ALB Controller · ExternalDNSk8s-masterналаштування · масштабування: Ingress → ALB · DNS-записиПід керуванням AWS

    ALB Controller і ExternalDNS налаштовують ресурси на боці AWS. Це не шлях, яким проходять запити.

  3. Istiodk8s-masterналаштування · масштабування: конфігурація xDSIstio ingress Envoyk8s-ingress-gateway

    Istiod передає конфігурацію Gateway, VirtualService і EnvoyFilter через xDS в ingress Envoy і в Envoy sidecar кожного API.

  4. KEDAk8s-monitoringналаштування · масштабування: кількість подівПул AIk8s-worker-ai · k8s-worker-ai-2

    KEDA змінює кількість подів воркерів. Кількість вузлів не змінюється.

  5. KEDAk8s-monitoringналаштування · масштабування: кількість подівпул storagek8s-worker-storage · k8s-worker-storage-2

    Поди воркерів пулу storage масштабуються так само.

  6. Fluent Bitспостережуваність: журналиElasticsearchk8s-logging

    Fluent Bit — DaemonSet на кожному вузлі, що надсилає журнали в Elasticsearch.

  7. Пул AIk8s-worker-ai · k8s-worker-ai-2спостережуваність: трасування запусків LLMLangSmith

    Траси викликів LLM ідуть до LangSmith — зовнішнього SaaS.

Усі зв’язки однакової товщини. Оберіть потік, щоб підсвітити лише його шлях із пронумерованими кроками.

  • Суцільна · напрямок, яким рухаються запити, робота, події й записи
  • Пунктирна · DNS-запит; запити через нього не проходять
  • Штрихова · налаштування чи масштабування; не шлях даних
  • Довга штрихпунктирна · журнали й трасування запусків
  • Товста чорна лінія · обраний потік; номери показують порядок
  • Рамка · фізичний вузол, ім’я хоста в заголовку
  • Внутрішня плашка · робоче навантаження на цьому вузлі
  • Штрихова рамка · пул планування з двох вузлів
  • Штрихова рамка · поза кластером, не рахується як вузол
  • Помаранчевий контур · де вирішує модель
  • Control plane1 вузол
  • Domain API8 вузлів
  • Пул AI2 вузли
  • пул storage2 вузли
  • Data5 вузлів
  • Platform6 вузлів

П’ять шарів із README (смуги) й фізичні групи (відтінок заголовка кожного вузла) групують ті самі 24 вузли по-різному. State KV ділить вузол зі Streams і окремо не рахується; Route 53, ALB і сервіси поза кластером не є вузлами. Пул — це діапазон планування, а не твердження, що кожен под працює на обох вузлах.

Схема з 24 вузлів · за переліком вузлів на дашборді від January 21, 2026

24вузлів

24 = 1 control plane + 8 API + 4 worker + 5 data + 6 platform

  1. 1Control plane

    role: control-plane

    kube-apiserver · scheduler · controller-manager · etcd, а також контролери платформи.

    1. k8s-master
  2. 8Domain API

    domain: <сервіс>

    Один вузол на домен. Внутрішні виклики використовують gRPC.

    1. k8s-api-auth
    2. k8s-api-users
    3. k8s-api-scan
    4. k8s-api-character
    5. k8s-api-location
    6. k8s-api-image
    7. k8s-api-chat
    8. k8s-api-info
  3. 4Execution worker

    Два пули планування по два вузли. KEDA змінює кількість подів; кількість вузлів лишається тією самою.

    пул storagedomain: worker-storage
    1. k8s-worker-storage
    2. k8s-worker-storage-2
    Пул AIdomain: worker-ai
    1. k8s-worker-ai
    2. k8s-worker-ai-2
  4. 5Data

    Redis розділено за призначенням на чотири вузли. Сховище PostgreSQL — EBS CSI · gp3.

    1. k8s-postgresql
    2. k8s-redis-auth
    3. k8s-redis-streams
    4. k8s-redis-cache
    5. k8s-redis-pubsub
  5. 6Platform

    Обмін повідомленнями, спостережуваність, ingress і доставка в реальному часі мають кожен свій вузол.

    1. k8s-rabbitmq
    2. k8s-monitoring
    3. k8s-logging
    4. k8s-ingress-gateway
    5. k8s-sse-gateway
    6. k8s-event-router
Кожен вузол
  • Fluent Bit · DaemonSet
  • Calico

Налаштовані моделі · за провайдерами

Сервіс закрито, тож це моделі, налаштовані в репозиторії, а не варіанти, доступні сьогодні. Кожну роль наведено окремо; це не список перевірених запусків.

  • OpenAI

    Типовий провайдер Chat

    Chat

    • openai/gpt-5.2типово

    Типова модель — gpt-5.2; якщо модель вказано в запиті, використовується вона.

    Scan

    • gpt-5.2типово
    • gpt-5.2-pro
    • gpt-5.1
    • gpt-5
    • gpt-5-pro
    • gpt-5-mini

    Моделі поза відображенням із 13 моделей відхиляються.

    Відображення зображень

    • gpt-image-1.5

    Окремо від gpt-5.2 — моделі оркестрації Responses. Генерацію зображень типово вимкнено.

    Оцінювання

    • gpt-4o-miniтипово

    LLM grader для оцінювання розмов, окремий від моделі Chat.

  • Google

    Коли в Chat обрано Google

    Chat

    • google/gemini-3-pro-preview
    • google/gemini-3-flash-preview

    Якщо обрано Google, типовою є gemini-3-flash-preview.

    Scan

    • gemini-3-pro-preview
    • gemini-3-flash-preview
    • gemini-2.5-pro
    • gemini-2.5-flash
    • gemini-2.5-flash-lite
    • gemini-2.0-flash
    • gemini-2.0-flash-lite

    Відображення зображень

    • gemini-3-pro-image-preview