Skip to main content

Command Palette

Search for a command to run...

Architecture Decisions: How We Built JiraniHub with React, TypeScript & PostgreSQL

Updated
4 min read
Architecture Decisions: How We Built JiraniHub with React, TypeScript & PostgreSQL

Architecture Decisions: How We Built JiraniHub with React, TypeScript & PostgreSQL

When we started building JiraniHub, we had to make foundational architecture decisions that would affect the platform for years. Here's what we chose and why.

The Requirements

JiraniHub manages gated residential communities. That means:

  • Multi-tenancy: Each estate is a separate tenant with isolated data

  • Real-time updates: Security alerts, announcements, voting

  • Mobile-first: Most users access via mobile browsers

  • Offline capability: Internet isn't always reliable in some estates

  • Compliance: KRA/eTIMS integration for Kenyan tax requirements

Frontend: React 18 + TypeScript + Vite 5

Why React 18?

React 18 gives us:

  • Concurrent rendering: Better UX for complex dashboards

  • Suspense: Better loading states for slow connections

  • Automatic batching: Fewer re-renders = better performance on mobile

Why TypeScript?

For a multi-tenant SaaS, type safety isn't optional. When you're managing data for 26+ estates, a type error could mean showing Estate A's data to Estate B's residents. TypeScript catches these at compile time.

Why Vite 5?

  • Fast HMR: Sub-second hot module replacement during development

  • Optimized builds: Smaller bundle sizes = faster load times on mobile

  • Native ES modules: No bundling overhead in development

Backend: Express.js + PostgreSQL + Prisma

Why Express.js?

We evaluated NestJS, Fastify, and Koa. We chose Express because:

  • Mature ecosystem: Every library supports Express

  • Simplicity: Easy to onboard new developers

  • Middleware pattern: Perfect for multi-tenant request handling

Why PostgreSQL?

  • Row-level security: Native multi-tenancy support

  • JSON columns: Flexible schema for estate-specific configurations

  • Full-text search: Built-in search across announcements, documents

  • Proven at scale: Used by Instagram, Spotify, Notion

Why Prisma?

  • Type-safe queries: End-to-end type safety from DB to frontend

  • Migration system: Version-controlled schema changes

  • Multi-tenant aware: Easy to scope queries to specific tenants

Multi-Tenancy: Schema-Based Isolation

We chose schema-based multi-tenancy over row-based or database-based:

-- Each estate gets its own schema
CREATE SCHEMA estate_001;
CREATE SCHEMA estate_002;

-- Tables in each schema
CREATE TABLE estate_001.residents (...);
CREATE TABLE estate_002.residents (...);

Why schema-based?

  • Strong isolation: No risk of data leakage between estates

  • Easy backups: Backup/restore per estate

  • Scalable: Add new estates without schema changes

  • Performance: PostgreSQL handles thousands of schemas efficiently

Authentication: Session-Based with HttpOnly Cookies

We chose session-based auth over JWT:

app.use(session({
  store: new PrismaSessionStore(prisma),
  secret: process.env.SESSION_SECRET,
  cookie: {
    httpOnly: true,
    secure: true,
    sameSite: 'strict',
    maxAge: 24 * 60 * 60 * 1000 // 24 hours
  }
}));

Why not JWT?

  • No token storage issues: JWTs stored in localStorage are vulnerable to XSS

  • Easy revocation: Delete session = immediate logout

  • Smaller payload: Session ID vs entire JWT in every request

Deployment: Google Cloud via Replit

We deploy on Google Cloud infrastructure via Replit:

  • Free tier: Perfect for pre-revenue startups

  • Auto-deploy: Push to GitHub = auto-deploy

  • Built-in CI/CD: No DevOps overhead

  • Global CDN: Fast load times across Africa

What We'd Do Differently

  1. Start with tRPC instead of REST: End-to-end type safety would save us API debugging time

  2. Use Redis for sessions: Database-backed sessions work but Redis is faster

  3. Implement CQRS earlier: Separating reads/writes would improve dashboard performance

Conclusion

Our stack choices reflect our priorities: type safety, multi-tenancy, mobile performance, and developer experience. We're serving 26+ estates and 500+ members with this architecture, and it's holding up well.

We're building in public. Follow our journey: @jiranihub


We're BCUSHA Ltd, a Nairobi-based PropTech startup. JiraniHub serves 26+ estates and 500+ members across 6 countries. Open source (BSL 1.1). Building in public.

Building JiraniHub in Public

Part 1 of 1

Architecture Decisions: How We Built JiraniHub with React, TypeScript & PostgreSQL