PropTech SaaS · Canada · Web
Tenant screening and property management SaaS
Lead developer on a production platform where every property company runs as an isolated tenant on its own domain. Identity, bank, credit and court-record checks merge into one automated PDF report, with Stripe usage-based billing.
- React 19
- React Router 7
- TypeScript
- Tailwind CSS 4
- Node/Express
- PostgreSQL
- Drizzle
- BullMQ
- Stripe
- Docker
- Azure
Results from projects our founder has led
6+screening integrations
4role-based portals
This is the project our founder knows best: tenant screening software development for a production SaaS platform that serves property companies across Canada. He is the lead developer, from the data model to the billing system to the deployment pipeline. Clients work under NDA, so the platform is described by industry rather than by name.
Context
Property managers and landlords in Canada screen applicants before they sign a lease. That means pulling identity, bank, credit, rental-history and court-record data from several providers, reading the results and keeping a defensible record of the decision.
The platform replaces that with one workflow. Each property company runs as an isolated tenant on its own domain, orders checks and gets back a single report. Screening is billed per use, so the product has to meter work accurately and charge for it without a person in the loop.
The challenge
Four things made this hard.
- Isolation. Every property company's data has to stay inside its own tenant, with no path for one customer to see another's applicants.
- Many actors. Different kinds of users need different views and permissions on the same records.
- Unreliable upstream data. Six or more third-party APIs, each with its own schema, latency and failure modes, have to produce one consistent report.
- Money tied to usage. Billing has to count every check, enforce spend limits and keep working when a provider call fails halfway through.
What we built
Hostname-based multi-tenancy
Every property company runs as an isolated tenant on its own domain. The request hostname resolves to a tenant at the top of the stack, and every query below that point is scoped to it.
Four role-based portals with RBAC
Four portals, one per kind of user, with role-based access control.
Session auth with Google, GitHub and TOTP
Session authentication with Google and GitHub OAuth for sign-in, plus TOTP two-factor.
6+ provider checks in one report
Identity, bank, credit, rental-history and court-record checks come from 6+ providers. The results merge into a single automated PDF report, with provider fallback when a provider is down or returns an error.
Stripe usage-based billing
Stripe usage-based billing with spend limits and automatic credit top-ups driven by webhooks.
Background workers
BullMQ and Redis background workers take the slow work out of the request path, so the web tier never waits on a provider.
Data model and migrations
A 59-table Drizzle/PostgreSQL schema with versioned migrations. Every schema change is a migration file in the repository, applied the same way in every environment.
Delivery pipeline and tests
Dockerised CI/CD to Azure via GitHub Actions. Vitest and Playwright test suites cover the logic and the critical flows end to end.
Architecture decisions
The platform's architecture follows from the four constraints above.
Hostname-based tenancy rather than a tenant column alone. A domain per customer gives each property company its own address, and resolving the tenant once at the top of the request makes it hard to forget the scope lower down.
Session auth rather than stateless tokens. A screening platform holds sensitive personal data, and a server-side session can be ended at once rather than when a token happens to expire.
Provider fallback, because no single data provider is reliable enough to be the only path: the report still has to come out when one of them does not answer.
Stripe webhooks as the source of truth for credit. A browser redirect after checkout is fragile; the webhook is what confirms that money moved.
Slow work on a queue. Screening calls can take a long time and fail in odd ways, so BullMQ and Redis workers keep them out of the request path and give retries and visibility without a custom job system.
Drizzle with versioned migrations to keep a 59-table schema honest. Queries are typed, so a renamed column fails at compile time instead of in production, and every change to the database is a file that was reviewed.
Outcome
- 6+ third-party integrations unified in one SaaS platform
- 4 role-based portals with RBAC
- 59-table PostgreSQL data model owned end to end
Results from projects our founder has led, across his wider work rather than this platform alone: 20% lower API latency through query tuning and caching, and 25% faster page loads with SSR and CDN improvements.
The same patterns (hostname tenancy, server-side RBAC, webhook-driven billing, queued integrations and migration-first data modelling) are what we bring to every SaaS engagement. Read more about our SaaS product engineering service, see how the same platform informs our AI integration, dedicated teams and technical leadership work, or start a project brief and we will reply within 24 hours.
Ready when you are.
Four quick questions, then a free 30-minute call.