Production-grade microservices platform demonstrating enterprise architecture patterns with Nuxt 4 + NestJS.
Built by Faiz Khairi to showcase scalable system design, message-driven architecture, and modern DevOps practices.
8-Service Microservices Platform:
Frontend (Nuxt 4)
↓
API Gateway (NestJS) — Routing, Auth, Rate Limiting, Circuit Breaker
↓
┌──┴──┬──────┬──────────┬──────────┬──────────┐
↓ ↓ ↓ ↓ ↓ ↓
Auth User Task Notification Search Queue Worker
:4001 :4002 :4003 :4004 :4005 (Background)
↓ ↓ ↓ ↑ Kafka ↑ ↑
Auth User Task ──────────────────
DB DB DB Kafka Event Bus
(task.created / updated / deleted)
| Service | Port | Responsibility |
|---|---|---|
| API Gateway | 4000 | Entry point, JWT validation, rate limiting, circuit breaker |
| Auth Service | 4001 | JWT authentication, refresh tokens, bcrypt password hashing |
| User Service | 4002 | User profiles with Redis cache-aside (60s TTL) |
| Task Service | 4003 | Task CRUD + BullMQ queue + Kafka event publishing |
| Notification Service | 4004 | Email + in-app notifications, Kafka consumer, WebSocket push (Socket.IO) |
| Search Service | 4005 | Elasticsearch full-text search (Kafka consumer) |
| Queue Worker | — | BullMQ background job processor |
| Component | Purpose |
|---|---|
| 4x PostgreSQL 16 | One database per service (microservices pattern) |
| Redis 7 | BullMQ job queue + cache-aside reads |
| Kafka + Zookeeper | Event streaming bus (task.events topic) |
| Elasticsearch 8 | Full-text search index, synced via Kafka |
| Prometheus + Grafana | Metrics scraping and dashboards |
| Mailpit | Email testing in development |
| Docker Compose | Orchestrating 17 containers |
| Kubernetes manifests | Production deployment (k8s/ + Helm chart) |
- Docker 20.10+
- Docker Compose 2.0+
- Node.js 20+ (for local development)
- pnpm 8+ (optional)
# Clone the repository
git clone https://github.com/faizkhairi/microservices-demo.git
cd microservices-demo
# Copy environment variables
cp .env.example .env
# Start all services with Docker Compose
docker compose up --build
# Services will be available at:
# - Frontend: http://localhost:3000
# - API Gateway: http://localhost:4000
# - Mailpit UI: http://localhost:8025 (email testing)First-time setup: Docker will build all 7 services + databases. This takes ~5-10 minutes.
- Nuxt 4 — Vue 3 SSR framework
- Shadcn-vue — Copy-paste UI components
- Tailwind CSS — Utility-first styling
- Pinia — State management
- Axios — HTTP client with JWT interceptor
- NestJS — Enterprise Node.js framework
- Prisma ORM — Type-safe database client
- PostgreSQL 16 — Production-grade relational DB
- Passport + JWT — Authentication strategy
- BullMQ + Redis — Job queue for async processing
- Kafka (KafkaJS) — Event streaming bus between services
- Elasticsearch — Full-text search indexing
- opossum — Circuit breaker for downstream call resilience
- Nodemailer — SMTP email sending
- Docker — Containerization
- Docker Compose — Multi-container orchestration (17 containers)
- Kubernetes + Helm — Production deployment manifests and chart
- Prometheus + Grafana — Metrics scraping and dashboards
- GitHub Actions — CI/CD pipeline
- Mailpit — Email testing (catches all emails in dev)
Each service can be run independently for development:
# Auth Service
cd services/auth-service
npm install
npm run dev # Runs on port 4001
# User Service
cd services/user-service
npm install
npm run dev # Runs on port 4002
# Frontend
cd frontend
npm install
npm run dev # Runs on port 3000Docker Compose: migrations run automatically on container start (prisma migrate deploy in each service Dockerfile). A fresh docker compose up --build applies all schemas with no manual steps.
For local development (services run on host, databases in Docker):
# Auth Service
cd services/auth-service && npm install
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/auth_db" npx prisma migrate dev
# User Service
cd services/user-service && npm install
DATABASE_URL="postgresql://postgres:postgres@localhost:5433/user_db" npx prisma migrate dev
# Task Service
cd services/task-service && npm install
DATABASE_URL="postgresql://postgres:postgres@localhost:5434/task_db" npx prisma migrate dev
# Notification Service
cd services/notification-service && npm install
DATABASE_URL="postgresql://postgres:postgres@localhost:5435/notification_db" npx prisma migrate dev# Run all tests
npm test
# Run tests for specific service
cd services/auth-service
npm test
# E2E tests (Playwright)
cd frontend
npm run test:e2e- Architecture Design — Detailed system design
- API Gateway — Routing, auth, circuit breaker
- Auth Service — JWT authentication
- User Service — Profile management + Redis cache
- Task Service — Task CRUD + BullMQ + Kafka events
- Notification Service — Email + in-app + Kafka consumer
- Search Service — Elasticsearch full-text search
- Queue Worker — Background jobs
- ✅ Database per service — Each service owns its data (no shared DB)
- ✅ API Gateway pattern — Centralized routing, auth, rate limiting, circuit breaking
- ✅ Service decomposition — Clear domain boundaries (auth, users, tasks, notifications, search)
- ✅ BullMQ + Redis — Async job processing with retry/DLQ semantics
- ✅ Kafka event bus —
task.created/task.updated/task.deletedtopic consumed by Notification and Search services independently - ✅ Real-time notifications — Socket.IO WebSocket gateway pushes in-app alerts on Kafka events
- ✅ Decoupled services — Task Service publishes events; it never calls Notification or Search directly
- ✅ Elasticsearch full-text search — Search Service indexes tasks via Kafka consumer, exposes
GET /search?q= - ✅ Redis cache-aside — User profile reads (60s TTL) and task list reads (30s TTL), invalidated on write
- ✅ Circuit breaker (opossum) — API Gateway trips per-downstream-service circuits on repeated failures, exposes
GET /health/circuit - ✅ Health checks — Every service has a
/healthendpoint
- ✅ JWT authentication — Stateless auth with 15-minute access tokens
- ✅ Refresh tokens — 7-day expiration for secure re-authentication
- ✅ Bcrypt password hashing — Industry-standard (salt rounds: 10)
- ✅ Rate limiting — 100 req/min per IP at API Gateway
- ✅ Owner-only access — Users can only access their own data
- ✅ Prometheus metrics —
/metricsendpoint on API Gateway (request rate, latency histograms) - ✅ Grafana dashboards — Auto-provisioned datasource + dashboard on container start
- ✅ Structured logging — Correlation-friendly service-scoped loggers
- ✅ Docker Compose — One-command local environment (17 containers)
- ✅ Kubernetes manifests — Deployments, Services, ConfigMap, Secret template, Ingress, HPA in
k8s/ - ✅ Helm chart — Templated multi-service deploy in
helm/microservices-demo/ - ✅ CI/CD pipeline — GitHub Actions builds all services
docker compose upOption 1: Docker Compose on VPS
# On server (Ubuntu/Debian)
docker compose -f docker-compose.prod.yml up -d
# Services use production environment variables
# PostgreSQL, Redis, and services run in containersOption 2: Kubernetes (EKS/GKE/AKS)
# Dry-run validation (no cluster required)
kubectl apply --dry-run=client -f k8s/
# Deploy to a real cluster
kubectl apply -f k8s/namespace.yaml
kubectl apply -f k8s/
# Or via Helm
helm lint helm/microservices-demo/
helm install microservices-demo helm/microservices-demo/ -n microservices-demo --create-namespace
# Each service runs as a separate Deployment + Service
# HPA autoscales api-gateway on CPU/memory (70%/80% thresholds)
# RDS for PostgreSQL, ElastiCache for Redis in productionFrontend Deployment:
- Netlify (recommended) — Nuxt SSR with Nitro
- Vercel — Alternative for Next.js-like SSR
- Self-hosted with Nginx
1. User submits form (frontend)
↓
2. POST /auth/register → API Gateway
↓
3. API Gateway → Auth Service
↓
4. Auth Service creates user in auth_db
↓
5. Returns success → frontend redirects to login
1. User creates task (frontend)
↓
2. POST /tasks → API Gateway (validates JWT)
↓
3. API Gateway → Task Service
↓
4. Task Service:
- Saves task to task_db
- Publishes "task.created" job to BullMQ
↓
5. Queue Worker (background):
- Picks up job from Redis
- Calls Notification Service
↓
6. Notification Service:
- Saves notification to notification_db
- Publishes live update via Socket.IO (`/notifications` namespace)
- Sends email via Mailpit (when email channel is used)
1. Frontend opens Socket.IO connection to Notification Service
- Namespace: /notifications
- Auth: JWT in handshake auth.token
↓
2. Server joins socket to room user:{userId}
↓
3. When Kafka emits task.created / task.updated / task.deleted
- Notification Service persists in-app notification
- Same payload is pushed to connected clients in that user room
Try it locally with examples/websocket-client.html.
| Technology | Reason |
|---|---|
| Nuxt 4 | SSR + Vue 3, production-ready, matches boilerplate |
| NestJS | Enterprise-grade, TypeScript-first, modular architecture |
| PostgreSQL | ACID compliance, production-grade, one DB per service |
| Prisma | Type-safe ORM, auto-migrations, excellent DX |
| BullMQ | Industry-standard Node.js job queue, Redis-backed |
| Docker | Consistent environments, easy orchestration |
✅ Microservices expertise — Service decomposition, API Gateway, database per service ✅ Message-driven architecture — BullMQ job queues + Kafka event streaming for async processing ✅ Search & caching — Elasticsearch full-text search, Redis cache-aside with invalidation ✅ Resilience patterns — Circuit breaker (opossum) to prevent cascading failures ✅ Observability — Prometheus metrics + Grafana dashboards ✅ Modern stack mastery — Nuxt 4, NestJS, Prisma, PostgreSQL, Redis, Kafka, Elasticsearch ✅ DevOps capabilities — Docker Compose, Kubernetes manifests, Helm chart ✅ Enterprise patterns — JWT auth, rate limiting, structured logging ✅ Scalability — Each service can scale independently, HPA-driven autoscaling
MIT License — See LICENSE for details.
Faiz Khairi
- GitHub: @faizkhairi
- LinkedIn: linkedin.com/in/faizkhairi
- Website: faizkhairi.github.io
If you find this project helpful, please give it a star! ⭐
Built with ❤️ to showcase production-grade microservices architecture.