Multi-Tenant SaaS Platform
A role-based multi-tenant platform where every query is scoped to a tenant and every route to a role.
- Node.js
- Express
- PostgreSQL
- JWT
- React · Vite
- Tailwind CSS
- Docker Compose
- Roles
- Super admin · Tenant admin · User
- Isolation
- Tenant middleware · per-route RBAC
- Limits
- Plan-based caps on users and projects
Overview
A production-style multi-tenant application: one deployment, many organisations, strict isolation. It is fully containerised — backend, frontend and database — and demonstrated in a recorded walkthrough.
Problem
Multi-tenancy is a correctness problem before it is a scaling problem. A single missing tenant filter leaks one organisation's data to another. Roles add a second axis: what a person can do inside their tenant.
Architecture
- 01Authentication middleware extracts identity from the JWT.
- 02RBAC middleware enforces role permissions per route, with read and write permissions separated.
- 03Tenant middleware scopes every query to the caller's tenant; the super admin is deliberately isolated from tenant-scoped data.
- 04Subscription plan limits (users, projects) are enforced in the API and surfaced clearly in the UI.
Implementation
Three roles
Super Admin: tenants and plans (read-only). Tenant Admin: dashboard, projects, tasks, users within limits. User: read-only dashboard, projects and tasks.
Error handling
Consistent backend errors; a global Axios interceptor handles 401 (session expired) and 403 (unauthorized) with toast notifications.
Zero-step start
Migrations and seeds run automatically on container startup, creating a super admin, a sample tenant and a tenant admin.
Challenges
Isolation everywhere
Enforced by middleware, not by remembering to add a WHERE clause in each controller.
Two axes of permission
Role and tenant are checked independently, in order, on every request.
Technical decisions
Configuration-based plans
No billing UI; plan limits are configuration, keeping the scope focused on isolation and access control.
Super admin without tenant access
The platform operator cannot read tenant data — a deliberate trust boundary.
Result
A clean multi-tenant reference implementation with proper role separation and tenant isolation, ready to run with one command.
Lessons
- 01Put isolation in the middleware layer so it cannot be forgotten.
- 02Separate read and write permissions early — merging them later is painful.
