Skip to content
Jithendar.com

Inside RoboShop AI: microservices on Kubernetes, from Minikube today to an EKS-ready design

How RoboShop AI's storefront, gateway, AI assistant and data services fit together, how it ships to Kubernetes today, and how its EKS stack is designed.

Published 10 min read

RoboShop AI storefront hero with the headline "A little more extraordinary" and a humanoid robot render
On this page

RoboShop AI is a robot store built from independently deployable services: a TypeScript storefront, a Python API gateway, a LangGraph shopping assistant, Go and Java services, and MongoDB, PostgreSQL, Redis, RabbitMQ and Kafka behind them. It runs live at jithendar.com/roboshop, and the code is public on GitHub.

This article walks through how it works, how it is deployed today, and how its Amazon EKS stack is designed.

At a glance

  • One public entry point. Only the edge proxy and gateway receive browser traffic; every other service is internal.
  • Polyglot by design. TypeScript, Python, Go and Java services, each with its own Dockerfile and Kubernetes manifest.
  • AI that cannot act on its own. The shopping assistant's model output is guidance only; it cannot execute tools, and no model is connected until an administrator chooses one.
  • Events without coupling. Orders flow to shipping over RabbitMQ; Kafka receives a replayable copy for analytics without adding a dependency to checkout.
  • Observable end to end. OpenTelemetry traces, Prometheus metrics and Loki logs across the services.

What RoboShop AI looks like

The storefront is a catalogue of twenty robots with search, filters, product pages, a cart and checkout.

RoboShop AI storefront hero with the headline "A little more extraordinary" and a humanoid robot render

The RoboShop AI storefront. Product images are labelled in the app as AI-generated concept renders.

Grid of RoboShop robot products such as AeroInspect A9, AgroBot A200 and Atlas X1 with prices and Add to cart buttons

The collection view with category filters, search and sorting. Prices are marked as demo prices.

RoboShop product page for the AeroInspect A9 drone with price, quantity, Add to cart and technical specifications

A product page: specifications, a clear note that hardware details are pending supplier confirmation, and the Moks assistant button in the corner.

RoboShop cart page in test mode showing the three checkout steps and an empty cart

Checkout is a three-step flow (cart, delivery and payment, confirmation), shown here in test mode.

Architecture overview

The browser talks to one origin. The edge proxy serves the storefront and forwards API calls to the AI gateway, which routes to the internal services.

Browser ──► nginx (edge) ──► frontend (storefront assets)
                │
                └──► ai-gateway :3000 ── public API, auth, order ledger
                        ├──► catalogue-service :4108 ──► MongoDB (products)
                        ├──► user-service ─────────────► MongoDB (accounts, sessions)
                        ├──► cart-service ─────────────► Redis
                        ├──► payment-service :4105 ────► Razorpay Orders & Payments API
                        ├──► moks (shopping agent) :4103 ──► LLM selected by a super admin
                        ├──► currency-service ─────────► ECB reference rates (hourly, cached)
                        └──► outbox ──► RabbitMQ ──► shipping-service ──► PostgreSQL
                                          └──► kafka-bridge ──► Kafka (analytics events)

mcp-server (internal) ──► gateway tools        OpenTelemetry ──► collector ──► Jaeger

Two rules shape everything else:

  1. Only the gateway is exposed for application traffic. Requests are same-origin, so the browser never talks to a backend directly.
  2. Each service owns its data. The catalogue owns product reads, the user service owns accounts, the cart service owns Redis, the gateway owns the order ledger, and shipping owns its PostgreSQL database.

The services

ServiceStackResponsibility
frontendTypeScriptStorefront, product pages, cart and admin UI
nginxnginxEdge proxy, asset routing and security headers
ai-gatewayPythonPublic API routing, authorization and the order ledger
user-servicePython + MongoDBAccounts, sessions, profiles, MFA, email recovery and purchase history
catalogue-serviceNode.js + MongoDBCatalogue reads, validated imports and publication
cart-servicePython + RedisCarts
payment-serviceNode.js + RazorpayPayment orders and captured-payment verification
shipping-serviceJava/Gradle + PostgreSQLLocations, quotes and shipment requests
currency-serviceGo (standard library)Estimated local-currency prices from the ECB reference feed
moksPython, LangGraph/LangChainThe shopping assistant (widget and AI engine)
mcp-serverPython, FastMCPDiagnostics and Model Context Protocol tools, internal only
kafka-bridge—Copies order events from RabbitMQ to Kafka

Supporting infrastructure: MongoDB, PostgreSQL, Redis, RabbitMQ and Kafka, plus Prometheus, Grafana, Loki/Alloy, the OpenTelemetry Collector and Jaeger.

How a purchase flows through the system

The catalogue service reads products from MongoDB. Recommendations and the assistant's retrieval work from that same catalogue snapshot, and the gateway supplies the sold-out exclusions so nobody is recommended something they cannot buy.

2. Prices in your currency

currency-service downloads the European Central Bank's reference feed once an hour, with a five-second deadline and a 64 KiB response limit. Requests only ever read the cache, so a slow upstream can never slow the storefront. After two hours without a successful refresh, rates are labelled stale; after seven days they are withdrawn rather than guessed. The rates are informational: country is a display hint and cannot affect payment.

3. Cart and checkout

Carts live in Redis behind cart-service. Orders, stock reservations and payment orders are recorded in the gateway's commerce ledger, which has a single writer so stock can never be double-counted. Today that ledger is a JSON store on one gateway replica; a transactional PostgreSQL ledger is built and tested as an opt-in migration (COMMERCE_BACKEND=postgres) but not yet switched on.

Checkout uses stock reservations: stock is held for the order before payment, so two buyers cannot both pay for the last unit.

4. Payment

payment-service integrates Razorpay's Orders and Payments API. The design does not trust the browser's word that a payment succeeded:

  • payment signatures are validated on the server,
  • the payment is checked as captured before the order is confirmed,
  • signed webhooks and status recovery reconcile anything the browser never reported back.

5. Shipping and analytics events

Confirmed orders are written to a durable outbox and published to RabbitMQ with publisher confirms, which feeds shipping-service. Separately, an independent quorum queue feeds kafka-bridge, which publishes to Kafka and only acknowledges RabbitMQ after Kafka confirms delivery. The result is a replayable event stream for analytics, with no Kafka calls or readiness dependencies added to checkout.

The AI shopping assistant

The Moks button on every page opens the shopping assistant: one Python process serving both the widget and a LangGraph/LangChain engine.

  • Who chooses the model. Only a super admin can connect a provider (Amazon Bedrock Converse or an approved Ollama endpoint), test it, and activate it. Configuration changes are revisioned and audited.
  • No database access for the agent. The agent owns inference but has no MongoDB credentials. Before every generation it reads the active configuration from the gateway; a changed revision or a disconnect stops new attempts.
  • Guidance, not actions. Model output cannot execute tools.

The MCP server exposes 15 tools with strict schemas and mutation annotations through FastMCP. Every call goes through the gateway, it is reachable only on the internal Kubernetes Service, and it has no public ingress.

Security and hardening

  • Containers run non-root, with a read-only root filesystem and dropped Linux capabilities.
  • Secrets are never baked into images; they are provided at runtime.
  • The gateway checks Origin and CSRF protections on authenticated actions.
  • There is no default administrator password. Customers, admins and a single super admin have separate roles.
  • Payment safety relies on server-side signature and capture checks, not the client.

Observability

Every service exposes liveness and metrics endpoints. The gateway's readiness check includes its dependencies, so Kubernetes stops sending traffic to it when something it relies on is down.

SignalPath
TracesServices → OpenTelemetry Collector → Jaeger (context propagates across internal HTTP calls)
MetricsPrometheus scrapes each service; dashboards in Grafana
LogsLoki, collected with Alloy
LLM tracesOptional Langfuse endpoint for the assistant

How it is deployed today

git push ──► GitHub Actions (self-hosted ARM64 runner)
               └─ docker build (linux/arm64) ──► Amazon ECR  roboshop-<service>:latest
                                                     │
Argo CD catalog (manual sync) ──► Minikube cluster ◄─┘  pulls with an ecr-pull secret
                                    └─ Traefik  /roboshop ─► strip prefix ─► nginx ─► services
Delivery today: GitHub Actions builds, ECR stores, Argo CD applies.
  • Cluster. A four-node Minikube cluster (arm64 nodes) on a single server, shared with other workloads.
  • Images. Each service has its own GitHub Actions workflow that builds an arm64 image on a self-hosted runner and pushes it to a private ECR repository.
  • Delivery. An Argo CD catalog describes every workload. New applications start with manual sync and no automatic pruning, so each change is reviewed in Argo CD before it reaches the cluster.
  • Registry credentials. ECR tokens expire, so a CronJob refreshes the ecr-pull image-pull secret every six hours.
  • Routing. Traefik serves the app under /roboshop and strips that prefix before forwarding to the edge proxy. TLS comes from cert-manager and Let's Encrypt.

The EKS design

The infrastructure/ Terraform describes how RoboShop AI would run on Amazon EKS. It is opt-in: nothing changes unless eks_enabled = true is supplied, and today the file is parked as eks.tfbk.

Network

LayerCIDRs (first two AZs)Purpose
Private10.0.0.0/20, 10.0.16.0/20EKS nodes, pod addresses and control-plane network interfaces
Public10.0.240.0/24, 10.0.241.0/24Internet-facing load balancers and NAT gateways
  • Private subnets reach the internet through a NAT gateway in the same AZ (a single shared NAT is an optional cost saving with a resilience trade-off).
  • An S3 gateway endpoint carries S3 traffic, including ECR image layers, without NAT.
  • Neither subnet type assigns public IPs to instances automatically.

Cluster

  • Kubernetes 1.36, deliberately chosen over the newer 1.37 to stay inside cert-manager 1.21's tested range.
  • API access is locked down: the private endpoint is always on; the public endpoint is enabled only for listed admin/CI CIDRs, and 0.0.0.0/0 is rejected by validation.
  • Access entries (authentication mode API) grant cluster-admin only to listed IAM roles or users. No cluster creator gets implicit admin access.
  • Control-plane audit, API and authenticator logs go to CloudWatch.
  • A managed node group of two t3.large on-demand workers (configurable from 2 to 6) runs in the private subnets on Amazon Linux 2023.
  • Core add-ons: vpc-cni, coredns, kube-proxy and eks-pod-identity-agent, versions resolved against the selected Kubernetes version.

Add-ons (designed, later removed from the repository)

A second Terraform state installed the platform layer once the cluster existed:

ComponentVersionRole
Traefikchart 42.1.0Ingress and TLS termination
AWS Load Balancer Controllerchart 3.6.0Provisions Traefik's public NLB, using pod identity
EBS CSI driver—Encrypted gp3 storage class (WaitForFirstConsumer, Retain), using pod identity
cert-managerv1.21.2Let's Encrypt staging and production issuers (HTTP-01 through Traefik)
KEDA2.21.0Event-driven autoscaling

The whole stack is applied by a manual Create infrastructure GitHub Actions workflow on the self-hosted runner: format check, validate, test, then plan and apply in order. There is no plan-only option, so every run applies.

Minikube today versus the EKS design

ConcernMinikube (today)EKS (design)
Nodes4 × arm64, single server2–6 × t3.large (x86_64), private subnets, multiple AZs
IngressTraefik on the hostTraefik behind an AWS NLB
Storagestandard host-path volumes tied to one nodeEncrypted gp3 EBS volumes
DeliveryArgo CD catalog, manual syncNew cluster; application delivery not yet defined
CostOne serverEKS control plane, EC2, NAT, load balancer, logs and volumes

What I would do next

Explore the code

Comments

    No comments yet. Start the conversation.