<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jestony Silvano</title>
    <description>The latest articles on DEV Community by Jestony Silvano (@jestscaledev).</description>
    <link>https://dev.to/jestscaledev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4117355%2F6478a9b7-a096-49d3-a861-db2ea469b207.png</url>
      <title>DEV Community: Jestony Silvano</title>
      <link>https://dev.to/jestscaledev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jestscaledev"/>
    <language>en</language>
    <item>
      <title>How I Built Multi-Tenant Data Isolation for My SaaS CRM with PostgreSQL RLS</title>
      <dc:creator>Jestony Silvano</dc:creator>
      <pubDate>Thu, 10 Sep 2026 16:00:33 +0000</pubDate>
      <link>https://dev.to/jestscaledev/how-i-built-multi-tenant-data-isolation-for-my-saas-crm-with-postgresql-rls-3e7d</link>
      <guid>https://dev.to/jestscaledev/how-i-built-multi-tenant-data-isolation-for-my-saas-crm-with-postgresql-rls-3e7d</guid>
      <description>&lt;h1&gt;
  
  
  How I Built Multi-Tenant Data Isolation for My SaaS CRM with PostgreSQL RLS
&lt;/h1&gt;

&lt;p&gt;When I started building uniThread CRM, I wanted it to be more than just a basic CRUD project. I wanted to actually understand what it takes to build a SaaS application where multiple organizations share the same system without ever seeing each other's data.&lt;/p&gt;

&lt;p&gt;That led me to one of the harder questions I had to answer while building it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How do I make sure users can only ever access data belonging to their own organization?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;My answer ended up being a combination of PostgreSQL Row-Level Security (RLS) and authorization logic on the backend. Here's how I got there, and why I didn't just trust one layer to handle it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Obvious Requirement
&lt;/h2&gt;

&lt;p&gt;The rule is simple to state: Organization A should never be able to access Organization B's data. Simple to say, less simple to guarantee.&lt;/p&gt;

&lt;p&gt;The easy way to handle this is to just add an &lt;code&gt;organization_id&lt;/code&gt; filter to every database query in the backend. And that works... until someone forgets to add it. One missed &lt;code&gt;WHERE&lt;/code&gt; clause on one endpoint, and suddenly you've got a data leak. I didn't want tenant isolation to depend entirely on every developer (including future me) remembering to add that filter every single time.&lt;/p&gt;

&lt;p&gt;That's what got me looking into PostgreSQL RLS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Designing Around Organizations
&lt;/h2&gt;

&lt;p&gt;For any organization-specific CRM data, I use an &lt;code&gt;organization_id&lt;/code&gt; column to tie each record to the organization that owns it. Nothing fancy, just:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;leads&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="n"&gt;UUID&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;organization_id&lt;/span&gt; &lt;span class="n"&gt;UUID&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That gives every lead a clear, explicit relationship to an organization. It sounds almost too simple to matter, but it's the foundation everything else builds on top of.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bringing in Row-Level Security
&lt;/h2&gt;

&lt;p&gt;PostgreSQL RLS lets the database itself decide which rows a query is allowed to see, instead of leaving that entirely up to the application code.&lt;/p&gt;

&lt;p&gt;First, you turn it on for the table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;leads&lt;/span&gt; &lt;span class="n"&gt;ENABLE&lt;/span&gt; &lt;span class="k"&gt;ROW&lt;/span&gt; &lt;span class="k"&gt;LEVEL&lt;/span&gt; &lt;span class="k"&gt;SECURITY&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then you write a policy that only allows access to rows belonging to the current user's organization:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;POLICY&lt;/span&gt; &lt;span class="nv"&gt;"Users can access their organization leads"&lt;/span&gt;
&lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;leads&lt;/span&gt;
&lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="k"&gt;SELECT&lt;/span&gt;
&lt;span class="k"&gt;USING&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;organization_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_user_organization_id&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once that's in place, tenant isolation stops being something only my application layer is responsible for. The database is now enforcing it too. Even if I mess something up in the app code, there's still a wall between organizations at the data layer. That extra layer of protection is really what sold me on this approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I Didn't Just Rely on RLS
&lt;/h2&gt;

&lt;p&gt;Even with RLS in place, I still wanted the backend to own authorization and business logic. RLS is great at stopping cross-tenant access, but it's not really designed to handle things like "can an Agent delete a lead" or "is this user even allowed to hit this endpoint."&lt;/p&gt;

&lt;p&gt;So the backend follows a fairly standard layered structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Request
   ↓
Controller
   ↓
Service
   ↓
Repository
   ↓
PostgreSQL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The backend handles authentication, role-based access control, organization context, business rules, and validation. Then PostgreSQL adds its own layer on top through RLS.&lt;/p&gt;

&lt;p&gt;The point isn't to make one layer do everything. It's to let each layer do what it's actually good at.&lt;/p&gt;

&lt;h2&gt;
  
  
  Roles
&lt;/h2&gt;

&lt;p&gt;Right now, uniThread has three organization-level roles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Owner&lt;/li&gt;
&lt;li&gt;Manager&lt;/li&gt;
&lt;li&gt;Agent&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A user's role determines what they're allowed to do inside their organization.&lt;/p&gt;

&lt;p&gt;Working through this part is actually what made the difference between authentication and authorization click for me in a way it never had before.&lt;/p&gt;

&lt;p&gt;Authentication asks: &lt;em&gt;who are you?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Authorization asks: &lt;em&gt;what are you allowed to do?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And tenant isolation asks a third, separate question: &lt;em&gt;which organization's data are you even allowed to touch?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;They sound like variations of the same idea when you read about them, but once you're actually implementing all three at once, the differences become a lot more obvious.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;p&gt;Before building uniThread, my mental model of auth was basically:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Login → JWT → Authenticated User&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;That's it. That was the whole picture in my head.&lt;/p&gt;

&lt;p&gt;Building something multi-tenant broke that mental model pretty quickly. Getting a user authenticated is really just the starting point. After that you still have to figure out what they can access, what actions they're allowed to take, and how the database itself should be protecting that data regardless of what the app layer does.&lt;/p&gt;

&lt;p&gt;It also made me a lot more deliberate about where security checks actually belong, and made me think harder about what happens the day a developer forgets to add one.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Result
&lt;/h2&gt;

&lt;p&gt;Between organization-scoped data, backend authorization, and PostgreSQL RLS, uniThread now has a decent foundation for keeping tenant data properly separated.&lt;/p&gt;

&lt;p&gt;More than the technical result, though, this was one of the first parts of the project that pushed me past "just build the CRUD feature" and into actually thinking about architecture, security, data ownership, and what happens as the system grows.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd Do Differently
&lt;/h2&gt;

&lt;p&gt;If I were starting uniThread over, I'd think about tenant isolation a lot earlier than I did. It's way easier to bake organization ownership into your schema from day one than to retrofit it after you've already built a pile of features on top of a shaky foundation.&lt;/p&gt;

&lt;p&gt;I'd also spend more time up front defining authorization rules, instead of discovering the edge cases one at a time while implementing individual features and going "oh... wait."&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;uniThread started out as just "I want to build a CRM." Somewhere along the way it turned into a much better lesson in how SaaS applications are actually put together under the hood.&lt;/p&gt;

&lt;p&gt;Multi-tenancy was one of those topics that looked simple from the outside and turned out to be way more interesting than expected once I actually had to implement it myself.&lt;/p&gt;

&lt;p&gt;I'm still learning as I go, but honestly, that's a big part of why I keep building projects like this. The interesting part was never just making the app work. It's figuring out how to make it work &lt;em&gt;correctly&lt;/em&gt; as things get more complicated.&lt;/p&gt;

</description>
      <category>saas</category>
      <category>postgres</category>
      <category>security</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Juniors! Overengineer Your Projects</title>
      <dc:creator>Jestony Silvano</dc:creator>
      <pubDate>Wed, 09 Sep 2026 11:15:17 +0000</pubDate>
      <link>https://dev.to/jestscaledev/juniors-overengineer-your-projects-42j0</link>
      <guid>https://dev.to/jestscaledev/juniors-overengineer-your-projects-42j0</guid>
      <description>&lt;p&gt;title: "Juniors! Overengineer Your Projects"&lt;br&gt;
published: true&lt;br&gt;
description: "Stop optimizing for the number of projects you can finish. Build fewer things, go deeper, use AI intelligently, break your own code, and learn how real software systems work."&lt;br&gt;
tags: "ai, beginners, webdev, programming, softwareengineering"&lt;/p&gt;




&lt;h1&gt;
  
  
  Juniors! Overengineer Your Projects
&lt;/h1&gt;

&lt;p&gt;If you're a junior developer trying to land your first software job, you've probably heard some version of this advice:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Build more projects."&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So you build another one.&lt;/p&gt;

&lt;p&gt;Then another.&lt;/p&gt;

&lt;p&gt;A portfolio website.&lt;br&gt;
A weather app.&lt;br&gt;
A todo app.&lt;br&gt;
A Netflix clone.&lt;br&gt;
A CRUD application.&lt;/p&gt;

&lt;p&gt;And eventually, you have a GitHub full of repositories. But how much did you actually learn? I think we should approach this differently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stop Optimizing for the Number of Projects
&lt;/h2&gt;

&lt;p&gt;You don't need to prove that you can start 20 projects. You need to prove that you can &lt;strong&gt;understand, build, debug, and improve software.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Instead of asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"How quickly can I finish this?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Try asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"How far can I take this?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's where things get interesting.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Don't Be Afraid to Overengineer
&lt;/h2&gt;

&lt;p&gt;Obviously, don't build a distributed microservice architecture for a todo app just because you can. That's not the point. The point is that &lt;strong&gt;complexity can create opportunities to learn.&lt;/strong&gt; Take a project further than you initially planned. Add authentication. Design a proper database. Think about authorization. Add role-based access control. Handle errors properly. Think about concurrency. Add caching. Write tests. Build background jobs. Think about how the system behaves when something fails. Deploy it. Monitor it. Then break it. Then fix it. You might spend weeks building something that could have been hacked together in three days. And that's okay. If those extra weeks made you understand something you didn't understand before, &lt;strong&gt;you didn't waste them.&lt;/strong&gt; You learned.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Read Your Own Code
&lt;/h2&gt;

&lt;p&gt;This one sounds obvious, but I think it's seriously underrated.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Read the code you wrote.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not just while you're writing it.&lt;/p&gt;

&lt;p&gt;Come back to it later.&lt;/p&gt;

&lt;p&gt;Look at an old function and ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Why did I build it this way?&lt;/li&gt;
&lt;li&gt;Do I still understand this?&lt;/li&gt;
&lt;li&gt;Would I design this differently now?&lt;/li&gt;
&lt;li&gt;Is this actually maintainable?&lt;/li&gt;
&lt;li&gt;What happens when this fails?&lt;/li&gt;
&lt;li&gt;Why does this abstraction exist?&lt;/li&gt;
&lt;li&gt;Did I solve the actual problem, or did I just make the code more complicated?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then change it.&lt;/p&gt;

&lt;p&gt;Refactor it.&lt;/p&gt;

&lt;p&gt;Delete it.&lt;/p&gt;

&lt;p&gt;Rewrite it.&lt;/p&gt;

&lt;p&gt;Your old code is one of the best teachers you'll ever have because it shows you exactly what you used to think you understood.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. We're Still Early in the AI Era
&lt;/h2&gt;

&lt;p&gt;This is probably one of the most interesting times to be learning software development.&lt;/p&gt;

&lt;p&gt;AI can write code incredibly quickly.&lt;/p&gt;

&lt;p&gt;So &lt;strong&gt;use it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Seriously.&lt;/p&gt;

&lt;p&gt;Don't pretend AI doesn't exist just because you want to "learn properly."&lt;/p&gt;

&lt;p&gt;Leverage it.&lt;/p&gt;

&lt;p&gt;Ask it to explain concepts you don't understand.&lt;/p&gt;

&lt;p&gt;Ask it to explain unfamiliar code.&lt;/p&gt;

&lt;p&gt;Ask it to compare architectural approaches.&lt;/p&gt;

&lt;p&gt;Ask it to review your database design.&lt;/p&gt;

&lt;p&gt;Ask it to find edge cases.&lt;/p&gt;

&lt;p&gt;Ask it to challenge your assumptions.&lt;/p&gt;

&lt;p&gt;Ask it questions you would normally spend hours trying to formulate yourself.&lt;/p&gt;

&lt;p&gt;But there's a catch.&lt;/p&gt;

&lt;h3&gt;
  
  
  Don't Let AI Become Your Brain
&lt;/h3&gt;

&lt;p&gt;The quality of the answer you get is heavily influenced by the quality of the question you ask.&lt;/p&gt;

&lt;p&gt;And the quality of your question depends on the context you can provide.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Build context.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Learn the problem first.&lt;/p&gt;

&lt;p&gt;Understand your system.&lt;/p&gt;

&lt;p&gt;Understand the constraints.&lt;/p&gt;

&lt;p&gt;Understand what you're trying to solve.&lt;/p&gt;

&lt;p&gt;Then ask AI.&lt;/p&gt;

&lt;p&gt;If you give it vague questions and no context, you'll often get vague solutions.&lt;/p&gt;

&lt;p&gt;If you understand the problem and provide meaningful context, AI becomes a much more powerful learning tool.&lt;/p&gt;

&lt;p&gt;And don't be afraid to use smaller models or solve something yourself before reaching for the biggest model available.&lt;/p&gt;

&lt;p&gt;Sometimes struggling with a problem for an hour teaches you more than getting the answer in ten seconds.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Build Systems, Not Just Projects
&lt;/h2&gt;

&lt;p&gt;There's a difference between building a project and building a system.&lt;/p&gt;

&lt;p&gt;A project can be:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"I built a CRUD application."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A system makes you ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"What happens when 10,000 users use this?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then you start thinking differently.&lt;/p&gt;

&lt;p&gt;You start thinking about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Architecture&lt;/li&gt;
&lt;li&gt;Data modeling&lt;/li&gt;
&lt;li&gt;Security&lt;/li&gt;
&lt;li&gt;Performance&lt;/li&gt;
&lt;li&gt;Caching&lt;/li&gt;
&lt;li&gt;Authentication&lt;/li&gt;
&lt;li&gt;Authorization&lt;/li&gt;
&lt;li&gt;Observability&lt;/li&gt;
&lt;li&gt;Deployment&lt;/li&gt;
&lt;li&gt;Failure recovery&lt;/li&gt;
&lt;li&gt;Scalability&lt;/li&gt;
&lt;li&gt;Maintainability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You don't necessarily need to implement all of these.&lt;/p&gt;

&lt;p&gt;But even thinking about them changes the way you understand software.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Build Something That Is Actually Yours
&lt;/h2&gt;

&lt;p&gt;Please, build another tutorial project if you want to. There's nothing wrong with that. But eventually, &lt;strong&gt;build something original.&lt;/strong&gt; Build something because you had an idea, because you noticed a problem.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"I have no idea how I'm going to build this."&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's where the fun starts. You might fail. Good. You might rewrite half of it. Even better. You might discover that your original architecture was terrible. Perfect. Now you have something to learn from.&lt;/p&gt;

&lt;h1&gt;
  
  
  Don't Maximize Output. Maximize Learning.
&lt;/h1&gt;

&lt;p&gt;There's a strange pressure among junior developers to constantly produce.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;More GitHub repositories.&lt;/li&gt;
&lt;li&gt;More projects.&lt;/li&gt;
&lt;li&gt;More technologies.&lt;/li&gt;
&lt;li&gt;More certificates.&lt;/li&gt;
&lt;li&gt;More tutorials.&lt;/li&gt;
&lt;li&gt;More AI-generated code.&lt;/li&gt;
&lt;li&gt;More, more, more.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But software development isn't a race to produce the most code. You can build 30 projects and barely understand any of them. Or you can build one project that forces you to learn databases, APIs, authentication, security, deployment, architecture, testing, debugging, and system design.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which developer do you think learned more?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So if you're a junior developer trying to get your first job:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Don't be afraid to take your project too far.&lt;/li&gt;
&lt;li&gt;Don't be afraid to spend too much time learning.&lt;/li&gt;
&lt;li&gt;Don't be afraid to read your own code.&lt;/li&gt;
&lt;li&gt;Don't be afraid to break things.&lt;/li&gt;
&lt;li&gt;Don't be afraid to rewrite things.&lt;/li&gt;
&lt;li&gt;Don't be afraid to ask AI questions.&lt;/li&gt;
&lt;li&gt;Don't be afraid to work without AI sometimes.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And most importantly:&lt;/p&gt;

&lt;h1&gt;
  
  
  Don't Be Afraid to Build Something Bigger Than You Know How to Build
&lt;/h1&gt;

&lt;p&gt;Because that's how you learn how to build it.&lt;/p&gt;




</description>
      <category>beginners</category>
      <category>webdev</category>
      <category>programming</category>
      <category>softwareengineering</category>
    </item>
  </channel>
</rss>
