atlas commerce
@tejasgk|2026 — Present
A multi-tenant ecommerce platform I built from the ground up to explore what actually goes into building a modern commerce system beyond the storefront.
2026 — Present
Next.js · React · TypeScript · Node.js · Go · MongoDB · PostgreSQL · Redis · Kafka · Stripe · WebSockets · OpenAI · TensorFlow.js · Docker · Kubernetes · Terraform · AWS
Production brand: Penderghast
What is Atlas Commerce?
Atlas Commerce started with a fairly simple idea: build an ecommerce marketplace from scratch.
Not just a storefront connected to Stripe, but the actual platform behind it.
I wanted sellers to be able to join the platform, create stores, list products, receive orders and payments, talk to customers, run promotions, understand their analytics, customize their storefronts and eventually use AI to operate parts of their business.
Customers needed their own side of the system: discovery, search, recommendations, carts, wishlists, checkout, orders, offers, store pages and real-time conversations with sellers.
And because it is a marketplace rather than a single ecommerce store, the platform itself also needed an administration layer for managing sellers, customers, products, events, payments, configuration and the health of the overall system.
What started as an ecommerce project eventually became an experiment in distributed systems, realtime software, payments, recommendation systems, AI agents and cloud infrastructure.
Today Atlas Commerce consists of roughly 19 applications and services inside a monorepo, including multiple Next.js frontends, TypeScript microservices, a Go realtime service, event-streaming infrastructure, an AI-powered storefront builder and the infrastructure required to deploy the platform.
The three sides of the marketplace
At a high level, Atlas Commerce has three primary users.
Customers
Customers interact with the marketplace itself.
They can browse products and stores, search and filter the catalog, view offers, add products to their cart or wishlist, checkout, track orders, manage their profile and shipping addresses, and communicate directly with sellers.
The storefront includes pages for:
- product discovery
- individual products
- shops
- cart
- checkout
- orders
- wishlist
- offers
- profile
- inbox
The frontend is built with Next.js, React and TypeScript.
Cart and wishlist state is handled locally with Zustand while server data is handled through React Query.
But actions inside the storefront also become useful signals elsewhere in the system.
When someone views a product, adds something to their cart, adds something to their wishlist or makes a purchase, those actions can be published as events.
Those events eventually feed the analytics and recommendation systems.
So the storefront isn't just displaying data.
It is one of the producers in a larger event-driven system.
Sellers
Sellers get a completely separate application.
This is essentially the operating system for running a store on Atlas Commerce.
A seller can create and manage products, process orders, create discounts, run events and promotions, communicate with customers, manage their team, configure payments, inspect performance and control their storefront.
The dashboard includes things like revenue and store-performance metrics, six-month revenue charts, order management, product management, customers, invoices, payments, notifications and messaging.
Atlas also supports multiple stores under a seller account.
A seller can switch between shops, and the rest of the dashboard operates within the currently active store.
That sounds like a relatively small feature, but it affects authorization and data access throughout the system because every operation has to understand both:
Who is this seller?
and
Which shop are they currently operating?
The authentication middleware resolves that context before requests reach protected seller functionality.
Administrators
There is also a dedicated admin application for operating the marketplace itself.
Admins can work with products, orders, users, sellers, events, notifications and global site configuration.
The admin dashboard includes marketplace-level KPIs such as revenue, orders, sellers and customers, along with charts, geographic information and recent activity.
I also built a realtime logging interface into the admin side.
Backend services can publish structured logs into Kafka.
A logger service consumes those events and broadcasts them over WebSockets to connected admin clients.
That gives the admin interface a live view into what is happening across the platform.
Architecture
As Atlas grew, I moved away from treating the backend as one application.
The backend is now organized as a set of services behind a central API gateway.
Conceptually:
┌─────────────────────┐
│ Customer Store │
└──────────┬──────────┘
│
┌──────────┴──────────┐
│ Seller Dashboard │
└──────────┬──────────┘
│
┌──────────┴──────────┐
│ Admin Console │
└──────────┬──────────┘
│
API Gateway
│
┌────────────┬───────┼───────┬─────────────┐
│ │ │ │ │
Auth Products Seller Orders Admin
│ │ │ │ │
└────────────┴───────┼───────┴─────────────┘
│
┌──────────────┼───────────────┐
│ │ │
Chat Recommendations Kafka
│ │
Redis Analytics
│ │
Database Logs
The gateway is responsible for routing traffic to the appropriate service and also provides shared concerns such as CORS and rate limiting.
The main services include:
Auth Service — registration, authentication, OTP verification, password management, seller onboarding and Stripe Connect setup.
Product Service — catalog management, product CRUD, variants, images, discount codes, events, search and product analytics.
Seller Service — shop lifecycle, profiles, websites, custom domains, followers, notifications and team members.
Order Service — payments, order creation, coupons, inventory updates, delivery state and confirmation emails.
Admin Service — marketplace administration.
Chatting Service — realtime customer/seller messaging.
Recommendation Service — personalized product recommendations.
Kafka Service — background event processing and analytics updates.
Logger Service — centralized realtime application logging.
There is also a separate OAuth service and a Go-based chat system I built alongside the main messaging implementation.
Authentication and multi-tenancy
Authentication has three main identities:
customer, seller and administrator.
The system uses JWT access and refresh tokens, with access tokens expiring relatively quickly and refresh tokens lasting longer.
Registration includes OTP verification, with temporary OTP state stored in Redis.
Authorization middleware handles role-specific access.
Seller authentication has another dimension because sellers can operate multiple shops.
Requests therefore resolve an active shop from the seller's session/context and attach that shop to the authenticated request.
This allows downstream services to reason about:
authenticated seller
+
currently selected shop
↓
shop-scoped operation
rather than repeatedly rebuilding that logic inside individual endpoints.
Products and catalog
Products are considerably more complicated than a name, image and price.
The catalog supports things such as:
- categories
- product images
- colors
- sizes
- variants
- custom specifications
- custom properties
- discounts
- events
- search
- filtering
- product analytics
- inventory
- sales counts
Images are uploaded through ImageKit.
Products use unique slugs for public URLs and can be soft-deleted rather than immediately destroyed.
A seller gets a short restoration window before deleted products disappear permanently.
The public product APIs support filtering across attributes such as price, category, color, size and country, along with searches, offers and shop discovery.
Payments and marketplace orders
Payments were one of the more interesting parts because Atlas isn't a normal single-vendor store.
A customer can be buying through a marketplace where the platform and individual sellers have different financial relationships.
I integrated Stripe PaymentIntents and Stripe Connect.
Atlas can create a payment while accounting for the seller receiving their portion and the marketplace taking a platform fee.
The order flow doesn't stop when Stripe says a payment succeeded.
A successful payment webhook triggers the rest of the commerce workflow.
That includes:
Payment succeeds
↓
Stripe webhook
↓
Create order
↓
Associate products / seller
↓
Decrease inventory
↓
Update sales / analytics
↓
Create notifications
↓
Send confirmation email
Payment sessions are temporarily stored in Redis.
Orders also have their own delivery lifecycle:
Ordered → Packed → Shipped → Out for Delivery → Delivered
The system supports percentage and fixed-value coupons as well.
Event-driven analytics with Kafka
One of the things I specifically wanted to learn while building Atlas was where an event system such as Kafka actually becomes useful.
Ecommerce gives you a natural use case.
A customer might:
view product
→ add to wishlist
→ add to cart
→ purchase
Those aren't just UI interactions.
They're behavioural events.
The storefront publishes events such as product views, cart additions and wishlist interactions to Kafka.
A background consumer processes those events and updates user and product analytics.
Conceptually:
Customer action
↓
Next.js storefront
↓
Kafka producer
↓
user-events topic
↓
Kafka consumer
↓
User analytics + Product analytics
↓
Recommendation system
I also use Kafka for other asynchronous parts of the platform.
Chat messages can flow through Kafka before being persisted in batches.
Structured application logs are published into another topic and consumed by the realtime logger service.
So Kafka became a shared event backbone rather than something I added just to say the project uses Kafka.
Personalized recommendations
Atlas also has its own recommendation service.
I built a collaborative-filtering-style model using TensorFlow.js.
Different user actions represent different levels of intent, so I don't treat all interactions equally.
For example:
product view → 0.1
wishlist → 0.5
add to cart → 0.7
purchase → 1.0
A purchase is obviously a much stronger signal than opening a product page.
The model uses user and product embeddings and generates personalized product recommendations from these interactions.
Recommendations are cached for three hours.
For users without enough behavioural history, the system falls back to a simpler cold-start strategy instead of pretending that it knows their preferences.
This was useful because it let me experiment with where traditional ML makes sense versus where an LLM makes sense.
Recommendations are fundamentally a prediction problem.
The agent functionality I added later is a language-understanding and tool-use problem.
They're separate systems.
Real-time messaging
Customers and sellers can communicate directly inside Atlas.
The main chat system combines REST APIs, WebSockets, Redis, Kafka and MongoDB.
WebSockets handle live delivery and presence.
Redis keeps track of online state and unseen-message counts.
Kafka is used to buffer message persistence.
Instead of writing every incoming message individually as part of the realtime delivery path, messages can be consumed and persisted in batches.
The system also supports:
- conversations
- paginated message history
- online/offline status
- unread counts
- mark-as-seen events
- customer and seller inboxes
I later built another chat implementation in Go as a separate service.
That version uses Go's HTTP stack with Gorilla WebSocket, PostgreSQL and Redis.
Part of the reason for building it was simply that I wanted to implement one of the realtime services outside the JavaScript ecosystem and understand the differences rather than keeping the entire platform TypeScript-only.
Store websites and custom domains
Atlas isn't limited to one central marketplace storefront.
Sellers can also have their own websites.
A shop website stores its own pages, theme, settings and SEO configuration.
Websites have lifecycle operations including publishing and archiving.
Publishing creates a snapshot of the website state rather than treating every editor change as immediately public.
Sellers can also connect custom domains.
Atlas generates verification information that can be checked through DNS before a domain becomes associated with a store.
A seller with multiple domains can choose which one should be primary.
The public storefront can then resolve the correct shop based on the incoming domain.
The website builder
Once sellers could have their own websites, I wanted them to be able to actually design those sites inside Atlas rather than choosing from a handful of hardcoded themes.
So I built a separate storefront builder.
It's a Next.js/React application with a drag-and-drop editor.
Merchants can:
- create multiple pages
- drag and drop sections
- add and modify elements
- edit properties
- preview different device sizes
- use templates
- undo and redo changes
- use keyboard shortcuts
- export HTML
There are currently multiple starting templates that merchants can filter and customize.
The important architectural idea is that the website isn't just arbitrary generated HTML.
The editor operates on a structured representation of the website.
That made the next feature possible.
AI-powered website building
I added an LLM directly into the builder.
Instead of requiring the merchant to manually perform every edit, they can describe what they want.
For example:
Add an About page with a hero, some information about the company and a CTA at the bottom.
I didn't want the LLM generating a giant blob of HTML and replacing the page.
Instead, the model returns structured operations.
Conceptually:
Merchant prompt
↓
LLM
↓
Structured BuilderAgentPlan
↓
Validate operations
↓
Builder engine
↓
Website document
↓
React renders changes
The model can plan operations such as adding, renaming or deleting pages, sections and elements.
The actual application remains responsible for executing those operations.
That means the LLM interprets intent while the application controls what is actually allowed to happen.
From one agent to a multi-agent commerce assistant
The website builder raised a much more interesting question for me.
If an AI agent can operate the website builder, why should it only operate the website builder?
A seller already has products, orders, customers, analytics, discounts, payments, websites and messages inside Atlas.
Normally they have to navigate between all of those interfaces themselves.
I've been extending the AI work toward a multi-agent commerce assistant inspired by products such as Shopify Sidekick.
Instead of treating the LLM as a chatbot, the idea is to give specialized agents controlled tools for different parts of the platform.
For example:
Merchant
│
▼
LLM / Router
│
┌──────────────┼──────────────┐
│ │ │
▼ ▼ ▼
Storefront Product Analytics
Agent Agent Agent
│ │ │
tools tools tools
│ │ │
└──────────────┼──────────────┘
▼
Atlas Services
An agent represents responsibility for a domain.
A tool represents something that agent can actually do.
For example, a storefront agent could have tools for retrieving a website, adding a page, changing a section or publishing the site.
A product agent could retrieve products, update them or inspect inventory.
An analytics agent could retrieve sales and behavioural information.
This lets a request eventually cross several systems.
A merchant could ask:
Which products haven't been selling well? Put them on a 15% discount and add a sale section to my homepage.
That request could require analytics, promotions and the storefront builder.
The interesting problem becomes coordinating those capabilities rather than simply generating a text response.
I'm deliberately keeping the LLM away from unrestricted database access.
Agents should operate through explicit tools backed by the same services the rest of Atlas uses.
The AI becomes another interface into the platform, not a parallel implementation of its business logic.
This part of Atlas is still something I'm actively experimenting with and expanding.
Shopify integration experiment
I also built a standalone Shopify app simulator inside the project.
I wanted to understand more of what actually happens when a third-party commerce application integrates with a platform such as Shopify.
The simulator implements the major pieces of that lifecycle:
Install
↓
OAuth authorization
↓
OAuth callback
↓
Session
↓
Embedded admin application
↓
Storefront extension
↓
Webhooks
It includes HMAC and state verification, mock Admin API functionality, an embedded application flow, storefront extensions and webhook simulation.
The runtime itself is intentionally in-memory because this part of Atlas is an integration experiment rather than a production Shopify application.
OAuth
Atlas also contains a minimal OAuth 2.0 implementation.
It supports an authorization-code flow where applications can request authorization, receive a temporary code and exchange it for access and refresh tokens.
There is also a user-info endpoint for authenticated applications.
I built this separately because I wanted to understand OAuth below the level of simply installing an authentication library.
Infrastructure
Eventually the number of applications became large enough that running and deploying Atlas became a project of its own.
The repository is a pnpm/Turborepo monorepo containing the frontends, backend services and shared packages.
For local infrastructure I use Docker Compose.
The development environment can bring up services such as:
PostgreSQL
Redis
Zookeeper
Kafka
Go chat service
Chat frontend
There is also a production Compose configuration for running the broader platform.
Kubernetes
I created Kubernetes manifests using Kustomize for the platform.
The configuration includes deployments for the major backend services and frontends along with infrastructure such as PostgreSQL, Redis, Zookeeper and Kafka.
Ingress rules route different hosts to the appropriate applications.
For example, the architecture can expose separate hosts for:
API
customer application
seller application
admin application
chat application
The Kubernetes setup is primarily part of my infrastructure experimentation rather than something I would describe as a complete enterprise production environment.
Terraform and AWS
I also created Terraform infrastructure for running Atlas on AWS.
The current baseline provisions a VPC with public and private subnets along with an EKS cluster and managed node group.
The default development region is ap-south-1.
The Terraform setup is intentionally a baseline rather than a finished production landing zone.
Things such as remote state, stronger IAM separation and a complete observability stack are still areas I would add before treating it as production infrastructure.
I prefer documenting that rather than pretending every part of a personal project is production-perfect.
CI/CD
Atlas has CI/CD implementations using both GitHub Actions and Jenkins.
The GitHub Actions pipeline can detect which services changed so that a modification to one application doesn't automatically require rebuilding every container in the monorepo.
The general pipeline is:
Validate infrastructure
↓
Detect changed services
↓
Build affected backend/frontend images
↓
Generate Prisma client where required
↓
Push images
↓
Deploy
I also created an equivalent Jenkins pipeline to experiment with another CI/CD environment.
Load testing
I added k6 tests because once I had an API gateway and several backend services, I wanted some way to test the system under more than a single browser session.
The test suite includes:
Smoke tests for basic availability.
Gateway ramp tests that gradually increase concurrent virtual users.
Checkout spike tests that simulate sudden traffic against order functionality.
Browser tests that navigate through the customer, seller and admin interfaces.
I defined latency and failure-rate thresholds for these tests rather than simply generating traffic and looking at whether the application crashed.
Shared packages and monorepo
With this many applications, duplicating everything between projects quickly becomes painful.
The monorepo therefore contains shared packages for things such as:
- database access
- authentication middleware
- error handling
- UI components
- Redis
- Kafka
- logging
- ImageKit
- TypeScript configuration
- ESLint configuration
The frontend applications share a shadcn/Radix-based component system.
Backend services share common error types and authentication middleware.
Kafka and Redis clients also live in shared packages rather than each service creating its own slightly different implementation.
Technologies
Atlas ended up touching a much wider stack than I originally expected.
Frontend
Next.js
React
TypeScript
Tailwind CSS
shadcn/ui
Radix UI
Zustand
React Query
React Hook Form
React DnD
Recharts
Backend
Node.js
Express
Go
REST APIs
WebSockets
JWT
OAuth 2.0
Data
MongoDB
PostgreSQL
Prisma
Redis
Event-driven systems
Apache Kafka
KafkaJS
Payments
Stripe
Stripe Connect
PaymentIntents
Webhooks
AI / ML
OpenAI
Structured LLM outputs
AI agents
Multi-agent experimentation
TensorFlow.js
Recommendation systems
PyTorch experiments
RAG experiments
Infrastructure
Docker
Docker Compose
Kubernetes
Kustomize
Terraform
AWS EKS
GitHub Actions
Jenkins
k6
What I learned building it
Atlas Commerce is probably less interesting to me as an "ecommerce clone" than as a place where I could connect concepts that are usually learned independently.
Building a React storefront is one problem.
Building a payment API is another.
Using Kafka is another.
Training a recommendation model is another.
Building a WebSocket server is another.
Running containers through Kubernetes is another.
Giving an LLM tools and letting it interact with an application is another.
Atlas gave me one system where all of those things could actually interact.
A product view can start in a React component, become an event, travel through Kafka, become analytics data and later influence recommendations.
A Stripe webhook can become an order, change inventory, update analytics and create a notification.
A WebSocket message can be delivered immediately while Kafka handles persistence asynchronously.
A seller can modify a structured storefront manually through React DnD or ask an LLM to generate the operations for them.
A custom domain can resolve to a seller's published website.
And the agent work I'm doing now can sit above those existing capabilities and start treating the entire commerce platform as a collection of tools.
That's really what Atlas Commerce became for me.
It started as:
"I'm going to build an ecommerce platform."
It gradually turned into:
"How much of a modern software platform can I understand by actually building the pieces myself?"
And I'm still building it.