arm
  • Home
  • Work
  • About
  • Writing
  • Resume
  • Contact
Open to work
❡Case study · Deep dive · 12 min read

Rentwise — taking a multi-tenant rental SaaS from zero to production.

Architecture decisions, real bugs, and what I would do differently if I started over tomorrow.

activesaasflagshipmulti-tenantbuilt solomonorepo
A property platform for the in-between
Small-to-mid landlords in India do not have time for enterprise software, and most lightweight tools skip Indian-market specifics. Rentwise sits between the two — built solo from schema design through deployment, and it shares a Turborepo with Schooly so auth, UI, and database packages are written once.
3
User roles
8+
Core features
5
Bugs surfaced
1
Person built it
Dashboard screenshot

§01The problem

Small-to-mid landlords in India manage multiple properties across spreadsheets, WhatsApp chats, and paper receipts. They cannot track rent payments, pending maintenance, or tenant history without stitching together four or five tools. Existing SaaS is either too enterprise-heavy, or it skips Indian-market specifics like Razorpay and regional communication.

The hard part is not the CRUD — it is multi-tenancy. One owner's data must never bleed into another's, and the tenant invite flow has to be airtight while still being friendly to non-technical users.

§02System architecture

A pragmatic Next.js + Hono stack — no edge runtime, no exotic database. The whole thing is intentionally boring on the outside so the multi-tenancy logic can be careful on the inside. Shared packages live in a Turborepo alongside Schooly.

Client
Next.js 15 App Routershadcn/uiTanStack QueryTailwind v4
Auth
Better AuthNext middlewareServer-component layoutSessionProvider context
API
Hono RPC (hc client)Zod validatorsRole-based guards
Database
PostgreSQLDrizzle ORMDocker (local)
Monorepo
Turboreposhared/authshared/uishared/db
Infra
Vercel (frontend)Railway (backend)Resend (email)

§03Three decisions worth defending

Decision 01

Hono RPC over oRPC

Switched to Hono's hc client for end-to-end type safety. Return types are inferred straight from the router definition — no separate type sharing, and a whole category of API contract bugs disappears.

Decision 02

Three-layer dashboard security

Middleware-only auth is not enough — it does not protect RSC data fetching. So: middleware (redirect), server-component layout (re-validate session), client SessionProvider (role gating). Belt + suspenders + a third belt.

Decision 03

Postgres over Cloudflare D1

Started on D1/SQLite for the edge convenience, then migrated. Complex multi-tenant JOINs perform better on Postgres, and the relational constraints I lean on were a real concern at scale.

§04Hardest bugs, plainly

Challenge 01

Tenant invite blocked by middleware

Middleware was blocking unauthenticated invite-acceptance routes — new tenants could not even reach sign-up. Fix: redesign the matcher to allow public invite paths while still guarding every dashboard route.

Challenge 02

BETTER_AUTH_URL in the wrong env section

Production URL resolution silently failed because the variable was in the server-only env section. Moving it to the client-accessible env prefix was a non-obvious fix that took a long time to track down.

Challenge 03

Full-table scan on the tenant query

A backend audit found tenant queries loading every row and filtering in JS instead of with WHERE. Rewrote with proper Drizzle where + indexed columns. Estimated 90%+ query-time reduction.

Lessons

Deploy earlier — always.

I spent weeks in a local-only environment. Real-domain deploys expose CORS, auth redirects, and env-var issues much earlier — and these are far easier to debug when you are not also debugging the feature code.

“The real lesson was not the bugs — it was that shipping early is its own kind of test, and skipping it is the most expensive form of perfectionism.”— Parm, in hindsight
Talk about this project →
Open to work

Have something in mind? Let's make it.

iamparmjeetmishra@gmail.com→
GithubMailLinkedInX/Twitter
arm© 2026 — Made with ♡ by Parm
HomeWorkAboutWritingResumeContact