Back to HomeCase Study

Building a Multi-Tenant SaaS Platform from Scratch

March 15, 20268 min read
Next.jsSupabaseMulti-TenantSaaSTypeScript

The Challenge

When I set out to build ChoGiaKiem.vn, the goal was ambitious: create a multi-tenant marketplace platform where each vendor gets their own storefront, subdomain, POS system, and business tools — all from a single codebase.

The platform needed to handle:

Multi-vendor isolation — each vendor's data completely separated
Auto subdomain routing — vendor1.chogiakiem.vn, vendor2.chogiakiem.vn
Full POS system with barcode scanning and receipt printing
Real-time inventory tracking across multiple warehouses
E-invoicing integration with the Vietnamese tax authority (VNPT)
HR dashboard — payroll, attendance, leave management

Architecture Decisions

Why Next.js + Supabase?

I chose Next.js 15 App Router for its hybrid rendering model — most dashboard pages are client-rendered for interactivity, while public storefronts use SSR for SEO. Supabase (PostgreSQL) was the natural choice for its Row-Level Security (RLS), real-time subscriptions, and generous free tier during development.

Multi-Tenant Strategy: Shared DB, RLS Isolation

Instead of separate databases per tenant, I used a shared database with RLS policies. Every table includes a vendor_id column, and Supabase RLS ensures vendors can only see their own data.

-- Example RLS policy
CREATE POLICY "Vendors see own products" ON products
  FOR ALL USING (vendor_id = auth.jwt() ->> 'vendor_id');

This approach keeps infrastructure costs low while maintaining strict data isolation.

Subdomain Routing

Next.js middleware handles subdomain detection, resolving vendorname.chogiakiem.vn to the correct vendor context before any page renders.

Key Technical Achievements

MetricValue
API Routes630+
React Components397
Database Tables50+
App Modules15+

The POS System

The POS module was the most complex — it needed to:

1.Scan barcodes via camera or USB scanner
2.Calculate tax, discounts, and loyalty points in real-time
3.Print thermal receipts (58mm/80mm)
4.Work offline with local state sync

I built a service worker that caches critical POS data locally, so cashiers can continue selling even during network interruptions.

E-Invoicing Integration

Vietnam's tax authority requires electronic invoicing (hóa đơn điện tử). I built a queue-based system that:

1.Generates invoices in the required XML format
2.Signs with digital certificates
3.Submits to VNPT's API
4.Stores the tax authority's response code

Results

Platform serves multiple active vendors with complete business operations
Zero data leaks between tenants — verified with penetration testing
Sub-second page loads on dashboard — Lighthouse performance score 90+
30% reduction in vendor onboarding time compared to manual setup

Lessons Learned

1.Start with RLS from day one — retrofitting security policies is painful
2.Invest in TypeScript types early — with 630+ API routes, type safety saved me countless hours
3.Build admin tools first — a good admin panel accelerates everything else
4.Test with real vendors — real-world usage revealed edge cases no unit test would catch

The platform continues to grow, and the architecture has proven scalable. Each new vendor can be onboarded in under 5 minutes, with full POS, inventory, and accounting ready to go.

E

Eric Phan

Full-Stack Developer & Digital Transformation Consultant. Building production SaaS platforms, government digital services, and AI-powered tools.