02 / 04Multi-Tenant SaaS · Backend Architecture

Customer support SaaS with database-enforced tenant isolation.

SupportFlow is a multi-tenant customer support platform built around PostgreSQL RLS, Security Definer RPCs, transactional workflows, realtime authorization, and server-side validation.

PRIMARY PROOF:Secure SaaS, multi-tenancy, authorization, realtime
Multi-TenancyRLSPostgreSQLRealtime
01 / THE PROBLEM

The Vulnerability of Frontend Tenant Isolation

A customer support system appears straightforward until multiple organizations share the same database infrastructure.

  • Which organization owns this ticket?
  • Which specific users are allowed to see it?
  • Which users have permission to transition ticket status or priority?
  • How is every state transition audited without race conditions?
  • How do realtime notifications reach only authorized subscribers?
  • Why a frontend check alone is a critical security vulnerability.

Make tenant isolation and workflow integrity properties of the database and transaction model, not conventions developers are expected to remember.

02 / WHAT I BUILT

System Overview & Capabilities

SupportFlow provides three distinct operational roles enforced through database rules.

Customer Role

  • Create tickets
  • Track ticket status
  • Upload attachments
  • Close resolved tickets

Agent Role

  • Triage & respond
  • Status state transitions
  • Tenant-scoped collaboration
  • Monitor SLA clocks

Admin Role

  • Assign agent workload
  • Manage priority & SLA
  • Organization settings
  • Database-aggregated analytics
03 / SYSTEM ARCHITECTURE

Data Flow & Infrastructure

01Supabase Auth Authentication
02Next.js Route Authorization
03PostgreSQL Tenant Context (current_organization_id())
04RLS-Protected Data Reads
05Security Definer RPC Mutations
06Transactional State Transitions
07Audit Events + Private Realtime Delivery
PIPELINE ARCHITECTURE DIAGRAM
Supabase Auth
      ↓
Next.js Authorization
      ↓
PostgreSQL Tenant Context (current_organization_id)
      ↓
RLS-Protected Reads
      ↓
Security Definer RPC Mutations
      ↓
Transactional Workflow (Atomic Lock & Mutate)
      ↓
Audit Events + Realtime WebSocket Delivery
Core Technical Stack:
Next.jsReactTypeScriptTailwindCSSSupabasePostgreSQLPostgreSQL RLSSecurity Definer RPCsSupabase RealtimeSupabase StorageZodVitestPlaywright
04 / KEY ENGINEERING DECISION

Shared Database + Shared Schema + Organization Discriminator

Enforcing authorization below the application layer

SupportFlow uses a shared database, shared schema, and organization_id discriminator model.

The application never trusts a tenant ID sent from the browser. Instead, tenant context is derived directly from the authenticated session inside PostgreSQL via current_organization_id() and current_role().

Reads are bounded by RLS policies; mutations are executed inside atomic Security Definer RPCs that lock target records, validate roles, update workflow state, and log immutable audit entries in a single transaction.

💡
In a shared database, the data layer itself should understand who owns the data and what operations a user is allowed to perform.
05 / IMPLEMENTATION DEPTH

Engineering Details

Database-Level Authorization & RLS

Every business table has Row-Level Security active with policies filtering by verified tenant context.

  • Reads constrained by organization_id = current_organization_id().
  • Customer queries restricted to tickets where customer_id = auth.uid().
  • RLS serves as an unbypassable second line of defense behind server middleware.

Transactional Security Definer Mutations

Core operations (create_ticket, assign_ticket, update_ticket_status, add_ticket_comment) run as PostgreSQL RPCs.

  • Resolves acting tenant and validates role permissions.
  • Acquires row-level lock on target ticket to prevent concurrent race conditions.
  • Updates ticket state, calculates SLA timestamps, and records an audit log row atomically.

Authorized Private Realtime Topics

Realtime comments and updates use private WebSocket broadcast channels verified by database policies.

Comment Inserted
      ↓
PostgreSQL Trigger
      ↓
realtime.send()
      ↓
ticket:<UUID>:comments
      ↓
realtime.messages RLS Policy Check
      ↓
Authorized Subscriber WebSocket Delivery

Tenant-Scoped Private Storage & 60s Signed URLs

Ticket attachments reside in a private bucket ('ticket-attachments') with 5 MB maximum size and MIME allowlists.

  • Storage path structure: organization_id / ticket_id / uuid-filename.
  • Downloads require server-generated 60-second signed URLs.
  • Zero public attachment buckets.

SLA Response Engine & Database Aggregated Analytics

Continuous elapsed-time response targets computed directly inside PostgreSQL.

Priority TierTarget First Response SLA
Urgent4 hours
High24 hours
Medium48 hours
Low72 hours
06 / INTERACTIVE VISUAL DEMONSTRATION

System Centerpiece & Inspection

Inspect the live execution state, benchmarks, security boundaries, and architectural guarantees.

Simulate Active Tenant Context:
Acting Role Context:
POSTGRESQL TABLE: `tickets` (SHARED SCHEMA)RLS: ENABLED
Ticket IDOrg IDTitleStatusVisibility
#TK-101ORG_01Billing invoice mismatchIn Progress✓ ALLOWED (Org Match)
#TK-102ORG_01SSO SAML configurationOpen✓ ALLOWED (Org Match)
#TK-201ORG_02API webhook rate limitingResolved✕ FILTERED (RLS)
#TK-202ORG_02Database migration errorOpen✕ FILTERED (RLS)
ACTIVE DATABASE POLICY EVALUATIONSQL EXPLAIN
-- Evaluated inside PostgreSQL kernel
CREATE POLICY "tenant_ticket_isolation" ON tickets
FOR ALL TO authenticated
USING (
  organization_id = current_organization_id()
  AND (
    current_role() IN ('admin', 'agent')
    OR (current_role() = 'customer' AND customer_id = auth.uid())
  )
);

-- Active Session State:
-- current_organization_id() = 'ORG_01'
-- current_role()            = 'agent'
-- Result: Zero cross-tenant data leakage possible
07 / EVALUATION & VERIFICATION

Rigorous Verification Evidence

24 / 24Unit Tests

SLA logic, Zod validation, role state machines

4 SuitesIntegration Suites

Live Supabase RLS & RPC isolation verified

1 Multi-RoleE2E Workflows

Simultaneous Customer, Admin, and Agent contexts

13 RPCsStored Procedures

Defensive search_path, atomic transactions

12 PoliciesRLS Policies

Active across all 7 business tables

08 / CANONICAL SCENARIO

Multi-Role Verified Ticket Lifecycle

OBSERVED INCIDENT / CONTEXT

Full workflow tested with simultaneous browser contexts in Playwright.

STEP-BY-STEP SYSTEM EXECUTION
1

Customer creates ticket via create_ticket RPC with file attachment

2

Admin assigns agent workload; SLA clock begins

3

Agent changes status to In Progress and sends private reply comment

4

Customer receives reply immediately via authorized Realtime WebSocket

5

Database trigger records first_agent_response_at and verifies SLA compliance

6

Agent marks ticket Resolved; Customer closes ticket; audit trail completed

FINAL OUTCOME / DIAGNOSIS

Full state progression completed atomically with zero cross-tenant leakage.

09 / DEMONSTRATED SKILLS

Engineering Capabilities Proven

Shared-schema multi-tenancy with organization_id discriminator
PostgreSQL Row-Level Security (RLS) enforcement
Security Definer stored procedures for transactional integrity
Private Realtime WebSocket authorization
Tenant-scoped private storage with signed download URLs
Atomic audit event logging & SLA tracking
Multi-role automated E2E testing with Playwright
10 / LIMITATIONS & SCOPE BOUNDARIES

Disciplined Technical Claims

Transparent Claims Discipline:
  • SupportFlow does not claim enterprise-scale load, millions of users, 99.99% uptime, or billing infrastructure.
  • The SLA engine measures continuous elapsed time rather than custom business-hours calendars.
  • The team roster lookup requires server-side service_role access to retrieve emails from auth.users (deliberate architectural trade-off).
11 / LESSONS LEARNED

Engineering Retrospective

Multi-tenancy is not just an application routing concern. In a shared database, the data layer itself should understand who owns the data and what operations a user is allowed to perform.

RLS as an Unbypassable Guardrail

Even if an application handler has a logic flaw, row-level security prevents cross-tenant data leakage at the query level.

Atomic RPCs Prevent Partial Failures

Wrapping status changes, audit logging, and SLA recalculation in a single stored procedure eliminates multi-step network failure inconsistencies.

NEXT CASE STUDY (03 / 04)

SignalRoom

Anonymous student feedback and AI analytics built around privacy-preserving response handling and database-enforced concurrency.

GET IN TOUCH

Have a system worth
building together?

I’m available for full-time engineering roles, high-impact contract builds, and applied AI systems. Send a direct inquiry below—messages are automatically delivered to my primary inbox.

SYSTEM INTAKE // DIRECT MESSAGE AUTOMATED INBOX DISPATCH
PROFESSIONAL NETWORK

LinkedIn Chat

Connect directly for professional opportunities, network conversations, and quick messaging.

OPEN SOURCE & CODE

GitHub Profile

Review codebases, architectural implementations, and public project repositories.