Skip to content
2025 – 2026AI ProductDistributed SystemsPlatform Engineering

CodeNex

An AI builder that turns a prompt into a running React application, on a microservice backend that gives every project its own live preview environment.

backend services split by scaling profile behind one gateway
3backend services split by scaling profile behind one gateway
isolated preview environment, addressed by its own subdomain
1 per projectisolated preview environment, addressed by its own subdomain
public product with streaming generation and running previews
Livepublic product with streaming generation and running previews

Generating code is the easy half. The hard half is everything around it: where the files live, how a user sees the result running, how concurrent builds stay isolated, and how streaming keeps the interface alive while a model works. I built CodeNex as a distributed system rather than a wrapper — a Spring Cloud backend, streamed generation, and per-project preview environments served on their own subdomains.

The problem

A prompt-to-app product only feels real when the user can click into a running application, not read a code listing. That requires solving problems a single service cannot: long-running generation that must stream rather than block, generated files that need durable storage separate from the container that produced them, previews that must be isolated per project, and the caching and quota accounting that keeps any of it affordable under concurrency.

Constraints

  • Generation takes far longer than a request-response cycle tolerates, so progress has to stream or the interface looks broken.
  • Every project's preview must be isolated — one user's generated app cannot reach another's files or environment.
  • Generated artifacts outlive the process that created them, so they cannot live on the generating container's disk.
  • Model calls cost money per token, so quotas and caching are product requirements, not optimizations.

Decisions

What I chose, why, and what I turned down to get there.

Split the backend by responsibility, behind one gateway

Account, workspace, and intelligence became separate services behind a Spring Cloud gateway, with routing by path prefix and configuration pulled from a central config service. Generation is bursty and expensive while account operations are cheap and constant — coupling them means scaling the wrong thing, and a model-provider failure taking down login.

Considered and rejected

  • A single monolithic backend — faster to build, and it forces generation load and auth traffic to scale together

A preview environment per project, on its own subdomain

Generated apps are served from a dedicated previews namespace, matched by subdomain through the ingress and resolved to a dynamic preview by a proxy service. Subdomain isolation gives each project a real origin, which means browser security boundaries do the isolation work rather than application-level path checks that are easy to get subtly wrong.

Considered and rejected

  • Serving previews from a shared path on the main domain — one origin for every user's generated code, so cookies and storage are shared by default

Object storage for generated files, not container disk

Files are pushed to object storage and watched into the preview environment, so the artifact survives the generating pod and a preview can be rebuilt without re-running the model. Treating generated code as durable state rather than process output is what makes workspaces resumable.

Stream tokens over server-sent events

Generation streams to the browser as it happens instead of resolving one long request. The user sees work in progress, which changes the product from a loading spinner into something that feels alive — and it removes the timeout ceiling a buffered response would impose.

An event bus between generation and everything downstream

Generation publishes events that other services consume, with a cache layer in front of read paths. Usage accounting, workspace updates, and preview refreshes are all reactions to generation rather than steps inside it, so a slow consumer cannot stall the generation itself.

The shape of the system

Traffic enters through an ingress that splits two ways: API calls to the gateway service and preview traffic to a proxy service that resolves project subdomains. Behind the gateway, account, workspace, and intelligence services each own their deployment and pull configuration centrally. The data layer carries a relational store for durable state, an event bus between services, a cache in front of hot reads, and object storage for generated files, which sync into the previews namespace.

  • Preview resolution is a subdomain match rather than a lookup in application code, so adding a project needs no routing change.
  • Configuration is fetched by services at runtime rather than baked into images, so an environment change does not require a rebuild.

What this was for

CodeNex is the project where I owned every layer at once — backend architecture, the streaming path, Kubernetes deployment, storage, authentication, quotas, and subscription billing. The value of building it was learning where a distributed system's real cost sits, which is almost never in the interesting part: it is in isolation boundaries, durable state, and what happens on the second concurrent request.

Stack

  • Java
  • Spring Boot
  • Spring AI
  • Spring Cloud Gateway
  • React
  • TypeScript
  • Kubernetes
  • PostgreSQL
  • Kafka
  • Redis
  • MinIO
  • Stripe

What was mine

Designed and built solo — backend services, streaming architecture, preview infrastructure, storage, authentication, quotas, and billing foundations.