An open-source, self-hostable multi-tenant application platform — that happens to ship an ERP as its first-party app suite.
Project status: pre-release, single maintainer. The architecture below is real and the code exists, but there are no tagged releases, no published container images, and the extracted repositories cannot yet install standalone — the build is still the
ERPSysmonorepo.ROADMAP.mdsays exactly what is and is not finished, andGOVERNANCE.mdsays who maintains it. Please read both before deploying this anywhere that matters.
| If you are… | Go to |
|---|---|
| Evaluating UniERP | What makes it different |
| Deploying it | unierp-infra — compose, Kubernetes, runbooks |
| Building on it | unierp-extension-api — the public contract |
| Contributing | CONTRIBUTING.md — it starts by telling you which of the repositories below your change belongs in |
| Stuck, or unsure where to ask | SUPPORT.md |
| Wondering how finished this is | ROADMAP.md — read this before you deploy it |
| Understanding the design | ARCHITECTURE.md here, then PLATFORM_ARCHITECTURE.md for the full specification |
Most ERPs are a product. Most app platforms are not self-hostable. UniERP is deliberately both, and the intersection is close to empty:
- Tenant isolation enforced by the database, not by application code. Every
tenant table carries a row-level-security policy with
FORCE, and the application role isNOBYPASSRLS. It is explainable to an auditor in one sentence, and it is proven by a two-tenant test per table. - Extensions run in a real sandbox. Third-party code executes in a V8 isolate
with no ambient authority — no
process, norequire, no filesystem — under metered CPU, memory, query and egress budgets, with a kill switch. - Local-first AI. Ollama and pgvector, so nothing leaves your infrastructure. For healthcare, government and EU-regulated buyers, sending ERP data to a vendor's model is often disqualifying.
- One backend, not forty-five microservices. Finance, inventory and sales write to each other constantly; splitting them would mean a distributed transaction on the most correctness-critical paths in the system.
UniERP is a layered polyrepo. A repository may depend only on published artifacts of a strictly lower layer — never sideways, never upward. Each repo's CI asserts this mechanically, so a UI component cannot import a database service. Not "shouldn't": cannot.
| Repository | What it is |
|---|---|
unierp-contracts |
Every API shape and event schema. Depends on nothing — that is what keeps the whole graph acyclic. |
| Repository | What it is |
|---|---|
unierp-kernel |
Tenancy context, policy engine, audit, outbox, idempotency |
unierp-design-system |
Tokens → components → charts → grid → forms. One package, subpath exports |
unierp-sdk |
The typed client third parties install. Generated from L0 |
unierp-shared · unierp-auth · unierp-service-kit · unierp-config |
Shared types, session primitives, service scaffolding, build config |
| Repository | What it is |
|---|---|
unierp-data |
Prisma schema, migrations, RLS policies, isolation-test generator |
unierp-framework |
The schema-driven page runtime. First-party and customer modules render through the same runtime |
unierp-extension-api |
The public contract partners compile against. 3-year support, 12-month deprecation |
unierp-sandbox |
The V8 isolate that runs extension and Studio code |
| Repository | What it is |
|---|---|
unierp-api |
The modular monolith. 45 business modules, two routers, one deployable |
unierp-idp |
Identity provider. A separate realm per plane, so no customer identity can obtain a control-plane token |
| Repository | What it is |
|---|---|
unierp-web |
Tenant Admin Portal + Application Layer — what customers use |
unierp-console |
Platform Admin Console. Separate origin, separate IdP realm, restricted ingress |
unierp-developer |
The developer platform: App Studio, the workflow/form/report builders, and tenant CMS |
unierp-corporate-website |
Marketing, docs, pricing, status |
unierp-corporate-site-template |
Starter template a tenant's public website is generated from |
| Repository | What it is |
|---|---|
unierp-mobile |
Flutter app — different language, toolchain and release cadence |
| Repository | What it is |
|---|---|
unierp-extensions |
First-party verticals: healthcare, education, real estate, field service. Depends on nothing but the public API — that constraint is the proof the API is real |
| Repository | What it is |
|---|---|
unierp-infra |
Compose, Kubernetes, control-plane ingress, load tests, runbooks, the package registry |
unierp-workspace |
Release-train manifest, shared CI gates, the federated ratchet |
The layered repositories above are the architecture. The build is still
ERPSys, the development monorepo the
polyrepo was extracted from, and that is deliberate rather than unfinished:
PLATFORM_ARCHITECTURE.md
§ 14 rule 4 keeps the monorepo buildable at every extraction tag until each
consumer has switched to a published artifact. The extracted L3/L4 repositories
still declare @unerp/* as workspace:*, so they cannot yet install
standalone — see § 14.1 for what unblocks that, and ROADMAP.md
for where that migration currently stands.
git clone https://github.com/kannan19302/ERPSys
cd ERPSys
pnpm install
pnpm devpnpm dev starts PostgreSQL, Redis, MinIO and the package registry in Docker
and runs the API, IdP and web app natively — the same Next.js middleware compile
takes ~1 second natively and ~960 seconds in a bind-mounted container on
Windows, so the datastores get Docker and the applications do not.
| Web | http://localhost:3000 |
| API | http://localhost:3001/api/v1 · Swagger at /swagger |
| IdP | http://localhost:3005 |
Then prove it actually works, rather than assuming green gates mean a working product:
pnpm smokeThat walks register → log in → read a tenant's data over HTTP against the
running services and fails loudly. It exists because every gate in pnpm verify
was green at a point when the application did not boot.
Shared services alone, without the monorepo, come from
unierp-infra:
docker compose -f docker-compose.dev.yml up -d.
Fifteen-plus repositories build three deployables. Repository topology and runtime topology are separate decisions:
PLANE 0 public marketing · docs · tenant signup · published tenant sites
PLANE 1 control admin.unierp.internal — provider-only, MFA, restricted ingress
PLANE 2 tenant admin app.unierp.com/settings
PLANE 3 application the 45 business modules
PLANE 4 developer Studio, workflow/form/report builders, extension runtime
console ─┐ ┌─ web · mobile
▼ ▼
/api/platform/v1 /api/v1
ControlPlaneGuard TenantGuard + RLS
└────────┬───────────┘
▼
unierp-api (one deployable)
│
PostgreSQL 16 (RLS) · Redis · MinIO · Ollama · outbox
Copyright (C) 2026 UniERP contributors.
GNU Affero General Public License v3.0. Self-hostable in full, with no proprietary runtime dependency — there is no open-core edition holding back tenant isolation, the sandbox or the audit trail.
The Affero clause is the part worth reading before you build on it: if you run a
modified UniERP as a network service, you owe your users the modified source.
Running it unmodified, or modifying it privately without offering it as a
service, carries no such obligation. Extensions that only compile against
unierp-extension-api
are separate works and are yours to licence as you choose.