Skip to content
Enterprise SaaS Product

Multi-Tenant ERP Platform

A microservices ERP built from day one for tenant isolation, independent deployment, and honest engineering scale.

Year 2025
Duration 14 months
Team 4 engineers
Status Live · early customers

A look at the product.

We set out to build a modern ERP that wouldn't force small and mid-sized businesses into the classic "monolith or nothing" trap. Off-the-shelf systems like SAP or Odoo either carried enterprise licensing costs or required months of customization to map onto real-world workflows.

Our thesis was simple: break the problem into small, independently deployable services from day one — even when every instinct as a small team says to ship a modular monolith and extract later. Fourteen months in, that commitment has shaped every technical and operational decision we've made since.

Challenge

Retail, services, and distribution companies all need a CRM, an accounting module, and an inventory system — but the rules, fields, and workflows diverge sharply. A traditional monolith handles that divergence by piling on configuration flags until the codebase becomes a museum of special cases.

We had harder constraints: complete data isolation per tenant (no shared schemas), independent deploy cadence per module (CRM ships without blocking Inventory), sub-second cross-service consistency, and a single coherent UI despite a fragmented backend — all running on infrastructure an SMB could actually afford.

Approach

We chose polyrepo over monorepo for deployment independence. 41 repositories in total: 16 backend services, 10 Vue 3 microfrontends, a shared UI library, a JWT authentication SDK, and infrastructure modules. Each backend service is a focused Laravel app with its own PostgreSQL schema.

Services communicate exclusively through NATS JetStream — no direct HTTP calls between services. Synchronous requests from the browser hit a Kong API gateway that routes to the appropriate service and handles JWT validation. The UI is stitched at runtime using Rsbuild Module Federation, so CRM and Inventory can ship new features independently without rebuilding the shell.

Tenant isolation is enforced at the database level via PostgreSQL row-level security, provisioned per tenant by CloudNativePG. A tenant ID rides on every NATS message header. If a service forgets to scope a query, RLS catches it — not human vigilance.

We committed to microservices from day one — even though every instinct on a small team says to ship a monolith and extract later.

Key capabilities shipped.

  • 16 focused Laravel services covering CRM, Accounting, Inventory, HR, Workflow, Ticketing, Reporting and more
  • Tenant-isolated PostgreSQL schemas with row-level security enforcement
  • NATS JetStream event bus with guaranteed delivery between services
  • 10 Vue 3 microfrontends federated at runtime — ship independently
  • Helm-based Kubernetes deployments on RKE2 clusters
  • Shared JWT auth SDK consumed by every service and microfrontend
  • Full observability stack: Prometheus metrics, Loki logs, Tempo traces
  • Automated tenant provisioning with dedicated database per customer

Grounded outcomes, measured in production.

Deploy Time
2–3 min
Git push to production per service
p95 Latency
< 180ms
Under realistic load tests
Tenant Leaks
Zero
6 months of pen-testing, no cross-tenant data access
Scale
41 repos
Clean boundaries, clear ownership per service

The platform supports unlimited tenants with zero cross-contamination. Each service deploys independently via Helm charts on RKE2 Kubernetes, with full observability through Prometheus, Grafana, Loki, and Tempo. Average deployment time: under 3 minutes per service.

Technologies used, grouped by role.

Backend
Laravel 12 PostgreSQL NATS JetStream Valkey CloudNativePG
Frontend
Vue 3 TypeScript Rsbuild Module Federation
Infrastructure & Observability
Kubernetes (RKE2) Helm Prometheus Grafana Loki Tempo