DEV Community

Cover image for What I Learned Building a Multi-Tenant SaaS as a Final Year Student
Michael Asante
Michael Asante

Posted on

What I Learned Building a Multi-Tenant SaaS as a Final Year Student

By Bigwig |


Most final year CS students build a project that lives on a USB drive, gets presented to a panel, and is never opened again.

Mine is live. It has real businesses on it. Real transactions. Real data.

I'm a final year Networking and Software Systems student at Presbyterian University Ghana (PUG), based in the Kwahu area of the Eastern Region. While preparing for my academic defense, I independently built and deployed StockMaster Ghana — a multi-tenant SaaS POS and business management system serving small and medium businesses in my community.

This is what I learned. Not from a tutorial. From actually doing it.


First, What Is Multi-Tenancy?

Before I get into the lessons, let me explain what I mean by multi-tenant — because it took me a while to really get it.

A single-tenant app is like a house. One family lives there. Everything is built for them.

A multi-tenant app is like an apartment building. Many tenants share the same infrastructure — same roof, same plumbing, same electricity grid — but each tenant has their own private space and can't access anyone else's.

In SaaS terms: one codebase, one database, many businesses — each seeing only their own data.

Single-tenant:    App A → Database A
                  App B → Database B  (separate deployments)

Multi-tenant:     App → Database
                          ├── Tenant A's data
                          ├── Tenant B's data
                          └── Tenant C's data  (one deployment)
Enter fullscreen mode Exit fullscreen mode

Getting this architecture right is where most beginners (myself included, at first) trip up.


The Stack I Chose and Why

  • Frontend: React + Vite
  • Backend/Database: Supabase (PostgreSQL)
  • Auth: Supabase Auth
  • Deployment: Vercel
  • Payments: MTN MoMo API integration (for the Ghanaian market)

I chose this stack for one reason: I could move fast without a dedicated backend server. Supabase gave me a full PostgreSQL database, authentication, Row-Level Security, and real-time subscriptions — all without spinning up a separate API server. For a solo student developer, that's a superpower.


Lesson 1: Row-Level Security Is Not Optional

This was my biggest early mistake.

I launched the first version of StockMaster Ghana without properly enabling Row-Level Security (RLS) on all my Supabase tables. Technically, each business had a tenant_id column — but without RLS enforced at the database level, the only thing keeping Business A from seeing Business B's data was my frontend logic.

Frontend logic can be bypassed. A database policy cannot.

Here's the kind of RLS policy I ended up implementing:

-- Enable RLS on the sales table
ALTER TABLE sales ENABLE ROW LEVEL SECURITY;

-- Each tenant can only see their own sales
CREATE POLICY "Tenants see own sales"
ON sales
FOR ALL
USING (tenant_id = auth.uid());
Enter fullscreen mode Exit fullscreen mode

After I enabled RLS across all 12 tables, I could sleep at night knowing that even if someone manipulated a request, the database itself would reject unauthorised access.

Lesson: Never trust the frontend to enforce data isolation. Do it at the database level.


Lesson 2: The Duplicate INSERT Bug That Almost Broke Everything

At one point, I had a live business — MMAT Plus Hub, a coated peanuts production company — actively using the system. When they recorded a sale, it was occasionally being inserted into the database twice.

Two records. One transaction. Double the stock deduction. Chaos.

The root cause? A React state update was triggering my form submission handler twice under certain conditions — a classic issue with useEffect dependencies and event handlers not being properly cleaned up.

The fix involved:

// Adding a submission lock to prevent duplicate inserts
const [isSubmitting, setIsSubmitting] = useState(false);

const handleSale = async (saleData) => {
  if (isSubmitting) return; // Guard against double submission
  setIsSubmitting(true);

  try {
    await supabase.from('sales').insert(saleData);
  } finally {
    setIsSubmitting(false);
  }
};
Enter fullscreen mode Exit fullscreen mode

But the deeper fix was adding a Postgres trigger that automatically reconciled financial records on the production line — so even if a duplicate slipped through, the financial totals would self-correct.

Lesson: Optimistic UI is great. Idempotent database operations are essential.


Lesson 3: One 8,600-Line File Is a Time Bomb

Early in the project, I had one massive file that did everything. Components, API calls, state management, utility functions — all 8,600 lines of it.

It worked. Until it didn't.

Adding a new feature meant scrolling through thousands of lines trying to remember where something lived. Fixing one bug would break something three sections down. Code reviews (even solo ones) became painful.

I eventually did a full modular refactor — splitting the monolith into 13 named modules:

src/
├── components/
│   ├── Sales/
│   ├── Inventory/
│   ├── Reports/
│   └── Dashboard/
├── hooks/
│   ├── useSales.js
│   ├── useInventory.js
│   └── useTenantData.js
├── lib/
│   ├── supabase.js
│   └── helpers.js
└── pages/
Enter fullscreen mode Exit fullscreen mode

The refactor took a painful weekend. But after it, adding new features became genuinely fun again.

Lesson: Start with structure. Refactoring a live production app is far more stressful than getting the architecture right early.


Lesson 4: Building for Your Own Community Is a Cheat Code

I'm from Kwahu. I built StockMaster Ghana for businesses in Kwahu. That context gave me advantages no amount of market research could replicate.

I knew that:

  • Many SMEs here deal in cash and MoMo, not card payments
  • Business owners often share devices with staff — so role-based access control mattered a lot
  • Debt tracking (customers buying on credit) is a core part of how local trade works
  • Seasonal patterns (Kwahu Easter festival, for example) cause major inventory spikes

These weren't features I found in a product requirements document. They came from conversations with actual users — people I knew.

When a business like MMAT Plus Hub (which processes coated peanuts for sale) needed a production line reconciliation feature, I could sit with the owner, understand the workflow, and build it in a week.

Lesson: Proximity to your users is a competitive advantage. Build for people you can actually talk to.


Lesson 5: Academic Projects and Real Products Need Different Hats

Here's something nobody tells you: building a live product while also writing an academic proposal about it creates a tension you have to manage carefully.

My department assigned me a different research topic for my final year project — a QR-Based Thesis Deposition System for PUG. That's a genuinely separate problem from StockMaster Ghana, and keeping them distinct matters for academic integrity.

The lesson I learned: your real-world experience makes you a better researcher, but your research topic needs to stand on its own merits — with its own problem statement, methodology, and contribution to knowledge.

Don't try to retroactively academise something you already built. Build something new, informed by what you've learned.

Lesson: Production experience sharpens your academic instincts. Keep the two outputs honest and distinct.


What I'd Tell My Past Self

If I could go back to when I started StockMaster Ghana, I'd say:

  1. Enable RLS on day one. Not after you have real users.
  2. Modularise early. One file feels fast until it doesn't.
  3. Write down every bug you fix. Those are your best blog posts, conference talks, and interview stories.
  4. Ship to real users as fast as possible. Feedback from a real business using your system daily is worth more than any tutorial.
  5. Your geography is not a limitation. Building in Kwahu, Ghana gave me a unique product with a real user base. That's more than most CS graduates can say.

What's Next

StockMaster Ghana is live and growing. My final year project (the QR-Based Thesis Deposition System) is in proposal stage. And I'm documenting all of it here on dev.to and on CyberSense Ghana's platforms.

If you're a student developer — especially one building in Africa — I'd love to connect. The problems here are real, the users are real, and the opportunity to build something that matters is very real.

Drop a comment. Let's talk.


Follow CyberSense Ghana @cybersense101 on TikTok, Instagram, and Facebook for cybersecurity awareness content built for West Africa.


Tags: #saas #webdev #beginners #programming #supabase #react #africa

Top comments (0)