SaaS Platform · Backend Engineering
WrapRight
A production multi-tenant CRM and shop-management platform for automotive appearance workshops: leads, quotes, scheduling, work orders, payments and team messaging in one system.
- Node.js
- Express
- MongoDB
- Mongoose
- Next.js
- Redux Toolkit
- BullMQ
- Redis
- Stripe Connect
- NMI
- AWS S3
5
Access tiers
2
Payment gateways
4+
Integrations
The problem
Workshops that do vinyl wraps, paint protection film, ceramic coating and window tint were running leads, quotes, scheduling and billing across spreadsheets, text messages and disconnected tools. The client needed one platform that many independent shops could use, each with its own data, staff roles and payment setup, without any shop ever seeing another shop's records.
The solution
I built the backend from the ground up as a multi-tenant Express and MongoDB API. Tenant isolation is enforced server-side on every query, with a five-tier role model (super admin, owner, admin, sales, tech) and JWT auth using HttpOnly cookies and refresh-token rotation. Subscription billing runs on NMI (customer vault, subscription API, webhooks) while shops accept customer payments through Stripe Connect. Gmail and RingCentral OAuth integrations bring email and messaging into the CRM, including webhook subscriptions with scheduled renewal and race-safe token refresh. Around that sit a Kanban lead pipeline with hosted lead forms and UTM tracking, bulk CSV import, work orders, appointments and employee scheduling, tenant-scoped S3 uploads, and consent tracking with a SHA-256 audit trail. A workflow automation builder (React Flow canvas on a BullMQ and Redis execution engine) is in active development.
The outcome
WrapRight is live in production with separate staging and production environments. At v0.9.0 the core CRM, billing, scheduling and communication features are shipped, and new automation features are being added on top.
Lessons learned
Tenant isolation has to be structural, not a convention: scoping every query and every upload path by tenant on the server mattered more than any single feature. Integrations taught the second lesson: external APIs fail in the gaps (expiring tokens, missed webhooks, concurrent refreshes), so refresh locks, webhook renewal jobs and idempotent handlers are part of the design. Even a small utility like per-tenant reference numbers hid a race condition that only showed up under concurrency.
Want something like this built?
Get in touch