Selected workCircuit 3 · Tenants
Lead2Done CRM
One codebase, a subdomain per customer
- My role
- Backend architect
- When
- Freelance · 2023 – present
- Where it stands
- Freelance · client
What I built
The multi-tenant backend of a SaaS CRM: tenant resolution, a modular RBAC module and the Paddle payments integration.
Why it mattered
A CRM sold as SaaS must keep every customer’s data apart while running on one codebase. Billing has to stay in sync with the payment provider, even when its events arrive later.
hostacme.app.com
tenantAcme
Signed in as an admin of Acme.
Illustration running in your browser. It shows the real system’s approach in simplified form; names and numbers are invented, and nothing here touches the real system.
What made it difficult
One app, many customers
Every request has to land on the right tenant before anything else happens.
Roles per module
What a user may do changes from module to module, and every endpoint must respect it.
Billing happens elsewhere
Subscription changes happen at Paddle, and the app hears about them by webhook.
How I solved it
Tenant from the subdomain
Nginx wildcard subdomains send every tenant to one app, and custom middleware resolves the tenant on each request.
Guards for access
Modular role-based access control is enforced with NestJS guards.
Webhooks drive billing
Paddle payments are integrated with webhook handling, so subscriptions follow what the provider reports.
What I delivered
The backend architecture of Lead2Done, a SaaS CRM, built for a freelance client.
Multi-tenancy by subdomain, modular RBAC with guards, and Paddle billing with webhooks.
No usage numbers are published here.
Built with
- NestJS
- TypeScript
- Nginx
- Paddle
- RBAC