wanis.dev
← All work
Property management

Property Management Platform

A multi-tenant property management platform for landlords, tenants, and contractors: properties, units, leases, payments, and maintenance.

Where
Trybe
Stack
NestJS · MongoDB · CASL

Client work. Diagrams are simplified and contain no client data.

Context

Landlords, tenants, contractors, and admins all work on the same records, such as a lease or a maintenance request, but each may only see and do certain things, and one landlord’s data must never leak into another’s.

My role

My main work was designing the multi-tenant architecture and the infrastructure, and building the core domain: tenants, leases (renewal, termination, consistent UTC date handling), properties and media, maintenance, and the permission policies.

Architecture

Next.js web app

NestJS API

JWT guard
global, unless @Public

CASL permissions
policy per resource

MongoDB
tenant-isolated

Status updater
scheduled

Fig. 1 — Property Management Platform, simplified
  1. Every API route requires a logged-in user unless it’s explicitly marked public.
  2. Permissions are built per user with CASL and enforced by a guard plus a policy class per resource: leases, properties, units, tenants, transactions, media, users, and more.
  3. Admins are global; landlords, tenants, and contractors are scoped to their own tenant, and a database plugin isolates each tenant’s data.
  4. A scheduled job moves records between statuses over time, such as marking payments overdue.

Design decisions & trade-offs

  • Permissions as policies, not per-endpoint checks. Access rules live in one policy class per resource that every request goes through, instead of being re-checked by hand in each handler. Trade-off: the permission model has to be designed carefully up front, because every feature depends on it.
  • Tenant isolation in the data layer. Scoping happens in a database plugin rather than in each query, so a forgotten filter can’t leak another tenant’s data. Trade-off: cross-tenant work (admin views, reporting) has to bypass it explicitly.

Stack

NestJS · TypeScript · MongoDB · CASL · JWT · Next.js