A Kubernetes-native platform that automatically provisions fully functional MedusaJS e-commerce stores on demand. Users interact with a React dashboard to create, monitor, and delete isolated stores — each running in its own namespace with dedicated PostgreSQL, Redis, Medusa backend, and Next.js storefront.
store-platform.mp4
┌──────────────────────────────────────────────────────────────┐
│ k3d / k3s Cluster │
│ │
│ ┌─── store-platform namespace ───────────────────────────┐ │
│ │ Dashboard (React) │ Platform API (Go) │ PostgreSQL│ │
│ └────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─── argo namespace ────────┼───────────────────────────┐ │
│ │ Argo Workflow Engine (provision / delete DAGs) │ │
│ └───────────────────────────┼───────────────────────────┘ │
│ │ │
│ ┌─── store-{name} namespace ┼───────────────────────────┐ │
│ │ MedusaJS Backend │ Storefront │ PostgreSQL │ Redis│ │
│ └────────────────────────────────────────────────────────┘ │
│ │
│ NGINX Ingress Controller (wildcard domains via nip.io) │
└──────────────────────────────────────────────────────────────┘
| Layer | Technology |
|---|---|
| Cluster | k3d (local) / k3s (production) |
| Ingress | NGINX Ingress Controller |
| Workflow Engine | Argo Workflows v4.0.0 |
| Package Manager | Helm v3 |
| E-commerce | MedusaJS v2 + Next.js 15 storefront |
| Platform API | Go 1.25 + Gin + GORM |
| Dashboard | React + TypeScript + Vite |
| DNS | nip.io (local) / real domain (prod) |
- Docker (with BuildKit enabled)
- k3d v5+
- kubectl
- Helm v3
- ~8 GB RAM available for the cluster
make allThis will:
- Create a k3d cluster with a local Docker registry
- Build all 5 Docker images (medusa-backend, medusa-storefront, store-provisioner, platform-api, dashboard)
- Push images to the local registry
- Install Argo Workflows + RBAC + WorkflowTemplates
- Deploy the platform (API + Dashboard + PostgreSQL)
make cluster-up # Create k3d cluster + registry + NGINX Ingress
make build # Build all Docker images
make push # Push to local registry (localhost:5000)
make deploy-argo # Install Argo Workflows + apply WorkflowTemplates
make deploy-platform # Deploy platform Helm chart| Service | URL |
|---|---|
| Dashboard | http://platform.local.127.0.0.1.nip.io |
| Platform API | http://api.local.127.0.0.1.nip.io |
| Argo UI | kubectl -n argo port-forward svc/argo-server 2746:2746 → https://localhost:2746 |
No /etc/hosts changes needed — nip.io resolves *.127.0.0.1.nip.io to 127.0.0.1 automatically.
- Open the Dashboard at http://platform.local.127.0.0.1.nip.io
- Click "Create New Store"
- Enter a store name (e.g.,
demo) and select MedusaJS - Click Create Store
- Watch the provisioning progress — takes ~5 minutes on first run
Once status shows Ready, click the Storefront link or navigate to:
http://demo-shop.local.127.0.0.1.nip.io
- Browse seeded products on the storefront
- Click a product → Add to Cart
- Go to Cart → Checkout
- Fill in shipping details and complete checkout (test/COD)
Option A — Admin UI:
- Navigate to
http://demo.local.127.0.0.1.nip.io/app - Log in with the admin credentials shown in the Dashboard detail page
- Go to Orders → verify the order is listed
Option B — API:
# Authenticate
TOKEN=$(curl -s -X POST http://demo.local.127.0.0.1.nip.io/auth/user/emailpass \
-H "Content-Type: application/json" \
-d '{"email":"admin@store.local","password":"<admin-password>"}' | jq -r .token)
# List orders
curl -s http://demo.local.127.0.0.1.nip.io/admin/orders \
-H "Authorization: Bearer $TOKEN" | jq .- In the Dashboard, click the trash icon next to the store
- Confirm deletion
- All resources (namespace, PVCs, deployments, secrets) are cleaned up automatically
The same Helm charts work on a production VPS. Only Helm values change.
curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--disable=traefik" sh -
export KUBECONFIG=/etc/rancher/k3s/k3s.yamlkubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.12.0/deploy/static/provider/baremetal/deploy.yamlREGISTRY=ghcr.io/youruser # or Docker Hub, ECR, etc.
for img in medusa-backend medusa-storefront store-provisioner platform-api dashboard; do
docker tag localhost:5000/$img:latest $REGISTRY/$img:latest
docker push $REGISTRY/$img:latest
donekubectl create namespace argo
kubectl apply -n argo -f https://github.com/argoproj/argo-workflows/releases/download/v4.0.0/quick-start-minimal.yaml
# Apply RBAC and WorkflowTemplates
kubectl apply -f helm/argo-workflows/ # update registry-prefix defaults firstDOMAIN=yourdomain.com
REGISTRY=ghcr.io/youruser
helm upgrade --install platform helm/platform \
--namespace store-platform --create-namespace \
-f helm/platform/values-prod.yaml \
--set domainSuffix=$DOMAIN \
--set registryPrefix=$REGISTRY| Setting | Local (values-local.yaml) |
Production (values-prod.yaml) |
|---|---|---|
| Domain | local.127.0.0.1.nip.io |
yourdomain.com |
| Registry | k3d-store-registry:5000 |
ghcr.io/youruser |
| TLS | None | cert-manager + Let's Encrypt |
| API replicas | 1 | 2 |
| PostgreSQL storage | 256Mi | 5–10Gi |
| Medusa resources | 100m CPU / 256Mi RAM | 500m CPU / 1Gi RAM |
| Medusa worker mode | shared |
server |
| Cookie security | COOKIE_SECURE=false (HTTP) |
COOKIE_SECURE=true (HTTPS) |
# Install cert-manager
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.16.0/cert-manager.yaml
# Create ClusterIssuer
cat <<EOF | kubectl apply -f -
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: you@example.com
privateKeySecretRef:
name: letsencrypt-prod
solvers:
- http01:
ingress:
class: nginx
EOFThe values-prod.yaml files already include cert-manager.io/cluster-issuer: letsencrypt-prod annotations.
# Rebuild and push updated images
make build push
# Upgrade the platform
helm upgrade platform helm/platform -n store-platform -f helm/platform/values-local.yaml
# Upgrade a specific store's chart
helm upgrade store-demo helm/store -n store-demo -f helm/store/values-local.yaml# View release history
helm history platform -n store-platform
helm history store-demo -n store-demo
# Rollback to a previous revision
helm rollback platform 1 -n store-platform
helm rollback store-demo 1 -n store-demoHelm tracks every release revision. Rollback restores the previous values and manifests atomically.
- Argo Workflows for orchestration: Provides DAG dependencies, per-step visibility, retry logic, and timeout handling. More robust than Kubernetes Jobs for multi-step provisioning.
- Namespace-per-store isolation: Each store gets its own namespace with dedicated resources,
ResourceQuota,LimitRange, andNetworkPolicy. Clean deletion via namespace removal. - Helm for deployment: Enables
upgrade --installidempotency, value-based environment profiles, androllbackfor recovery. - Placeholder URL injection: Builds a single Docker image that works in any environment by replacing URL placeholders at container startup.
- Namespace creation: Uses
kubectl create --dry-run=client | kubectl apply— safe to retry. - Helm install: Uses
helm upgrade --install— idempotent; re-running converges to desired state. - Background sync worker: Polls Argo every 10s and maps workflow phases to store statuses. If the API or workflow restarts, status reconciles automatically.
- Argo retry strategy: The
wait-for-medusastep hasretryStrategy.limit: 3for transient failures. - Failure reporting: Failed workflow steps surface error messages in the dashboard.
Store deletion is a 3-step DAG:
helm uninstall— removes all Helm-tracked resourcescleanup-resources— deletes remaining PVCs, secrets, configmaps, ingressesdelete-namespace— removes the namespace and any orphaned resources
- No hardcoded secrets: All passwords/keys generated at runtime via
openssl rand - RBAC: Platform API and Argo workflows have scoped ClusterRoles with only required permissions
- securityContext: Containers run as non-root with read-only root filesystems where possible
- ResourceQuota + LimitRange: Per-store namespace limits prevent resource exhaustion
- NetworkPolicy: Default-deny ingress/egress with explicit allows per store namespace
- Rate limiting: API rate-limits store creation requests
- DNS: Replace
nip.iowith real domain; configure DNS wildcard (*.yourdomain.com) - TLS: Enable cert-manager with Let's Encrypt; set
COOKIE_SECURE=true - Storage: Increase PVC sizes; use a proper StorageClass (e.g.,
longhorn,ebs-gp3) - Registry: Push to a real container registry
- Resources: Production CPU/memory limits via
values-prod.yaml - Secrets: Use external secrets management (e.g., Vault, Sealed Secrets) for sensitive values
├── Makefile # Build/deploy automation
├── README.md # This file
├── IMPLEMENTATION.md # Detailed implementation document
├── scripts/
│ ├── setup-cluster.sh # Create k3d cluster + registry
│ ├── setup-argo.sh # Install Argo Workflows + RBAC
│ ├── teardown-cluster.sh # Delete cluster
│ └── build-images.sh # Build all Docker images
├── docker/
│ ├── medusa-backend/ # MedusaJS v2 backend image
│ ├── medusa-storefront/ # Next.js storefront image
│ └── store-provisioner/ # Helm/kubectl tooling image
├── helm/
│ ├── platform/ # Platform Helm chart (API, Dashboard, DB)
│ ├── store/ # Per-store Helm chart (Medusa, Storefront, DB, Redis)
│ └── argo-workflows/ # WorkflowTemplates (provision + delete)
├── platform-api/ # Go backend (REST API + Argo integration)
└── dashboard/ # React frontend (store management UI)
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/health |
Health check |
GET |
/api/stores |
List all stores |
POST |
/api/stores |
Create a new store |
GET |
/api/stores/:id |
Get store details |
DELETE |
/api/stores/:id |
Delete a store |
GET |
/api/stores/:id/logs |
Get provisioning/deletion workflow steps |
make clean # Removes platform Helm release + deletes k3d cluster + registry