← blog/saas-developmentPT
    // blog/saas-development.md

    SaaS Development

    What changes when your software stops serving one client and starts serving many — multi-tenancy, RLS, and the decisions you can't undo.

    2026-05-09·8 min read·product·POSTEP Digital

    org_id on every table · RLS in the database, not the app · outsource billing · decide early what can't be undone

    // 01

    The problem

    Building software for one client is different from building a product. In the first case, you solve a specific problem with known business rules and a single set of users. In the second, you have to serve N companies that don't know each other — and can't see each other.

    The first time we tried to turn a client feature into a product, we discovered almost none of the code was reusable. Schema, authentication, permissions, billing, onboarding — everything had to be rethought.

    What looked like an extension was a brand-new project.

    // 02

    What changes when it becomes SaaS

    The real difference between a client app and a multi-tenant SaaS isn't on the frontend. It's in how data is isolated, how auth is modeled, and where the line sits between platform code and the company that subscribes to it.

    // comparison
    Client app
    1 database, 1 set of users
    fixed rules, defined in the contract
    specific deploy per client
    no recurring billing
    manual or non-existent onboarding
    Multi-tenant SaaS
    1 database, N isolated organizations
    config per org, not per contract
    one deploy serves every customer
    Stripe, plans, limits per tier
    self-service onboarding from scratch
    // 03

    Multi-tenancy: the heart of the problem

    Every SaaS decision starts here: how two companies share the same database without ever seeing each other's data. The wrong call at this point costs you a rewrite by the second customer.

    // the model we adopted
    organizations table
    each company is one org with its own id
    every table has org_id
    sales, leads, commissions — all tied to the org
    RLS in Supabase
    policy USING (org_id = auth.jwt()->org_id)
    result
    isolation enforced by the database, not by the app

    When isolation depends on frontend code, a single bug in one query is enough to leak data between customers. With RLS, even a SELECT * with no filter only returns what the logged-in org is allowed to see.

    // 04

    The stack we picked

    Building SaaS solo or with a small team forces you to reduce decisions. Each piece is there for a concrete reason — almost always because it removes infrastructure code that adds nothing to the product.

    React + Vite + TanStack Routerend-to-end typing, type-safe routes, builds fast enough to iterate several times a day
    Tailwind v4design system without leaving JSX, zero orphan CSS, theming via CSS vars
    Supabase (Postgres + Auth + RLS)real database, auth out of the box, per-org isolation by policy — no custom permission middleware
    Edge Functionsserver-side logic that needs secret keys (Stripe, email, integrations) without spinning up a separate backend
    Stripecheckout, recurring billing, webhooks. In a SaaS product, outsourcing billing is non-negotiable
    N8Nanything ops — reports, notifications, sync — becomes a workflow instead of code in the app

    None of these picks are opinion — they fall out of two rules: (1) don't write what you can outsource, (2) let the database solve what the database can solve.

    // 05

    The decisions that get expensive later

    Some early choices are nearly invisible and become impossible to undo once the product has paying customers. Worth pausing to decide before the first line of code.

    auth model

    does a user belong to 1 org or several? email invites? Changing this later breaks the whole permission schema

    billing unit

    charge per seat, per usage or flat plan? Defines plan schema and limits — refactoring is painful

    onboarding flow

    self-service or manual approval? Defines everything: signup, org creation, trial, Stripe activation

    data export

    if a customer asks to leave with their data, can you deliver? GDPR and LGPD require it — think early or scramble later

    feature flag

    how do you ship features to some customers without branching? Decide early or you'll end up with if(orgId === 'X') in the code

    None of these decisions need to be perfect at MVP. But all of them need to be conscious — the only one that really hurts is the one made out of ignorance.

    // 06

    Where to start

    week 1

    Define the problem with one real customer. Who they are, what hurts, how much they'd pay. Without a concrete customer, any SaaS is a hypothesis.

    week 2

    Model the schema with org_id on every table from the very first CREATE TABLE. Write RLS policies before any query lands in the app.

    weeks 3–4

    Working MVP: signup → create org → main flow → 1 complete use case. No Stripe yet. The goal is to validate usage, not to charge.

    month 2

    Stripe + plans + limits. Self-service onboarding. Per-org usage logs. From here on it's a product, not a prototype.

    month 3+

    Iterate based on what your first 3 customers do (and don't do). Cut features no one uses. Listen for the recurring request.

    // main rule

    SaaS isn't tech — it's software distribution with recurring billing. If your product doesn't solve a problem someone would pay every month to solve, no stack will save it. Start with the customer, not with the schema.

    written by
    POSTEP Digital
    ← all posts