Role-Based Multi-Tenant SaaS Platform
A multi-tenant e-commerce SaaS with per-seller data isolation, built with Next.js 16, PayloadCMS, and tRPC for end-to-end type safety. In progress.
Learning project (in progress): Built by following a structured tutorial to explore advanced Next.js patterns, multi-tenant architecture, and headless CMS integration.
A multi-tenant e-commerce SaaS where each seller's data and products are isolated through declarative role-based access control. PayloadCMS powers the headless backend and admin panel, Next.js 16 renders the storefronts, and tRPC connects them with end-to-end type safety.
httpOnly cookie server-side, never exposed to JavaScript
Main storefront: category nav, price & tag filters
Tenant storefront: per-seller product listings
Next.js 16 · App Router · TypeScript
PayloadCMS · MongoDB (Mongoose)
tRPC 11 · TanStack Query 5
React Hook Form + Zod · Tailwind + shadcn/ui
Each tenant's data is isolated via PayloadCMS access control hooks, while super-admins retain unrestricted access.
JWT lives in an httpOnly cookie set server-side, protecting against XSS token theft.
TanStack Query's useInfiniteQuery with server-side prefetching for fast first paint.
Compile-time guarantees end-to-end using Payload's auto-generated TypeScript types.
Parent/subcategory nesting powers a multi-level nav and combined tag filtering.
Auto-generated admin UI for products, tenants, users, and media.
The multiTenantPlugin attaches a tenant relationship to scoped collections. PayloadCMS access control hooks then filter queries declaratively, so tenant admins only see their own data, and super-admins see everything. No manual access logic per collection.
The tRPC login mutation invokes Payload's local auth API server-side. The JWT is written to an httpOnly cookie and sent automatically on every request, while remaining unreadable to client JavaScript. queryClient.invalidateQueries refreshes session state on login/logout.
tRPC routers (products, categories, tenants) expose Payload data with full type inference. TanStack Query 5 handles caching, background refetch, and infinite scroll; the first page is server-prefetched.
Designing a single codebase that isolates data per tenant via scoped queries and declarative access control.
Using PayloadCMS as both backend API and admin UI in place of custom dashboards.
tRPC + Payload's generated types keep client and server in lockstep at compile time.
React Hook Form + Zod schemas shared between forms and tRPC input validators.
Server components, route groups, and middleware for SSR data prefetching.
Feature branches with PR-based merges, reviewed by CodeRabbit AI on every change.